You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1543 lines
60 KiB
1543 lines
60 KiB
2 years ago
|
<?php
|
||
|
// This file is part of Moodle - http://moodle.org/
|
||
|
//
|
||
|
// Moodle is free software: you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU General Public License as published by
|
||
|
// the Free Software Foundation, either version 3 of the License, or
|
||
|
// (at your option) any later version.
|
||
|
//
|
||
|
// Moodle is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
// GNU General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU General Public License
|
||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
/**
|
||
|
* The forum module mail generation tests.
|
||
|
*
|
||
|
* @package mod_forum
|
||
|
* @category external
|
||
|
* @copyright 2013 Andrew Nicols
|
||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||
|
*/
|
||
|
|
||
|
defined('MOODLE_INTERNAL') || die();
|
||
|
|
||
|
global $CFG;
|
||
|
require_once($CFG->dirroot . '/mod/forum/lib.php');
|
||
|
require_once(__DIR__ . '/cron_trait.php');
|
||
|
require_once(__DIR__ . '/generator_trait.php');
|
||
|
|
||
|
class mod_forum_mail_testcase extends advanced_testcase {
|
||
|
// Make use of the cron tester trait.
|
||
|
use mod_forum_tests_cron_trait;
|
||
|
|
||
|
// Make use of the test generator trait.
|
||
|
use mod_forum_tests_generator_trait;
|
||
|
|
||
|
/**
|
||
|
* @var \phpunit_message_sink
|
||
|
*/
|
||
|
protected $messagesink;
|
||
|
|
||
|
/**
|
||
|
* @var \phpunit_mailer_sink
|
||
|
*/
|
||
|
protected $mailsink;
|
||
|
|
||
|
public function setUp() {
|
||
|
global $CFG;
|
||
|
|
||
|
// We must clear the subscription caches. This has to be done both before each test, and after in case of other
|
||
|
// tests using these functions.
|
||
|
\mod_forum\subscriptions::reset_forum_cache();
|
||
|
\mod_forum\subscriptions::reset_discussion_cache();
|
||
|
|
||
|
// Messaging is not compatible with transactions...
|
||
|
$this->preventResetByRollback();
|
||
|
|
||
|
// Catch all messages.
|
||
|
$this->messagesink = $this->redirectMessages();
|
||
|
$this->mailsink = $this->redirectEmails();
|
||
|
|
||
|
// Forcibly reduce the maxeditingtime to a second in the past to
|
||
|
// ensure that messages are sent out.
|
||
|
$CFG->maxeditingtime = -1;
|
||
|
}
|
||
|
|
||
|
public function tearDown() {
|
||
|
// We must clear the subscription caches. This has to be done both before each test, and after in case of other
|
||
|
// tests using these functions.
|
||
|
\mod_forum\subscriptions::reset_forum_cache();
|
||
|
|
||
|
$this->messagesink->clear();
|
||
|
$this->messagesink->close();
|
||
|
unset($this->messagesink);
|
||
|
|
||
|
$this->mailsink->clear();
|
||
|
$this->mailsink->close();
|
||
|
unset($this->mailsink);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Perform message inbound setup for the mod_forum reply handler.
|
||
|
*/
|
||
|
protected function helper_spoof_message_inbound_setup() {
|
||
|
global $CFG, $DB;
|
||
|
// Setup the default Inbound Message mailbox settings.
|
||
|
$CFG->messageinbound_domain = 'example.com';
|
||
|
$CFG->messageinbound_enabled = true;
|
||
|
|
||
|
// Must be no longer than 15 characters.
|
||
|
$CFG->messageinbound_mailbox = 'moodlemoodle123';
|
||
|
|
||
|
$record = $DB->get_record('messageinbound_handlers', array('classname' => '\mod_forum\message\inbound\reply_handler'));
|
||
|
$record->enabled = true;
|
||
|
$record->id = $DB->update_record('messageinbound_handlers', $record);
|
||
|
}
|
||
|
|
||
|
public function test_cron_message_includes_courseid() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'recipient' => (object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->messagesink->close();
|
||
|
$this->eventsink = $this->redirectEvents();
|
||
|
$this->send_notifications_and_assert($author, [$post]);
|
||
|
$events = $this->eventsink->get_events();
|
||
|
$event = reset($events);
|
||
|
|
||
|
$this->assertEquals($course->id, $event->other['courseid']);
|
||
|
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
}
|
||
|
|
||
|
public function test_forced_subscription() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, [$post]);
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that for a forum with subscription disabled that standard users will not receive posts.
|
||
|
*/
|
||
|
public function test_subscription_disabled_standard_users() {
|
||
|
global $DB;
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
// Run cron and check that the expected number of users received the notification.
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, []);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that for a forum with subscription disabled that a user subscribed to the forum will receive the post.
|
||
|
*/
|
||
|
public function test_subscription_disabled_user_subscribed_forum() {
|
||
|
global $DB;
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// A user with the manageactivities capability within the course can subscribe.
|
||
|
$roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
|
||
|
assign_capability('moodle/course:manageactivities', CAP_ALLOW, $roleids['student'], context_course::instance($course->id));
|
||
|
|
||
|
// Suscribe the recipient only.
|
||
|
\mod_forum\subscriptions::subscribe_user($recipient->id, $forum);
|
||
|
|
||
|
$this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
|
||
|
'userid' => $recipient->id,
|
||
|
'forum' => $forum->id,
|
||
|
)));
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
// Run cron and check that the expected number of users received the notification.
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
],
|
||
|
'recipient' => (object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that for a forum with subscription disabled that a user subscribed to the discussion will receive the
|
||
|
* post.
|
||
|
*/
|
||
|
public function test_subscription_disabled_user_subscribed_discussion() {
|
||
|
global $DB;
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// A user with the manageactivities capability within the course can subscribe.
|
||
|
$roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
|
||
|
assign_capability('moodle/course:manageactivities', CAP_ALLOW, $roleids['student'], context_course::instance($course->id));
|
||
|
|
||
|
// Run cron and check that the expected number of users received the notification.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
// Subscribe the user to the discussion.
|
||
|
\mod_forum\subscriptions::subscribe_user_to_discussion($recipient->id, $discussion);
|
||
|
$this->helper_update_subscription_time($recipient, $discussion, -60);
|
||
|
|
||
|
// Run cron and check that the expected number of users received the notification.
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
],
|
||
|
'recipient' => (object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that for a forum with automatic subscription that users receive posts.
|
||
|
*/
|
||
|
public function test_automatic() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, [$post]);
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that private replies are not sent to users with an automatic subscription unless they are an expected
|
||
|
* recipient.
|
||
|
*/
|
||
|
public function test_automatic_with_private_reply() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', [
|
||
|
'course' => $course->id,
|
||
|
'forcesubscribe' => FORUM_INITIALSUBSCRIBE,
|
||
|
]);
|
||
|
|
||
|
[$student, $otherstudent] = $this->helper_create_users($course, 2, 'student');
|
||
|
[$teacher, $otherteacher] = $this->helper_create_users($course, 2, 'teacher');
|
||
|
|
||
|
[$discussion, $post] = $this->helper_post_to_forum($forum, $student);
|
||
|
$reply = $this->helper_post_to_discussion($forum, $discussion, $teacher, [
|
||
|
'privatereplyto' => $student->id,
|
||
|
]);
|
||
|
|
||
|
// The private reply is queued to all messages as reply visibility may change between queueing, and sending.
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $student->id,
|
||
|
'messages' => 2,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $otherstudent->id,
|
||
|
'messages' => 2,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $teacher->id,
|
||
|
'messages' => 2,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $otherteacher->id,
|
||
|
'messages' => 2,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
// The actual messages sent will respect private replies.
|
||
|
$this->send_notifications_and_assert($student, [$post, $reply]);
|
||
|
$this->send_notifications_and_assert($teacher, [$post, $reply]);
|
||
|
$this->send_notifications_and_assert($otherteacher, [$post, $reply]);
|
||
|
$this->send_notifications_and_assert($otherstudent, [$post]);
|
||
|
}
|
||
|
|
||
|
public function test_optional() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, []);
|
||
|
}
|
||
|
|
||
|
public function test_automatic_with_unsubscribed_user() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Unsubscribe the 'author' user from the forum.
|
||
|
\mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
}
|
||
|
|
||
|
public function test_optional_with_subscribed_user() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Subscribe the 'recipient' user from the forum.
|
||
|
\mod_forum\subscriptions::subscribe_user($recipient->id, $forum);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
}
|
||
|
|
||
|
public function test_automatic_with_unsubscribed_discussion() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
// Unsubscribe the 'author' user from the discussion.
|
||
|
\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
|
||
|
|
||
|
$this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
|
||
|
$this->assertTrue(\mod_forum\subscriptions::is_subscribed($recipient->id, $forum, $discussion->id));
|
||
|
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
}
|
||
|
|
||
|
public function test_optional_with_subscribed_discussion() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
$this->helper_update_post_time($post, -90);
|
||
|
|
||
|
// Subscribe the 'recipient' user to the discussion.
|
||
|
\mod_forum\subscriptions::subscribe_user_to_discussion($recipient->id, $discussion);
|
||
|
$this->helper_update_subscription_time($recipient, $discussion, -60);
|
||
|
|
||
|
// Initially we don't expect any user to receive this post as you cannot subscribe to a discussion until after
|
||
|
// you have read it.
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, []);
|
||
|
|
||
|
// Have a user reply to the discussion.
|
||
|
$reply = $this->helper_post_to_discussion($forum, $discussion, $author);
|
||
|
$this->helper_update_post_time($reply, -30);
|
||
|
|
||
|
// We expect only one user to receive this post.
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, [$reply]);
|
||
|
}
|
||
|
|
||
|
public function test_optional_with_subscribed_discussion_and_post() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
$this->helper_update_post_time($post, -90);
|
||
|
|
||
|
// Have a user reply to the discussion before we subscribed.
|
||
|
$reply = $this->helper_post_to_discussion($forum, $discussion, $author);
|
||
|
$this->helper_update_post_time($reply, -75);
|
||
|
|
||
|
// Subscribe the 'recipient' user to the discussion.
|
||
|
\mod_forum\subscriptions::subscribe_user_to_discussion($recipient->id, $discussion);
|
||
|
$this->helper_update_subscription_time($recipient, $discussion, -60);
|
||
|
|
||
|
// Have a user reply to the discussion.
|
||
|
$reply = $this->helper_post_to_discussion($forum, $discussion, $author);
|
||
|
$this->helper_update_post_time($reply, -30);
|
||
|
|
||
|
// We expect only one user to receive this post.
|
||
|
// The original post won't be received as it was written before the user subscribed.
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, [$reply]);
|
||
|
}
|
||
|
|
||
|
public function test_automatic_with_subscribed_discussion_in_unsubscribed_forum() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
$this->helper_update_post_time($post, -90);
|
||
|
|
||
|
// Unsubscribe the 'author' user from the forum.
|
||
|
\mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
|
||
|
|
||
|
// Then re-subscribe them to the discussion.
|
||
|
\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
|
||
|
$this->helper_update_subscription_time($author, $discussion, -60);
|
||
|
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
|
||
|
// Now post a reply to the original post.
|
||
|
$reply = $this->helper_post_to_discussion($forum, $discussion, $author);
|
||
|
$this->helper_update_post_time($reply, -30);
|
||
|
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, [$reply]);
|
||
|
$this->send_notifications_and_assert($recipient, [$reply]);
|
||
|
}
|
||
|
|
||
|
public function test_optional_with_unsubscribed_discussion_in_subscribed_forum() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
// Unsubscribe the 'recipient' user from the discussion.
|
||
|
\mod_forum\subscriptions::subscribe_user($recipient->id, $forum);
|
||
|
|
||
|
// Then unsubscribe them from the discussion.
|
||
|
\mod_forum\subscriptions::unsubscribe_user_from_discussion($recipient->id, $discussion);
|
||
|
|
||
|
// We don't expect any users to receive this post.
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
(object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 0,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, []);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that a user unsubscribed from a forum who has subscribed to a discussion, only receives posts made after
|
||
|
* they subscribed to the discussion.
|
||
|
*/
|
||
|
public function test_forum_discussion_subscription_forum_unsubscribed_discussion_subscribed_after_post() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
$expectedmessages = array();
|
||
|
|
||
|
// Create a user enrolled in the course as a student.
|
||
|
list($author) = $this->helper_create_users($course, 1);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
$this->helper_update_post_time($post, -90);
|
||
|
|
||
|
$expectedmessages[] = array(
|
||
|
'id' => $post->id,
|
||
|
'subject' => $post->subject,
|
||
|
'count' => 0,
|
||
|
);
|
||
|
|
||
|
// Then subscribe the user to the discussion.
|
||
|
$this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
|
||
|
$this->helper_update_subscription_time($author, $discussion, -60);
|
||
|
|
||
|
// Then post a reply to the first discussion.
|
||
|
$reply = $this->helper_post_to_discussion($forum, $discussion, $author);
|
||
|
$this->helper_update_post_time($reply, -30);
|
||
|
|
||
|
$expect = [
|
||
|
(object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, [$reply]);
|
||
|
}
|
||
|
|
||
|
public function test_forum_message_inbound_multiple_posts() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create a user enrolled in the course as a student.
|
||
|
list($author) = $this->helper_create_users($course, 1);
|
||
|
|
||
|
$expectedmessages = array();
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
$this->helper_update_post_time($post, -90);
|
||
|
|
||
|
$expectedmessages[] = (object) [
|
||
|
'id' => $post->id,
|
||
|
'subject' => $post->subject,
|
||
|
'count' => 0,
|
||
|
];
|
||
|
|
||
|
// Then post a reply to the first discussion.
|
||
|
$reply = $this->helper_post_to_discussion($forum, $discussion, $author);
|
||
|
$this->helper_update_post_time($reply, -60);
|
||
|
|
||
|
$expectedmessages[] = (object) [
|
||
|
'id' => $reply->id,
|
||
|
'subject' => $reply->subject,
|
||
|
'count' => 1,
|
||
|
];
|
||
|
|
||
|
// Ensure that messageinbound is enabled and configured for the forum handler.
|
||
|
$this->helper_spoof_message_inbound_setup();
|
||
|
|
||
|
$author->emailstop = '0';
|
||
|
set_user_preference('message_provider_mod_forum_posts_loggedoff', 'email', $author);
|
||
|
set_user_preference('message_provider_mod_forum_posts_loggedin', 'email', $author);
|
||
|
|
||
|
// Run cron and check that the expected number of users received the notification.
|
||
|
// Clear the mailsink, and close the messagesink.
|
||
|
$this->mailsink->clear();
|
||
|
$this->messagesink->close();
|
||
|
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => count($expectedmessages),
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, $expectedmessages);
|
||
|
$messages = $this->mailsink->get_messages();
|
||
|
|
||
|
// There should be the expected number of messages.
|
||
|
$this->assertEquals(2, count($messages));
|
||
|
|
||
|
foreach ($messages as $message) {
|
||
|
$this->assertRegExp('/Reply-To: moodlemoodle123\+[^@]*@example.com/', $message->header);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function test_long_subject() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create a user enrolled in the course as student.
|
||
|
list($author) = $this->helper_create_users($course, 1);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
$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.';
|
||
|
$a = (object)array('courseshortname' => $course->shortname, 'forumname' => $forum->name, 'subject' => $subject);
|
||
|
$expectedsubject = get_string('postmailsubject', 'forum', $a);
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author, array('name' => $subject));
|
||
|
|
||
|
// Run cron and check that the expected number of users received the notification.
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, [$post]);
|
||
|
$messages = $this->messagesink->get_messages();
|
||
|
$message = reset($messages);
|
||
|
$this->assertEquals($author->id, $message->useridfrom);
|
||
|
$this->assertEquals($expectedsubject, $message->subject);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test inital email and reply email subjects
|
||
|
*/
|
||
|
public function test_subjects() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
list($author) = $this->helper_create_users($course, 1);
|
||
|
list($commenter) = $this->helper_create_users($course, 1);
|
||
|
|
||
|
$strre = get_string('re', 'forum');
|
||
|
|
||
|
// New posts should not have Re: in the subject.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'commenter' => (object) [
|
||
|
'userid' => $commenter->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, [$post]);
|
||
|
$this->send_notifications_and_assert($commenter, [$post]);
|
||
|
$messages = $this->messagesink->get_messages();
|
||
|
$this->assertNotContains($strre, $messages[0]->subject);
|
||
|
$this->messagesink->clear();
|
||
|
|
||
|
// Replies should have Re: in the subject.
|
||
|
$reply = $this->helper_post_to_discussion($forum, $discussion, $commenter);
|
||
|
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'commenter' => (object) [
|
||
|
'userid' => $commenter->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($commenter, [$reply]);
|
||
|
$this->send_notifications_and_assert($author, [$reply]);
|
||
|
$messages = $this->messagesink->get_messages();
|
||
|
$this->assertContains($strre, $messages[0]->subject);
|
||
|
$this->assertContains($strre, $messages[1]->subject);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* dataProvider for test_forum_post_email_templates().
|
||
|
*/
|
||
|
public function forum_post_email_templates_provider() {
|
||
|
// Base information, we'll build variations based on it.
|
||
|
$base = array(
|
||
|
'user' => array('firstname' => 'Love', 'lastname' => 'Moodle', 'mailformat' => 0, 'maildigest' => 0),
|
||
|
'course' => array('shortname' => '101', 'fullname' => 'Moodle 101'),
|
||
|
'forums' => array(
|
||
|
array(
|
||
|
'name' => 'Moodle Forum',
|
||
|
'forumposts' => array(
|
||
|
array(
|
||
|
'name' => 'Hello Moodle',
|
||
|
'message' => 'Welcome to Moodle',
|
||
|
'messageformat' => FORMAT_MOODLE,
|
||
|
'attachments' => array(
|
||
|
array(
|
||
|
'filename' => 'example.txt',
|
||
|
'filecontents' => 'Basic information about the course'
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
'expectations' => array(
|
||
|
array(
|
||
|
'subject' => '.*101.*Hello',
|
||
|
'contents' => array(
|
||
|
'~{$a',
|
||
|
'~&(amp|lt|gt|quot|\#039);(?!course)',
|
||
|
'Attachment example.txt:' . PHP_EOL .
|
||
|
'https://www.example.com/moodle/pluginfile.php/\d*/mod_forum/attachment/\d*/example.txt' . PHP_EOL,
|
||
|
'Hello Moodle', 'Moodle Forum', 'Welcome.*Moodle', 'Love Moodle', '1\d1'
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
|
||
|
// Build the text cases.
|
||
|
$textcases = array('Text mail without ampersands, quotes or lt/gt' => array('data' => $base));
|
||
|
|
||
|
// Single and double quotes everywhere.
|
||
|
$newcase = $base;
|
||
|
$newcase['user']['lastname'] = 'Moodle\'"';
|
||
|
$newcase['course']['shortname'] = '101\'"';
|
||
|
$newcase['forums'][0]['name'] = 'Moodle Forum\'"';
|
||
|
$newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle\'"';
|
||
|
$newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle\'"';
|
||
|
$newcase['expectations'][0]['contents'] = array(
|
||
|
'Attachment example.txt:', '~{\$a', '~&(quot|\#039);', 'Love Moodle\'', '101\'', 'Moodle Forum\'"',
|
||
|
'Hello Moodle\'"', 'Welcome to Moodle\'"');
|
||
|
$textcases['Text mail with quotes everywhere'] = array('data' => $newcase);
|
||
|
|
||
|
// Lt and gt everywhere. This case is completely borked because format_string()
|
||
|
// strips tags with $CFG->formatstringstriptags and also escapes < and > (correct
|
||
|
// for web presentation but not for text email). See MDL-19829.
|
||
|
$newcase = $base;
|
||
|
$newcase['user']['lastname'] = 'Moodle>';
|
||
|
$newcase['course']['shortname'] = '101>';
|
||
|
$newcase['forums'][0]['name'] = 'Moodle Forum>';
|
||
|
$newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle>';
|
||
|
$newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle>';
|
||
|
$newcase['expectations'][0]['contents'] = array(
|
||
|
'Attachment example.txt:', '~{\$a', '~&gt;', 'Love Moodle>', '101>', 'Moodle Forum>',
|
||
|
'Hello Moodle>', 'Welcome to Moodle>');
|
||
|
$textcases['Text mail with gt and lt everywhere'] = array('data' => $newcase);
|
||
|
|
||
|
// Ampersands everywhere. This case is completely borked because format_string()
|
||
|
// escapes ampersands (correct for web presentation but not for text email). See MDL-19829.
|
||
|
$newcase = $base;
|
||
|
$newcase['user']['lastname'] = 'Moodle&';
|
||
|
$newcase['course']['shortname'] = '101&';
|
||
|
$newcase['forums'][0]['name'] = 'Moodle Forum&';
|
||
|
$newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle&';
|
||
|
$newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle&';
|
||
|
$newcase['expectations'][0]['contents'] = array(
|
||
|
'Attachment example.txt:', '~{\$a', '~&amp;', 'Love Moodle&', '101&', 'Moodle Forum&',
|
||
|
'Hello Moodle&', 'Welcome to Moodle&');
|
||
|
$textcases['Text mail with ampersands everywhere'] = array('data' => $newcase);
|
||
|
|
||
|
// Text+image message i.e. @@PLUGINFILE@@ token handling.
|
||
|
$newcase = $base;
|
||
|
$newcase['forums'][0]['forumposts'][0]['name'] = 'Text and image';
|
||
|
$newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle, '
|
||
|
.'@@PLUGINFILE@@/Screen%20Shot%202016-03-22%20at%205.54.36%20AM%20%281%29.png !';
|
||
|
$newcase['expectations'][0]['subject'] = '.*101.*Text and image';
|
||
|
$newcase['expectations'][0]['contents'] = array(
|
||
|
'~{$a',
|
||
|
'~&(amp|lt|gt|quot|\#039);(?!course)',
|
||
|
'Attachment example.txt:' . PHP_EOL .
|
||
|
'https://www.example.com/moodle/pluginfile.php/\d*/mod_forum/attachment/\d*/example.txt' . PHP_EOL ,
|
||
|
'Text and image', 'Moodle Forum',
|
||
|
'Welcome to Moodle, *' . PHP_EOL . '.*'
|
||
|
.'https://www.example.com/moodle/pluginfile.php/\d+/mod_forum/post/\d+/'
|
||
|
.'Screen%20Shot%202016-03-22%20at%205\.54\.36%20AM%20%281%29\.png *' . PHP_EOL . '.*!',
|
||
|
'Love Moodle', '1\d1');
|
||
|
$textcases['Text mail with text+image message i.e. @@PLUGINFILE@@ token handling'] = array('data' => $newcase);
|
||
|
|
||
|
// Now the html cases.
|
||
|
$htmlcases = array();
|
||
|
|
||
|
// New base for html cases, no quotes, lts, gts or ampersands.
|
||
|
$htmlbase = $base;
|
||
|
$htmlbase['user']['mailformat'] = 1;
|
||
|
$htmlbase['expectations'][0]['contents'] = array(
|
||
|
'~{\$a',
|
||
|
'~&(amp|lt|gt|quot|\#039);(?!course)',
|
||
|
'<div class="attachments">( *\n *)?<a href',
|
||
|
'<div class="subject">\n.*Hello Moodle', '>Moodle Forum', '>Welcome.*Moodle', '>Love Moodle', '>1\d1');
|
||
|
$htmlcases['HTML mail without ampersands, quotes or lt/gt'] = array('data' => $htmlbase);
|
||
|
|
||
|
// Single and double quotes, lt and gt, ampersands everywhere.
|
||
|
$newcase = $htmlbase;
|
||
|
$newcase['user']['lastname'] = 'Moodle\'">&';
|
||
|
$newcase['course']['shortname'] = '101\'">&';
|
||
|
$newcase['forums'][0]['name'] = 'Moodle Forum\'">&';
|
||
|
$newcase['forums'][0]['forumposts'][0]['name'] = 'Hello Moodle\'">&';
|
||
|
$newcase['forums'][0]['forumposts'][0]['message'] = 'Welcome to Moodle\'">&';
|
||
|
$newcase['expectations'][0]['contents'] = array(
|
||
|
'~{\$a',
|
||
|
'~&(amp|lt|gt|quot|\#039);',
|
||
|
'<div class="attachments">( *\n *)?<a href',
|
||
|
'<div class="subject">\n.*Hello Moodle\'">&', '>Moodle Forum\'">&',
|
||
|
'>Welcome.*Moodle\'">&', '>Love Moodle&\#039;">&', '>101\'">&');
|
||
|
$htmlcases['HTML mail with quotes, gt, lt and ampersand everywhere'] = array('data' => $newcase);
|
||
|
|
||
|
// Text+image message i.e. @@PLUGINFILE@@ token handling.
|
||
|
$newcase = $htmlbase;
|
||
|
$newcase['forums'][0]['forumposts'][0]['name'] = 'HTML text and image';
|
||
|
$newcase['forums'][0]['forumposts'][0]['message'] = '<p>Welcome to Moodle, '
|
||
|
.'<img src="@@PLUGINFILE@@/Screen%20Shot%202016-03-22%20at%205.54.36%20AM%20%281%29.png"'
|
||
|
.' alt="" width="200" height="393" class="img-responsive" />!</p>';
|
||
|
$newcase['expectations'][0]['subject'] = '.*101.*HTML text and image';
|
||
|
$newcase['expectations'][0]['contents'] = array(
|
||
|
'~{\$a',
|
||
|
'~&(amp|lt|gt|quot|\#039);(?!course)',
|
||
|
'<div class="attachments">( *\n *)?<a href',
|
||
|
'<div class="subject">\n.*HTML text and image', '>Moodle Forum',
|
||
|
'<p>Welcome to Moodle, '
|
||
|
.'<img src="https://www.example.com/moodle/tokenpluginfile.php/[^/]*/\d+/mod_forum/post/\d+/'
|
||
|
.'Screen%20Shot%202016-03-22%20at%205\.54\.36%20AM%20%281%29\.png"'
|
||
|
.' alt="" width="200" height="393" class="img-responsive" />!</p>',
|
||
|
'>Love Moodle', '>1\d1');
|
||
|
$htmlcases['HTML mail with text+image message i.e. @@PLUGINFILE@@ token handling'] = array('data' => $newcase);
|
||
|
|
||
|
return $textcases + $htmlcases;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Verify forum emails body using templates to generate the expected results.
|
||
|
*
|
||
|
* @dataProvider forum_post_email_templates_provider
|
||
|
* @param array $data provider samples.
|
||
|
*/
|
||
|
public function test_forum_post_email_templates($data) {
|
||
|
global $DB;
|
||
|
|
||
|
$this->resetAfterTest();
|
||
|
|
||
|
// Create the course, with the specified options.
|
||
|
$options = array();
|
||
|
foreach ($data['course'] as $option => $value) {
|
||
|
$options[$option] = $value;
|
||
|
}
|
||
|
$course = $this->getDataGenerator()->create_course($options);
|
||
|
|
||
|
// Create the user, with the specified options and enrol in the course.
|
||
|
$options = array();
|
||
|
foreach ($data['user'] as $option => $value) {
|
||
|
$options[$option] = $value;
|
||
|
}
|
||
|
$user = $this->getDataGenerator()->create_user($options);
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course->id);
|
||
|
|
||
|
// Create forums, always force susbscribed (for easy), with the specified options.
|
||
|
$posts = array();
|
||
|
foreach ($data['forums'] as $dataforum) {
|
||
|
$forumposts = isset($dataforum['forumposts']) ? $dataforum['forumposts'] : array();
|
||
|
unset($dataforum['forumposts']);
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
|
||
|
foreach ($dataforum as $option => $value) {
|
||
|
$options[$option] = $value;
|
||
|
}
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create posts, always for immediate delivery (for easy), with the specified options.
|
||
|
foreach ($forumposts as $forumpost) {
|
||
|
$attachments = isset($forumpost['attachments']) ? $forumpost['attachments'] : array();
|
||
|
unset($forumpost['attachments']);
|
||
|
$postoptions = array('course' => $course->id, 'forum' => $forum->id, 'userid' => $user->id,
|
||
|
'mailnow' => 1, 'attachment' => !empty($attachments));
|
||
|
foreach ($forumpost as $option => $value) {
|
||
|
$postoptions[$option] = $value;
|
||
|
}
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $user, $postoptions);
|
||
|
$posts[$post->subject] = $post; // Need this to verify cron output.
|
||
|
|
||
|
// Add the attachments to the post.
|
||
|
if ($attachments) {
|
||
|
$fs = get_file_storage();
|
||
|
foreach ($attachments as $attachment) {
|
||
|
$filerecord = array(
|
||
|
'contextid' => context_module::instance($forum->cmid)->id,
|
||
|
'component' => 'mod_forum',
|
||
|
'filearea' => 'attachment',
|
||
|
'itemid' => $post->id,
|
||
|
'filepath' => '/',
|
||
|
'filename' => $attachment['filename']
|
||
|
);
|
||
|
$fs->create_file_from_string($filerecord, $attachment['filecontents']);
|
||
|
}
|
||
|
$DB->set_field('forum_posts', 'attachment', '1', array('id' => $post->id));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Clear the mailsink and close the messagesink.
|
||
|
// (surely setup should provide us this cleared but...)
|
||
|
$this->mailsink->clear();
|
||
|
$this->messagesink->close();
|
||
|
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $user->id,
|
||
|
'messages' => count($posts),
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($user, $posts);
|
||
|
|
||
|
// Get the mails.
|
||
|
$mails = $this->mailsink->get_messages();
|
||
|
|
||
|
// Start testing the expectations.
|
||
|
$expectations = $data['expectations'];
|
||
|
|
||
|
// Assert the number is the expected.
|
||
|
$this->assertSame(count($expectations), count($mails));
|
||
|
|
||
|
// Start processing mails, first localizing its expectations, then checking them.
|
||
|
foreach ($mails as $mail) {
|
||
|
// Find the corresponding expectation.
|
||
|
$foundexpectation = null;
|
||
|
foreach ($expectations as $key => $expectation) {
|
||
|
// All expectations must have a subject for matching.
|
||
|
if (!isset($expectation['subject'])) {
|
||
|
$this->fail('Provider expectation missing mandatory subject');
|
||
|
}
|
||
|
if (preg_match('!' . $expectation['subject'] . '!', $mail->subject)) {
|
||
|
// If we already had found the expectation, there are non-unique subjects. Fail.
|
||
|
if (isset($foundexpectation)) {
|
||
|
$this->fail('Multiple expectations found (by subject matching). Please make them unique.');
|
||
|
}
|
||
|
$foundexpectation = $expectation;
|
||
|
unset($expectations[$key]);
|
||
|
}
|
||
|
}
|
||
|
// Arrived here, we should have found the expectations.
|
||
|
$this->assertNotEmpty($foundexpectation, 'Expectation not found for the mail');
|
||
|
|
||
|
// If we have found the expectation and have contents to match, let's do it.
|
||
|
if (isset($foundexpectation) and isset($foundexpectation['contents'])) {
|
||
|
$mail->body = quoted_printable_decode($mail->body);
|
||
|
if (!is_array($foundexpectation['contents'])) { // Accept both string and array.
|
||
|
$foundexpectation['contents'] = array($foundexpectation['contents']);
|
||
|
}
|
||
|
foreach ($foundexpectation['contents'] as $content) {
|
||
|
if (strpos($content, '~') !== 0) {
|
||
|
$this->assertRegexp('#' . $content . '#m', $mail->body);
|
||
|
} else {
|
||
|
preg_match('#' . substr($content, 1) . '#m', $mail->body, $matches);
|
||
|
$this->assertNotRegexp('#' . substr($content, 1) . '#m', $mail->body);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Finished, there should not be remaining expectations.
|
||
|
$this->assertCount(0, $expectations);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that posts already mailed are not re-sent.
|
||
|
*/
|
||
|
public function test_already_mailed() {
|
||
|
global $DB;
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
$DB->set_field('forum_posts', 'mailed', 1);
|
||
|
|
||
|
// No posts shoudl be considered.
|
||
|
$this->queue_tasks_and_assert([]);
|
||
|
|
||
|
// No notifications should be queued.
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, []);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that posts marked mailnow are not suspect to the maxeditingtime.
|
||
|
*/
|
||
|
public function test_mailnow() {
|
||
|
global $CFG, $DB;
|
||
|
|
||
|
// Update the maxeditingtime to 1 day so that posts won't be sent.
|
||
|
$CFG->maxeditingtime = DAYSECS;
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $postmailednow) = $this->helper_post_to_forum($forum, $author, ['mailnow' => 1]);
|
||
|
|
||
|
// Only the mailnow post should be considered.
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'recipient' => (object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
// No notifications should be queued.
|
||
|
$this->send_notifications_and_assert($author, [$postmailednow]);
|
||
|
$this->send_notifications_and_assert($recipient, [$postmailednow]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that if a user has no permission to view a post, then it is not sent.
|
||
|
*/
|
||
|
public function test_access_coursemodule_hidden() {
|
||
|
global $CFG, $DB;
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Create one users enrolled in the course as an editing teacher.
|
||
|
list($editor) = $this->helper_create_users($course, 1, 'editingteacher');
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
// Hide the coursemodule.
|
||
|
set_coursemodule_visible($forum->cmid, 0);
|
||
|
|
||
|
// Only the mailnow post should be considered.
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'recipient' => (object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'editor' => (object) [
|
||
|
'userid' => $editor->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
// No notifications should be queued.
|
||
|
$this->send_notifications_and_assert($author, [], true);
|
||
|
$this->send_notifications_and_assert($recipient, [], true);
|
||
|
$this->send_notifications_and_assert($editor, [$post], true);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that if a user loses permission to view a post after it is queued, that it is not sent.
|
||
|
*/
|
||
|
public function test_access_coursemodule_hidden_after_queue() {
|
||
|
global $CFG, $DB;
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Create one users enrolled in the course as an editing teacher.
|
||
|
list($editor) = $this->helper_create_users($course, 1, 'editingteacher');
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
// Only the mailnow post should be considered.
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'recipient' => (object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'editor' => (object) [
|
||
|
'userid' => $editor->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
// Hide the coursemodule.
|
||
|
set_coursemodule_visible($forum->cmid, 0);
|
||
|
|
||
|
// No notifications should be queued for the students.
|
||
|
$this->send_notifications_and_assert($author, [], true);
|
||
|
$this->send_notifications_and_assert($recipient, [], true);
|
||
|
|
||
|
// The editing teacher should still receive the post.
|
||
|
$this->send_notifications_and_assert($editor, [$post]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that messages are not sent until the timestart.
|
||
|
*/
|
||
|
public function test_access_before_timestart() {
|
||
|
global $CFG, $DB;
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Create one users enrolled in the course as an editing teacher.
|
||
|
list($editor) = $this->helper_create_users($course, 1, 'editingteacher');
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
// Update the discussion to have a timestart in the future.
|
||
|
$DB->set_field('forum_discussions', 'timestart', time() + DAYSECS);
|
||
|
|
||
|
// None should be sent.
|
||
|
$this->queue_tasks_and_assert([]);
|
||
|
|
||
|
// No notifications should be queued for any user.
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, []);
|
||
|
$this->send_notifications_and_assert($editor, []);
|
||
|
|
||
|
// Update the discussion to have a timestart in the past.
|
||
|
$DB->set_field('forum_discussions', 'timestart', time() - DAYSECS);
|
||
|
|
||
|
// Now should be sent to all.
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'recipient' => (object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'editor' => (object) [
|
||
|
'userid' => $editor->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
// No notifications should be queued for any user.
|
||
|
$this->send_notifications_and_assert($author, [$post]);
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
$this->send_notifications_and_assert($editor, [$post]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Ensure that messages are not sent after the timeend.
|
||
|
*/
|
||
|
public function test_access_after_timeend() {
|
||
|
global $CFG, $DB;
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
// Create a course, with a forum.
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
// Create two users enrolled in the course as students.
|
||
|
list($author, $recipient) = $this->helper_create_users($course, 2);
|
||
|
|
||
|
// Create one users enrolled in the course as an editing teacher.
|
||
|
list($editor) = $this->helper_create_users($course, 1, 'editingteacher');
|
||
|
|
||
|
// Post a discussion to the forum.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
|
||
|
// Update the discussion to have a timestart in the past.
|
||
|
$DB->set_field('forum_discussions', 'timeend', time() - DAYSECS);
|
||
|
|
||
|
// None should be sent.
|
||
|
$this->queue_tasks_and_assert([]);
|
||
|
|
||
|
// No notifications should be queued for any user.
|
||
|
$this->send_notifications_and_assert($author, []);
|
||
|
$this->send_notifications_and_assert($recipient, []);
|
||
|
$this->send_notifications_and_assert($editor, []);
|
||
|
|
||
|
// Update the discussion to have a timestart in the past.
|
||
|
$DB->set_field('forum_discussions', 'timeend', time() + DAYSECS);
|
||
|
|
||
|
// Now should be sent to all.
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'recipient' => (object) [
|
||
|
'userid' => $recipient->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'editor' => (object) [
|
||
|
'userid' => $editor->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
// No notifications should be queued for any user.
|
||
|
$this->send_notifications_and_assert($author, [$post]);
|
||
|
$this->send_notifications_and_assert($recipient, [$post]);
|
||
|
$this->send_notifications_and_assert($editor, [$post]);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test notification comes with customdata.
|
||
|
*/
|
||
|
public function test_notification_customdata() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
$options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
|
||
|
$forum = $this->getDataGenerator()->create_module('forum', $options);
|
||
|
|
||
|
list($author) = $this->helper_create_users($course, 1);
|
||
|
list($commenter) = $this->helper_create_users($course, 1);
|
||
|
|
||
|
$strre = get_string('re', 'forum');
|
||
|
|
||
|
// New posts should not have Re: in the subject.
|
||
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
||
|
$expect = [
|
||
|
'author' => (object) [
|
||
|
'userid' => $author->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
'commenter' => (object) [
|
||
|
'userid' => $commenter->id,
|
||
|
'messages' => 1,
|
||
|
],
|
||
|
];
|
||
|
$this->queue_tasks_and_assert($expect);
|
||
|
|
||
|
$this->send_notifications_and_assert($author, [$post]);
|
||
|
$this->send_notifications_and_assert($commenter, [$post]);
|
||
|
$messages = $this->messagesink->get_messages();
|
||
|
$customdata = json_decode($messages[0]->customdata);
|
||
|
$this->assertEquals($forum->id, $customdata->instance);
|
||
|
$this->assertEquals($forum->cmid, $customdata->cmid);
|
||
|
$this->assertEquals($post->id, $customdata->postid);
|
||
|
$this->assertEquals($discussion->id, $customdata->discussionid);
|
||
|
$this->assertObjectHasAttribute('notificationiconurl', $customdata);
|
||
|
$this->assertObjectHasAttribute('actionbuttons', $customdata);
|
||
|
$this->assertCount(1, (array) $customdata->actionbuttons);
|
||
|
}
|
||
|
}
|