MDL-65069 mod_forum: Remove unused code and additional dev docs.
[moodle.git] / mod / forum / tests / subscriptions_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * The module forums tests
19  *
20  * @package    mod_forum
21  * @copyright  2013 Frédéric Massart
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 global $CFG;
28 require_once(__DIR__ . '/generator_trait.php');
29 require_once("{$CFG->dirroot}/mod/forum/lib.php");
31 class mod_forum_subscriptions_testcase extends advanced_testcase {
32     // Include the mod_forum test helpers.
33     // This includes functions to create forums, users, discussions, and posts.
34     use mod_forum_tests_generator_trait;
36     /**
37      * Test setUp.
38      */
39     public function setUp() {
40         global $DB;
42         // We must clear the subscription caches. This has to be done both before each test, and after in case of other
43         // tests using these functions.
44         \mod_forum\subscriptions::reset_forum_cache();
45         \mod_forum\subscriptions::reset_discussion_cache();
46     }
48     /**
49      * Test tearDown.
50      */
51     public function tearDown() {
52         // We must clear the subscription caches. This has to be done both before each test, and after in case of other
53         // tests using these functions.
54         \mod_forum\subscriptions::reset_forum_cache();
55         \mod_forum\subscriptions::reset_discussion_cache();
56     }
58     public function test_subscription_modes() {
59         global $DB;
61         $this->resetAfterTest(true);
63         // Create a course, with a forum.
64         $course = $this->getDataGenerator()->create_course();
66         $options = array('course' => $course->id);
67         $forum = $this->getDataGenerator()->create_module('forum', $options);
69         // Create a user enrolled in the course as a student.
70         list($user) = $this->helper_create_users($course, 1);
72         // Must be logged in as the current user.
73         $this->setUser($user);
75         \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_FORCESUBSCRIBE);
76         $forum = $DB->get_record('forum', array('id' => $forum->id));
77         $this->assertEquals(FORUM_FORCESUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
78         $this->assertTrue(\mod_forum\subscriptions::is_forcesubscribed($forum));
79         $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
80         $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
82         \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_DISALLOWSUBSCRIBE);
83         $forum = $DB->get_record('forum', array('id' => $forum->id));
84         $this->assertEquals(FORUM_DISALLOWSUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
85         $this->assertTrue(\mod_forum\subscriptions::subscription_disabled($forum));
86         $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
87         $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
89         \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_INITIALSUBSCRIBE);
90         $forum = $DB->get_record('forum', array('id' => $forum->id));
91         $this->assertEquals(FORUM_INITIALSUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
92         $this->assertTrue(\mod_forum\subscriptions::is_subscribable($forum));
93         $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
94         $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
96         \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_CHOOSESUBSCRIBE);
97         $forum = $DB->get_record('forum', array('id' => $forum->id));
98         $this->assertEquals(FORUM_CHOOSESUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
99         $this->assertTrue(\mod_forum\subscriptions::is_subscribable($forum));
100         $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
101         $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
102     }
104     /**
105      * Test fetching unsubscribable forums.
106      */
107     public function test_unsubscribable_forums() {
108         global $DB;
110         $this->resetAfterTest(true);
112         // Create a course, with a forum.
113         $course = $this->getDataGenerator()->create_course();
115         // Create a user enrolled in the course as a student.
116         list($user) = $this->helper_create_users($course, 1);
118         // Must be logged in as the current user.
119         $this->setUser($user);
121         // Without any subscriptions, there should be nothing returned.
122         $result = \mod_forum\subscriptions::get_unsubscribable_forums();
123         $this->assertEquals(0, count($result));
125         // Create the forums.
126         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
127         $forceforum = $this->getDataGenerator()->create_module('forum', $options);
128         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
129         $disallowforum = $this->getDataGenerator()->create_module('forum', $options);
130         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
131         $chooseforum = $this->getDataGenerator()->create_module('forum', $options);
132         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
133         $initialforum = $this->getDataGenerator()->create_module('forum', $options);
135         // At present the user is only subscribed to the initial forum.
136         $result = \mod_forum\subscriptions::get_unsubscribable_forums();
137         $this->assertEquals(1, count($result));
139         // Ensure that the user is enrolled in all of the forums except force subscribed.
140         \mod_forum\subscriptions::subscribe_user($user->id, $disallowforum);
141         \mod_forum\subscriptions::subscribe_user($user->id, $chooseforum);
143         $result = \mod_forum\subscriptions::get_unsubscribable_forums();
144         $this->assertEquals(3, count($result));
146         // Hide the forums.
147         set_coursemodule_visible($forceforum->cmid, 0);
148         set_coursemodule_visible($disallowforum->cmid, 0);
149         set_coursemodule_visible($chooseforum->cmid, 0);
150         set_coursemodule_visible($initialforum->cmid, 0);
151         $result = \mod_forum\subscriptions::get_unsubscribable_forums();
152         $this->assertEquals(0, count($result));
154         // Add the moodle/course:viewhiddenactivities capability to the student user.
155         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
156         $context = \context_course::instance($course->id);
157         assign_capability('moodle/course:viewhiddenactivities', CAP_ALLOW, $roleids['student'], $context);
159         // All of the unsubscribable forums should now be listed.
160         $result = \mod_forum\subscriptions::get_unsubscribable_forums();
161         $this->assertEquals(3, count($result));
162     }
164     /**
165      * Test that toggling the forum-level subscription for a different user does not affect their discussion-level
166      * subscriptions.
167      */
168     public function test_forum_subscribe_toggle_as_other() {
169         global $DB;
171         $this->resetAfterTest(true);
173         // Create a course, with a forum.
174         $course = $this->getDataGenerator()->create_course();
176         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
177         $forum = $this->getDataGenerator()->create_module('forum', $options);
179         // Create a user enrolled in the course as a student.
180         list($author) = $this->helper_create_users($course, 1);
182         // Post a discussion to the forum.
183         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
185         // Check that the user is currently not subscribed to the forum.
186         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
188         // Check that the user is unsubscribed from the discussion too.
189         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
191         // Check that we have no records in either of the subscription tables.
192         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
193             'userid'        => $author->id,
194             'forum'         => $forum->id,
195         )));
196         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
197             'userid'        => $author->id,
198             'discussion'    => $discussion->id,
199         )));
201         // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
202         // subscriptions table.
203         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
204         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
205             'userid'        => $author->id,
206             'forum'         => $forum->id,
207         )));
208         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
209             'userid'        => $author->id,
210             'discussion'    => $discussion->id,
211         )));
213         // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
214         // discussion subscriptions table.
215         \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
216         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
217             'userid'        => $author->id,
218             'forum'         => $forum->id,
219         )));
220         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
221             'userid'        => $author->id,
222             'discussion'    => $discussion->id,
223         )));
225         // Enroling the user in the discussion should add one record to the forum discussion table without modifying the
226         // form subscriptions.
227         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
228         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
229             'userid'        => $author->id,
230             'forum'         => $forum->id,
231         )));
232         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
233             'userid'        => $author->id,
234             'discussion'    => $discussion->id,
235         )));
237         // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
238         // discussion subscriptions table.
239         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
240         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
241             'userid'        => $author->id,
242             'forum'         => $forum->id,
243         )));
244         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
245             'userid'        => $author->id,
246             'discussion'    => $discussion->id,
247         )));
249         // Re-subscribe to the discussion so that we can check the effect of forum-level subscriptions.
250         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
251         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
252             'userid'        => $author->id,
253             'forum'         => $forum->id,
254         )));
255         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
256             'userid'        => $author->id,
257             'discussion'    => $discussion->id,
258         )));
260         // Subscribing to the forum should have no effect on the forum discussion subscriptions table if the user did
261         // not request the change themself.
262         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
263         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
264             'userid'        => $author->id,
265             'forum'         => $forum->id,
266         )));
267         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
268             'userid'        => $author->id,
269             'discussion'    => $discussion->id,
270         )));
272         // Unsubscribing from the forum should have no effect on the forum discussion subscriptions table if the user
273         // did not request the change themself.
274         \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
275         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
276             'userid'        => $author->id,
277             'forum'         => $forum->id,
278         )));
279         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
280             'userid'        => $author->id,
281             'discussion'    => $discussion->id,
282         )));
284         // Subscribing to the forum should remove the per-discussion subscription preference if the user requested the
285         // change themself.
286         \mod_forum\subscriptions::subscribe_user($author->id, $forum, null, true);
287         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
288             'userid'        => $author->id,
289             'forum'         => $forum->id,
290         )));
291         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
292             'userid'        => $author->id,
293             'discussion'    => $discussion->id,
294         )));
296         // Now unsubscribe from the current discussion whilst being subscribed to the forum as a whole.
297         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
298         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
299             'userid'        => $author->id,
300             'forum'         => $forum->id,
301         )));
302         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
303             'userid'        => $author->id,
304             'discussion'    => $discussion->id,
305         )));
307         // Unsubscribing from the forum should remove the per-discussion subscription preference if the user requested the
308         // change themself.
309         \mod_forum\subscriptions::unsubscribe_user($author->id, $forum, null, true);
310         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
311             'userid'        => $author->id,
312             'forum'         => $forum->id,
313         )));
314         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
315             'userid'        => $author->id,
316             'discussion'    => $discussion->id,
317         )));
319         // Subscribe to the discussion.
320         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
321         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
322             'userid'        => $author->id,
323             'forum'         => $forum->id,
324         )));
325         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
326             'userid'        => $author->id,
327             'discussion'    => $discussion->id,
328         )));
330         // Subscribe to the forum without removing the discussion preferences.
331         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
332         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
333             'userid'        => $author->id,
334             'forum'         => $forum->id,
335         )));
336         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
337             'userid'        => $author->id,
338             'discussion'    => $discussion->id,
339         )));
341         // Unsubscribing from the discussion should result in a change.
342         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
343         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
344             'userid'        => $author->id,
345             'forum'         => $forum->id,
346         )));
347         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
348             'userid'        => $author->id,
349             'discussion'    => $discussion->id,
350         )));
352     }
354     /**
355      * Test that a user unsubscribed from a forum is not subscribed to it's discussions by default.
356      */
357     public function test_forum_discussion_subscription_forum_unsubscribed() {
358         $this->resetAfterTest(true);
360         // Create a course, with a forum.
361         $course = $this->getDataGenerator()->create_course();
363         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
364         $forum = $this->getDataGenerator()->create_module('forum', $options);
366         // Create users enrolled in the course as students.
367         list($author) = $this->helper_create_users($course, 1);
369         // Check that the user is currently not subscribed to the forum.
370         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
372         // Post a discussion to the forum.
373         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
375         // Check that the user is unsubscribed from the discussion too.
376         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
377     }
379     /**
380      * Test that the act of subscribing to a forum subscribes the user to it's discussions by default.
381      */
382     public function test_forum_discussion_subscription_forum_subscribed() {
383         $this->resetAfterTest(true);
385         // Create a course, with a forum.
386         $course = $this->getDataGenerator()->create_course();
388         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
389         $forum = $this->getDataGenerator()->create_module('forum', $options);
391         // Create users enrolled in the course as students.
392         list($author) = $this->helper_create_users($course, 1);
394         // Enrol the user in the forum.
395         // If a subscription was added, we get the record ID.
396         $this->assertInternalType('int', \mod_forum\subscriptions::subscribe_user($author->id, $forum));
398         // If we already have a subscription when subscribing the user, we get a boolean (true).
399         $this->assertTrue(\mod_forum\subscriptions::subscribe_user($author->id, $forum));
401         // Check that the user is currently subscribed to the forum.
402         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
404         // Post a discussion to the forum.
405         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
407         // Check that the user is subscribed to the discussion too.
408         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
409     }
411     /**
412      * Test that a user unsubscribed from a forum can be subscribed to a discussion.
413      */
414     public function test_forum_discussion_subscription_forum_unsubscribed_discussion_subscribed() {
415         $this->resetAfterTest(true);
417         // Create a course, with a forum.
418         $course = $this->getDataGenerator()->create_course();
420         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
421         $forum = $this->getDataGenerator()->create_module('forum', $options);
423         // Create a user enrolled in the course as a student.
424         list($author) = $this->helper_create_users($course, 1);
426         // Check that the user is currently not subscribed to the forum.
427         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
429         // Post a discussion to the forum.
430         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
432         // Attempting to unsubscribe from the discussion should not make a change.
433         $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion));
435         // Then subscribe them to the discussion.
436         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
438         // Check that the user is still unsubscribed from the forum.
439         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
441         // But subscribed to the discussion.
442         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
443     }
445     /**
446      * Test that a user subscribed to a forum can be unsubscribed from a discussion.
447      */
448     public function test_forum_discussion_subscription_forum_subscribed_discussion_unsubscribed() {
449         $this->resetAfterTest(true);
451         // Create a course, with a forum.
452         $course = $this->getDataGenerator()->create_course();
454         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
455         $forum = $this->getDataGenerator()->create_module('forum', $options);
457         // Create two users enrolled in the course as students.
458         list($author) = $this->helper_create_users($course, 2);
460         // Enrol the student in the forum.
461         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
463         // Check that the user is currently subscribed to the forum.
464         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
466         // Post a discussion to the forum.
467         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
469         // Then unsubscribe them from the discussion.
470         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
472         // Check that the user is still subscribed to the forum.
473         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
475         // But unsubscribed from the discussion.
476         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
477     }
479     /**
480      * Test the effect of toggling the discussion subscription status when subscribed to the forum.
481      */
482     public function test_forum_discussion_toggle_forum_subscribed() {
483         global $DB;
485         $this->resetAfterTest(true);
487         // Create a course, with a forum.
488         $course = $this->getDataGenerator()->create_course();
490         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
491         $forum = $this->getDataGenerator()->create_module('forum', $options);
493         // Create two users enrolled in the course as students.
494         list($author) = $this->helper_create_users($course, 2);
496         // Enrol the student in the forum.
497         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
499         // Check that the user is currently subscribed to the forum.
500         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
502         // Post a discussion to the forum.
503         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
505         // Check that the user is initially subscribed to that discussion.
506         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
508         // An attempt to subscribe again should result in a falsey return to indicate that no change was made.
509         $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
511         // And there should be no discussion subscriptions (and one forum subscription).
512         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
513             'userid'        => $author->id,
514             'discussion'    => $discussion->id,
515         )));
516         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
517             'userid'        => $author->id,
518             'forum'         => $forum->id,
519         )));
521         // Then unsubscribe them from the discussion.
522         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
524         // Check that the user is still subscribed to the forum.
525         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
527         // An attempt to unsubscribe again should result in a falsey return to indicate that no change was made.
528         $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion));
530         // And there should be a discussion subscriptions (and one forum subscription).
531         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
532             'userid'        => $author->id,
533             'discussion'    => $discussion->id,
534         )));
535         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
536             'userid'        => $author->id,
537             'forum'         => $forum->id,
538         )));
540         // But unsubscribed from the discussion.
541         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
543         // There should be a record in the discussion subscription tracking table.
544         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
545             'userid'        => $author->id,
546             'discussion'    => $discussion->id,
547         )));
549         // And one in the forum subscription tracking table.
550         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
551             'userid'        => $author->id,
552             'forum'         => $forum->id,
553         )));
555         // Now subscribe the user again to the discussion.
556         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
558         // Check that the user is still subscribed to the forum.
559         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
561         // And is subscribed to the discussion again.
562         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
564         // There should be no record in the discussion subscription tracking table.
565         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
566             'userid'        => $author->id,
567             'discussion'    => $discussion->id,
568         )));
570         // And one in the forum subscription tracking table.
571         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
572             'userid'        => $author->id,
573             'forum'         => $forum->id,
574         )));
576         // And unsubscribe again.
577         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
579         // Check that the user is still subscribed to the forum.
580         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
582         // But unsubscribed from the discussion.
583         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
585         // There should be a record in the discussion subscription tracking table.
586         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
587             'userid'        => $author->id,
588             'discussion'    => $discussion->id,
589         )));
591         // And one in the forum subscription tracking table.
592         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
593             'userid'        => $author->id,
594             'forum'         => $forum->id,
595         )));
597         // And subscribe the user again to the discussion.
598         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
600         // Check that the user is still subscribed to the forum.
601         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
602         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
604         // And is subscribed to the discussion again.
605         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
607         // There should be no record in the discussion subscription tracking table.
608         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
609             'userid'        => $author->id,
610             'discussion'    => $discussion->id,
611         )));
613         // And one in the forum subscription tracking table.
614         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
615             'userid'        => $author->id,
616             'forum'         => $forum->id,
617         )));
619         // And unsubscribe again.
620         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
622         // Check that the user is still subscribed to the forum.
623         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
625         // But unsubscribed from the discussion.
626         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
628         // There should be a record in the discussion subscription tracking table.
629         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
630             'userid'        => $author->id,
631             'discussion'    => $discussion->id,
632         )));
634         // And one in the forum subscription tracking table.
635         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
636             'userid'        => $author->id,
637             'forum'         => $forum->id,
638         )));
640         // Now unsubscribe the user from the forum.
641         $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user($author->id, $forum, null, true));
643         // This removes both the forum_subscriptions, and the forum_discussion_subs records.
644         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
645             'userid'        => $author->id,
646             'discussion'    => $discussion->id,
647         )));
648         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
649             'userid'        => $author->id,
650             'forum'         => $forum->id,
651         )));
653         // And should have reset the discussion cache value.
654         $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $author->id);
655         $this->assertInternalType('array', $result);
656         $this->assertFalse(isset($result[$discussion->id]));
657     }
659     /**
660      * Test the effect of toggling the discussion subscription status when unsubscribed from the forum.
661      */
662     public function test_forum_discussion_toggle_forum_unsubscribed() {
663         global $DB;
665         $this->resetAfterTest(true);
667         // Create a course, with a forum.
668         $course = $this->getDataGenerator()->create_course();
670         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
671         $forum = $this->getDataGenerator()->create_module('forum', $options);
673         // Create two users enrolled in the course as students.
674         list($author) = $this->helper_create_users($course, 2);
676         // Check that the user is currently unsubscribed to the forum.
677         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
679         // Post a discussion to the forum.
680         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
682         // Check that the user is initially unsubscribed to that discussion.
683         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
685         // Then subscribe them to the discussion.
686         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
688         // An attempt to subscribe again should result in a falsey return to indicate that no change was made.
689         $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
691         // Check that the user is still unsubscribed from the forum.
692         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
694         // But subscribed to the discussion.
695         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
697         // There should be a record in the discussion subscription tracking table.
698         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
699             'userid'        => $author->id,
700             'discussion'    => $discussion->id,
701         )));
703         // Now unsubscribe the user again from the discussion.
704         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
706         // Check that the user is still unsubscribed from the forum.
707         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
709         // And is unsubscribed from the discussion again.
710         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
712         // There should be no record in the discussion subscription tracking table.
713         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
714             'userid'        => $author->id,
715             'discussion'    => $discussion->id,
716         )));
718         // And subscribe the user again to the discussion.
719         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
721         // Check that the user is still unsubscribed from the forum.
722         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
724         // And is subscribed to the discussion again.
725         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
727         // There should be a record in the discussion subscription tracking table.
728         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
729             'userid'        => $author->id,
730             'discussion'    => $discussion->id,
731         )));
733         // And unsubscribe again.
734         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
736         // Check that the user is still unsubscribed from the forum.
737         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
739         // But unsubscribed from the discussion.
740         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
742         // There should be no record in the discussion subscription tracking table.
743         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
744             'userid'        => $author->id,
745             'discussion'    => $discussion->id,
746         )));
747     }
749     /**
750      * Test that the correct users are returned when fetching subscribed users from a forum where users can choose to
751      * subscribe and unsubscribe.
752      */
753     public function test_fetch_subscribed_users_subscriptions() {
754         global $DB, $CFG;
756         $this->resetAfterTest(true);
758         // Create a course, with a forum. where users are initially subscribed.
759         $course = $this->getDataGenerator()->create_course();
760         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
761         $forum = $this->getDataGenerator()->create_module('forum', $options);
763         // Create some user enrolled in the course as a student.
764         $usercount = 5;
765         $users = $this->helper_create_users($course, $usercount);
767         // All users should be subscribed.
768         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
769         $this->assertEquals($usercount, count($subscribers));
771         // Subscribe the guest user too to the forum - they should never be returned by this function.
772         $this->getDataGenerator()->enrol_user($CFG->siteguest, $course->id);
773         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
774         $this->assertEquals($usercount, count($subscribers));
776         // Unsubscribe 2 users.
777         $unsubscribedcount = 2;
778         for ($i = 0; $i < $unsubscribedcount; $i++) {
779             \mod_forum\subscriptions::unsubscribe_user($users[$i]->id, $forum);
780         }
782         // The subscription count should now take into account those users who have been unsubscribed.
783         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
784         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
785     }
787     /**
788      * Test that the correct users are returned hwen fetching subscribed users from a forum where users are forcibly
789      * subscribed.
790      */
791     public function test_fetch_subscribed_users_forced() {
792         global $DB;
794         $this->resetAfterTest(true);
796         // Create a course, with a forum. where users are initially subscribed.
797         $course = $this->getDataGenerator()->create_course();
798         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
799         $forum = $this->getDataGenerator()->create_module('forum', $options);
801         // Create some user enrolled in the course as a student.
802         $usercount = 5;
803         $users = $this->helper_create_users($course, $usercount);
805         // All users should be subscribed.
806         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
807         $this->assertEquals($usercount, count($subscribers));
808     }
810     /**
811      * Test that unusual combinations of discussion subscriptions do not affect the subscribed user list.
812      */
813     public function test_fetch_subscribed_users_discussion_subscriptions() {
814         global $DB;
816         $this->resetAfterTest(true);
818         // Create a course, with a forum. where users are initially subscribed.
819         $course = $this->getDataGenerator()->create_course();
820         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
821         $forum = $this->getDataGenerator()->create_module('forum', $options);
823         // Create some user enrolled in the course as a student.
824         $usercount = 5;
825         $users = $this->helper_create_users($course, $usercount);
827         list($discussion, $post) = $this->helper_post_to_forum($forum, $users[0]);
829         // All users should be subscribed.
830         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
831         $this->assertEquals($usercount, count($subscribers));
832         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
833         $this->assertEquals($usercount, count($subscribers));
835         \mod_forum\subscriptions::unsubscribe_user_from_discussion($users[0]->id, $discussion);
837         // All users should be subscribed.
838         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
839         $this->assertEquals($usercount, count($subscribers));
841         // All users should be subscribed.
842         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
843         $this->assertEquals($usercount, count($subscribers));
845         // Manually insert an extra subscription for one of the users.
846         $record = new stdClass();
847         $record->userid = $users[2]->id;
848         $record->forum = $forum->id;
849         $record->discussion = $discussion->id;
850         $record->preference = time();
851         $DB->insert_record('forum_discussion_subs', $record);
853         // The discussion count should not have changed.
854         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
855         $this->assertEquals($usercount, count($subscribers));
856         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
857         $this->assertEquals($usercount, count($subscribers));
859         // Unsubscribe 2 users.
860         $unsubscribedcount = 2;
861         for ($i = 0; $i < $unsubscribedcount; $i++) {
862             \mod_forum\subscriptions::unsubscribe_user($users[$i]->id, $forum);
863         }
865         // The subscription count should now take into account those users who have been unsubscribed.
866         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
867         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
868         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
869         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
871         // Now subscribe one of those users back to the discussion.
872         $subscribeddiscussionusers = 1;
873         for ($i = 0; $i < $subscribeddiscussionusers; $i++) {
874             \mod_forum\subscriptions::subscribe_user_to_discussion($users[$i]->id, $discussion);
875         }
876         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
877         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
878         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
879         $this->assertEquals($usercount - $unsubscribedcount + $subscribeddiscussionusers, count($subscribers));
880     }
882     /**
883      * Test whether a user is force-subscribed to a forum.
884      */
885     public function test_force_subscribed_to_forum() {
886         global $DB;
888         $this->resetAfterTest(true);
890         // Create a course, with a forum.
891         $course = $this->getDataGenerator()->create_course();
893         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
894         $forum = $this->getDataGenerator()->create_module('forum', $options);
896         // Create a user enrolled in the course as a student.
897         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
898         $user = $this->getDataGenerator()->create_user();
899         $this->getDataGenerator()->enrol_user($user->id, $course->id, $roleids['student']);
901         // Check that the user is currently subscribed to the forum.
902         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
904         // Remove the allowforcesubscribe capability from the user.
905         $cm = get_coursemodule_from_instance('forum', $forum->id);
906         $context = \context_module::instance($cm->id);
907         assign_capability('mod/forum:allowforcesubscribe', CAP_PROHIBIT, $roleids['student'], $context);
908         $this->assertFalse(has_capability('mod/forum:allowforcesubscribe', $context, $user->id));
910         // Check that the user is no longer subscribed to the forum.
911         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
912     }
914     /**
915      * Test that the subscription cache can be pre-filled.
916      */
917     public function test_subscription_cache_prefill() {
918         global $DB;
920         $this->resetAfterTest(true);
922         // Create a course, with a forum.
923         $course = $this->getDataGenerator()->create_course();
925         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
926         $forum = $this->getDataGenerator()->create_module('forum', $options);
928         // Create some users.
929         $users = $this->helper_create_users($course, 20);
931         // Reset the subscription cache.
932         \mod_forum\subscriptions::reset_forum_cache();
934         // Filling the subscription cache should use a query.
935         $startcount = $DB->perf_get_reads();
936         $this->assertNull(\mod_forum\subscriptions::fill_subscription_cache($forum->id));
937         $postfillcount = $DB->perf_get_reads();
938         $this->assertNotEquals($postfillcount, $startcount);
940         // Now fetch some subscriptions from that forum - these should use
941         // the cache and not perform additional queries.
942         foreach ($users as $user) {
943             $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($forum->id, $user->id));
944         }
945         $finalcount = $DB->perf_get_reads();
946         $this->assertEquals(0, $finalcount - $postfillcount);
947     }
949     /**
950      * Test that the subscription cache can filled user-at-a-time.
951      */
952     public function test_subscription_cache_fill() {
953         global $DB;
955         $this->resetAfterTest(true);
957         // Create a course, with a forum.
958         $course = $this->getDataGenerator()->create_course();
960         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
961         $forum = $this->getDataGenerator()->create_module('forum', $options);
963         // Create some users.
964         $users = $this->helper_create_users($course, 20);
966         // Reset the subscription cache.
967         \mod_forum\subscriptions::reset_forum_cache();
969         // Filling the subscription cache should only use a single query.
970         $startcount = $DB->perf_get_reads();
972         // Fetch some subscriptions from that forum - these should not use the cache and will perform additional queries.
973         foreach ($users as $user) {
974             $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($forum->id, $user->id));
975         }
976         $finalcount = $DB->perf_get_reads();
977         $this->assertEquals(20, $finalcount - $startcount);
978     }
980     /**
981      * Test that the discussion subscription cache can filled course-at-a-time.
982      */
983     public function test_discussion_subscription_cache_fill_for_course() {
984         global $DB;
986         $this->resetAfterTest(true);
988         // Create a course, with a forum.
989         $course = $this->getDataGenerator()->create_course();
991         // Create the forums.
992         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
993         $disallowforum = $this->getDataGenerator()->create_module('forum', $options);
994         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
995         $chooseforum = $this->getDataGenerator()->create_module('forum', $options);
996         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
997         $initialforum = $this->getDataGenerator()->create_module('forum', $options);
999         // Create some users and keep a reference to the first user.
1000         $users = $this->helper_create_users($course, 20);
1001         $user = reset($users);
1003         // Reset the subscription caches.
1004         \mod_forum\subscriptions::reset_forum_cache();
1006         $startcount = $DB->perf_get_reads();
1007         $result = \mod_forum\subscriptions::fill_subscription_cache_for_course($course->id, $user->id);
1008         $this->assertNull($result);
1009         $postfillcount = $DB->perf_get_reads();
1010         $this->assertNotEquals($postfillcount, $startcount);
1011         $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($disallowforum->id, $user->id));
1012         $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($chooseforum->id, $user->id));
1013         $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($initialforum->id, $user->id));
1014         $finalcount = $DB->perf_get_reads();
1015         $this->assertEquals(0, $finalcount - $postfillcount);
1017         // Test for all users.
1018         foreach ($users as $user) {
1019             $result = \mod_forum\subscriptions::fill_subscription_cache_for_course($course->id, $user->id);
1020             $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($disallowforum->id, $user->id));
1021             $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($chooseforum->id, $user->id));
1022             $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($initialforum->id, $user->id));
1023         }
1024         $finalcount = $DB->perf_get_reads();
1025         $this->assertNotEquals($finalcount, $postfillcount);
1026     }
1028     /**
1029      * Test that the discussion subscription cache can be forcibly updated for a user.
1030      */
1031     public function test_discussion_subscription_cache_prefill() {
1032         global $DB;
1034         $this->resetAfterTest(true);
1036         // Create a course, with a forum.
1037         $course = $this->getDataGenerator()->create_course();
1039         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1040         $forum = $this->getDataGenerator()->create_module('forum', $options);
1042         // Create some users.
1043         $users = $this->helper_create_users($course, 20);
1045         // Post some discussions to the forum.
1046         $discussions = array();
1047         $author = $users[0];
1048         for ($i = 0; $i < 20; $i++) {
1049             list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1050             $discussions[] = $discussion;
1051         }
1053         // Unsubscribe half the users from the half the discussions.
1054         $forumcount = 0;
1055         $usercount = 0;
1056         foreach ($discussions as $data) {
1057             if ($forumcount % 2) {
1058                 continue;
1059             }
1060             foreach ($users as $user) {
1061                 if ($usercount % 2) {
1062                     continue;
1063                 }
1064                 \mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion);
1065                 $usercount++;
1066             }
1067             $forumcount++;
1068         }
1070         // Reset the subscription caches.
1071         \mod_forum\subscriptions::reset_forum_cache();
1072         \mod_forum\subscriptions::reset_discussion_cache();
1074         // Filling the discussion subscription cache should only use a single query.
1075         $startcount = $DB->perf_get_reads();
1076         $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id));
1077         $postfillcount = $DB->perf_get_reads();
1078         $this->assertNotEquals($postfillcount, $startcount);
1080         // Now fetch some subscriptions from that forum - these should use
1081         // the cache and not perform additional queries.
1082         foreach ($users as $user) {
1083             $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $user->id);
1084             $this->assertInternalType('array', $result);
1085         }
1086         $finalcount = $DB->perf_get_reads();
1087         $this->assertEquals(0, $finalcount - $postfillcount);
1088     }
1090     /**
1091      * Test that the discussion subscription cache can filled user-at-a-time.
1092      */
1093     public function test_discussion_subscription_cache_fill() {
1094         global $DB;
1096         $this->resetAfterTest(true);
1098         // Create a course, with a forum.
1099         $course = $this->getDataGenerator()->create_course();
1101         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1102         $forum = $this->getDataGenerator()->create_module('forum', $options);
1104         // Create some users.
1105         $users = $this->helper_create_users($course, 20);
1107         // Post some discussions to the forum.
1108         $discussions = array();
1109         $author = $users[0];
1110         for ($i = 0; $i < 20; $i++) {
1111             list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1112             $discussions[] = $discussion;
1113         }
1115         // Unsubscribe half the users from the half the discussions.
1116         $forumcount = 0;
1117         $usercount = 0;
1118         foreach ($discussions as $data) {
1119             if ($forumcount % 2) {
1120                 continue;
1121             }
1122             foreach ($users as $user) {
1123                 if ($usercount % 2) {
1124                     continue;
1125                 }
1126                 \mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion);
1127                 $usercount++;
1128             }
1129             $forumcount++;
1130         }
1132         // Reset the subscription caches.
1133         \mod_forum\subscriptions::reset_forum_cache();
1134         \mod_forum\subscriptions::reset_discussion_cache();
1136         $startcount = $DB->perf_get_reads();
1138         // Now fetch some subscriptions from that forum - these should use
1139         // the cache and not perform additional queries.
1140         foreach ($users as $user) {
1141             $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $user->id);
1142             $this->assertInternalType('array', $result);
1143         }
1144         $finalcount = $DB->perf_get_reads();
1145         $this->assertNotEquals($finalcount, $startcount);
1146     }
1148     /**
1149      * Test that after toggling the forum subscription as another user,
1150      * the discussion subscription functionality works as expected.
1151      */
1152     public function test_forum_subscribe_toggle_as_other_repeat_subscriptions() {
1153         global $DB;
1155         $this->resetAfterTest(true);
1157         // Create a course, with a forum.
1158         $course = $this->getDataGenerator()->create_course();
1160         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
1161         $forum = $this->getDataGenerator()->create_module('forum', $options);
1163         // Create a user enrolled in the course as a student.
1164         list($user) = $this->helper_create_users($course, 1);
1166         // Post a discussion to the forum.
1167         list($discussion, $post) = $this->helper_post_to_forum($forum, $user);
1169         // Confirm that the user is currently not subscribed to the forum.
1170         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1172         // Confirm that the user is unsubscribed from the discussion too.
1173         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum, $discussion->id));
1175         // Confirm that we have no records in either of the subscription tables.
1176         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1177             'userid'        => $user->id,
1178             'forum'         => $forum->id,
1179         )));
1180         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
1181             'userid'        => $user->id,
1182             'discussion'    => $discussion->id,
1183         )));
1185         // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
1186         // subscriptions table.
1187         \mod_forum\subscriptions::subscribe_user($user->id, $forum);
1188         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
1189             'userid'        => $user->id,
1190             'forum'         => $forum->id,
1191         )));
1192         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
1193             'userid'        => $user->id,
1194             'discussion'    => $discussion->id,
1195         )));
1197         // Now unsubscribe from the discussion. This should return true.
1198         $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1200         // Attempting to unsubscribe again should return false because no change was made.
1201         $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1203         // Subscribing to the discussion again should return truthfully as the subscription preference was removed.
1204         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1206         // Attempting to subscribe again should return false because no change was made.
1207         $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1209         // Now unsubscribe from the discussion. This should return true once more.
1210         $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1212         // And unsubscribing from the forum but not as a request from the user should maintain their preference.
1213         \mod_forum\subscriptions::unsubscribe_user($user->id, $forum);
1215         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1216             'userid'        => $user->id,
1217             'forum'         => $forum->id,
1218         )));
1219         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
1220             'userid'        => $user->id,
1221             'discussion'    => $discussion->id,
1222         )));
1224         // Subscribing to the discussion should return truthfully because a change was made.
1225         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1226         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1227             'userid'        => $user->id,
1228             'forum'         => $forum->id,
1229         )));
1230         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
1231             'userid'        => $user->id,
1232             'discussion'    => $discussion->id,
1233         )));
1234     }
1236     /**
1237      * Test that providing a context_module instance to is_subscribed does not result in additional lookups to retrieve
1238      * the context_module.
1239      */
1240     public function test_is_subscribed_cm() {
1241         global $DB;
1243         $this->resetAfterTest(true);
1245         // Create a course, with a forum.
1246         $course = $this->getDataGenerator()->create_course();
1248         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
1249         $forum = $this->getDataGenerator()->create_module('forum', $options);
1251         // Create a user enrolled in the course as a student.
1252         list($user) = $this->helper_create_users($course, 1);
1254         // Retrieve the $cm now.
1255         $cm = get_fast_modinfo($forum->course)->instances['forum'][$forum->id];
1257         // Reset get_fast_modinfo.
1258         get_fast_modinfo(0, 0, true);
1260         // Call is_subscribed without passing the $cmid - this should result in a lookup and filling of some of the
1261         // caches. This provides us with consistent data to start from.
1262         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1263         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1265         // Make a note of the number of DB calls.
1266         $basecount = $DB->perf_get_reads();
1268         // Call is_subscribed - it should give return the correct result (False), and result in no additional queries.
1269         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum, null, $cm));
1271         // The capability check does require some queries, so we don't test it directly.
1272         // We don't assert here because this is dependant upon linked code which could change at any time.
1273         $suppliedcmcount = $DB->perf_get_reads() - $basecount;
1275         // Call is_subscribed without passing the $cmid now - this should result in a lookup.
1276         get_fast_modinfo(0, 0, true);
1277         $basecount = $DB->perf_get_reads();
1278         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1279         $calculatedcmcount = $DB->perf_get_reads() - $basecount;
1281         // There should be more queries than when we performed the same check a moment ago.
1282         $this->assertGreaterThan($suppliedcmcount, $calculatedcmcount);
1283     }
1285     public function is_subscribable_forums() {
1286         return [
1287             [
1288                 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE,
1289             ],
1290             [
1291                 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE,
1292             ],
1293             [
1294                 'forcesubscribe' => FORUM_INITIALSUBSCRIBE,
1295             ],
1296             [
1297                 'forcesubscribe' => FORUM_FORCESUBSCRIBE,
1298             ],
1299         ];
1300     }
1302     public function is_subscribable_provider() {
1303         $data = [];
1304         foreach ($this->is_subscribable_forums() as $forum) {
1305             $data[] = [$forum];
1306         }
1308         return $data;
1309     }
1311     /**
1312      * @dataProvider is_subscribable_provider
1313      */
1314     public function test_is_subscribable_logged_out($options) {
1315         $this->resetAfterTest(true);
1317         // Create a course, with a forum.
1318         $course = $this->getDataGenerator()->create_course();
1319         $options['course'] = $course->id;
1320         $forum = $this->getDataGenerator()->create_module('forum', $options);
1322         $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
1323     }
1325     /**
1326      * @dataProvider is_subscribable_provider
1327      */
1328     public function test_is_subscribable_is_guest($options) {
1329         global $DB;
1330         $this->resetAfterTest(true);
1332         $guest = $DB->get_record('user', array('username'=>'guest'));
1333         $this->setUser($guest);
1335         // Create a course, with a forum.
1336         $course = $this->getDataGenerator()->create_course();
1337         $options['course'] = $course->id;
1338         $forum = $this->getDataGenerator()->create_module('forum', $options);
1340         $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
1341     }
1343     public function is_subscribable_loggedin_provider() {
1344         return [
1345             [
1346                 ['forcesubscribe' => FORUM_DISALLOWSUBSCRIBE],
1347                 false,
1348             ],
1349             [
1350                 ['forcesubscribe' => FORUM_CHOOSESUBSCRIBE],
1351                 true,
1352             ],
1353             [
1354                 ['forcesubscribe' => FORUM_INITIALSUBSCRIBE],
1355                 true,
1356             ],
1357             [
1358                 ['forcesubscribe' => FORUM_FORCESUBSCRIBE],
1359                 false,
1360             ],
1361         ];
1362     }
1364     /**
1365      * @dataProvider is_subscribable_loggedin_provider
1366      */
1367     public function test_is_subscribable_loggedin($options, $expect) {
1368         $this->resetAfterTest(true);
1370         // Create a course, with a forum.
1371         $course = $this->getDataGenerator()->create_course();
1372         $options['course'] = $course->id;
1373         $forum = $this->getDataGenerator()->create_module('forum', $options);
1375         $user = $this->getDataGenerator()->create_user();
1376         $this->getDataGenerator()->enrol_user($user->id, $course->id);
1377         $this->setUser($user);
1379         $this->assertEquals($expect, \mod_forum\subscriptions::is_subscribable($forum));
1380     }
1382     public function test_get_user_default_subscription() {
1383         global $DB;
1384         $this->resetAfterTest(true);
1386         // Create a course, with a forum.
1387         $course = $this->getDataGenerator()->create_course();
1388         $context = \context_course::instance($course->id);
1389         $options['course'] = $course->id;
1390         $forum = $this->getDataGenerator()->create_module('forum', $options);
1391         $cm = get_coursemodule_from_instance("forum", $forum->id, $course->id);
1393         // Create a user enrolled in the course as a student.
1394         list($author, $student) = $this->helper_create_users($course, 2, 'student');
1395         // Post a discussion to the forum.
1396         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1398         // A guest user.
1399         $this->setUser(0);
1400         $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1401         $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1403         // A user enrolled in the course.
1404         $this->setUser($author->id);
1405         $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1406         $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1408         // Subscribption disabled.
1409         $this->setUser($student->id);
1410         \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_DISALLOWSUBSCRIBE);
1411         $forum = $DB->get_record('forum', array('id' => $forum->id));
1412         $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1413         $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1415         \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_FORCESUBSCRIBE);
1416         $forum = $DB->get_record('forum', array('id' => $forum->id));
1417         $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1418         $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1420         // Admin user.
1421         $this->setAdminUser();
1422         $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1423         $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1424     }