mirror of
https://github.com/moodle/moodle.git
synced 2025-07-12 18:06:41 +02:00
Under certain conditions, users marked as not confirmed yet may be returned as forum notification recipients. Such users are considered as inactive though and the delivery adhoc task cannot be run as these users, throwing an exception. The solution is to make sure that fetch_subscribed_users() does not include unconfirmed users, similarly to what was done for suspended users and nologin users. The added unit test also checks for deleted users. But these should never be returned as subscribed because we consider enrolled users only and deleted users are filtered out implicitly.
1607 lines
63 KiB
PHP
1607 lines
63 KiB
PHP
<?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() {
|
|
global $DB;
|
|
$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 users enrolled in the course as students.
|
|
list($author, $recipient, $unconfirmed, $deleted) = $this->helper_create_users($course, 4);
|
|
|
|
// Make the third user unconfirmed (thence inactive) to make sure it does not break the notifications.
|
|
$DB->set_field('user', 'confirmed', 0, ['id' => $unconfirmed->id]);
|
|
|
|
// Mark the fourth user as deleted to make sure it does not break the notifications.
|
|
$DB->set_field('user', 'deleted', 1, ['id' => $deleted->id]);
|
|
|
|
// 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,
|
|
],
|
|
(object) [
|
|
'userid' => $unconfirmed->id,
|
|
'messages' => 0,
|
|
],
|
|
(object) [
|
|
'userid' => $deleted->id,
|
|
'messages' => 0,
|
|
],
|
|
];
|
|
$this->queue_tasks_and_assert($expect);
|
|
|
|
$this->send_notifications_and_assert($author, [$post]);
|
|
$this->send_notifications_and_assert($recipient, [$post]);
|
|
$this->send_notifications_and_assert($unconfirmed, []);
|
|
$this->send_notifications_and_assert($deleted, []);
|
|
}
|
|
|
|
/**
|
|
* 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_subscription_by_inactive_users() {
|
|
global $DB;
|
|
$this->resetAfterTest(true);
|
|
|
|
$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, $u1, $u2, $u3) = $this->helper_create_users($course, 4);
|
|
|
|
// Subscribe the three users to the forum.
|
|
\mod_forum\subscriptions::subscribe_user($u1->id, $forum);
|
|
\mod_forum\subscriptions::subscribe_user($u2->id, $forum);
|
|
\mod_forum\subscriptions::subscribe_user($u3->id, $forum);
|
|
|
|
// Make the first user inactive - suspended.
|
|
$DB->set_field('user', 'suspended', 1, ['id' => $u1->id]);
|
|
|
|
// Make the second user inactive - unable to log in.
|
|
$DB->set_field('user', 'auth', 'nologin', ['id' => $u2->id]);
|
|
|
|
// Post a discussion to the forum.
|
|
list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
|
|
|
|
$expect = [
|
|
(object) [
|
|
'userid' => $u1->id,
|
|
'messages' => 0,
|
|
],
|
|
(object) [
|
|
'userid' => $u2->id,
|
|
'messages' => 0,
|
|
],
|
|
(object) [
|
|
'userid' => $u3->id,
|
|
'messages' => 1,
|
|
],
|
|
];
|
|
|
|
$this->queue_tasks_and_assert($expect);
|
|
$this->send_notifications_and_assert($u1, []);
|
|
$this->send_notifications_and_assert($u2, []);
|
|
$this->send_notifications_and_assert($u3, [$post]);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|