Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace mod_forum;
18
 
19
use mod_forum_tests_generator_trait;
20
 
21
defined('MOODLE_INTERNAL') || die();
22
 
23
global $CFG;
24
require_once(__DIR__ . '/generator_trait.php');
25
require_once("{$CFG->dirroot}/mod/forum/lib.php");
26
 
27
/**
28
 * The module forums tests
29
 *
30
 * @package    mod_forum
31
 * @copyright  2013 Frédéric Massart
32
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33
 */
1441 ariadna 34
final class subscriptions_test extends \advanced_testcase {
1 efrain 35
    // Include the mod_forum test helpers.
36
    // This includes functions to create forums, users, discussions, and posts.
37
    use mod_forum_tests_generator_trait;
38
 
39
    /**
40
     * Test setUp.
41
     */
42
    public function setUp(): void {
43
        global $DB;
1441 ariadna 44
        parent::setUp();
1 efrain 45
 
46
        // We must clear the subscription caches. This has to be done both before each test, and after in case of other
47
        // tests using these functions.
48
        \mod_forum\subscriptions::reset_forum_cache();
49
        \mod_forum\subscriptions::reset_discussion_cache();
50
    }
51
 
52
    /**
53
     * Test tearDown.
54
     */
55
    public function tearDown(): void {
56
        // We must clear the subscription caches. This has to be done both before each test, and after in case of other
57
        // tests using these functions.
58
        \mod_forum\subscriptions::reset_forum_cache();
59
        \mod_forum\subscriptions::reset_discussion_cache();
1441 ariadna 60
        parent::tearDown();
1 efrain 61
    }
62
 
63
    /**
64
     * Test subscription modes modifications.
65
     *
66
     * @covers \mod_forum\event\subscription_mode_updated
67
     */
11 efrain 68
    public function test_subscription_modes(): void {
1 efrain 69
        global $DB;
70
 
71
        $this->resetAfterTest(true);
72
 
73
        // Create a course, with a forum.
74
        $course = $this->getDataGenerator()->create_course();
75
 
76
        $options = array('course' => $course->id);
77
        $forum = $this->getDataGenerator()->create_module('forum', $options);
78
        $context = \context_module::instance($forum->cmid);
79
 
80
        // Create a user enrolled in the course as a student.
81
        list($user) = $this->helper_create_users($course, 1);
82
 
83
        // Must be logged in as the current user.
84
        $this->setUser($user);
85
 
86
        $sink = $this->redirectEvents(); // Capturing the event.
87
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_FORCESUBSCRIBE);
88
        $forum = $DB->get_record('forum', array('id' => $forum->id));
89
        $this->assertEquals(FORUM_FORCESUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
90
        $this->assertTrue(\mod_forum\subscriptions::is_forcesubscribed($forum));
91
        $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
92
        $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
93
 
94
        $events = $sink->get_events();
95
        $this->assertCount(1, $events);
96
        $event = reset($events);
97
        $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event);
98
        $this->assertEquals($context, $event->get_context());
99
        $this->assertEventContextNotUsed($event);
100
        $this->assertNotEmpty($event->get_name());
101
 
102
        $sink = $this->redirectEvents(); // Capturing the event.
103
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_DISALLOWSUBSCRIBE);
104
        $forum = $DB->get_record('forum', array('id' => $forum->id));
105
        $this->assertEquals(FORUM_DISALLOWSUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
106
        $this->assertTrue(\mod_forum\subscriptions::subscription_disabled($forum));
107
        $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
108
        $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
109
 
110
        $events = $sink->get_events();
111
        $this->assertCount(1, $events);
112
        $event = reset($events);
113
        $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event);
114
        $this->assertEquals($context, $event->get_context());
115
        $this->assertEventContextNotUsed($event);
116
        $this->assertNotEmpty($event->get_name());
117
 
118
        $sink = $this->redirectEvents(); // Capturing the event.
119
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_INITIALSUBSCRIBE);
120
        $forum = $DB->get_record('forum', array('id' => $forum->id));
121
        $this->assertEquals(FORUM_INITIALSUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
122
        $this->assertTrue(\mod_forum\subscriptions::is_subscribable($forum));
123
        $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
124
        $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
125
 
126
        $events = $sink->get_events();
127
        $this->assertCount(1, $events);
128
        $event = reset($events);
129
        $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event);
130
        $this->assertEquals($context, $event->get_context());
131
        $this->assertEventContextNotUsed($event);
132
        $this->assertNotEmpty($event->get_name());
133
 
134
        $sink = $this->redirectEvents(); // Capturing the event.
135
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_CHOOSESUBSCRIBE);
136
        $forum = $DB->get_record('forum', array('id' => $forum->id));
137
        $this->assertEquals(FORUM_CHOOSESUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
138
        $this->assertTrue(\mod_forum\subscriptions::is_subscribable($forum));
139
        $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
140
        $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
141
 
142
        $events = $sink->get_events();
143
        $this->assertCount(1, $events);
144
        $event = reset($events);
145
        $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event);
146
        $this->assertEquals($context, $event->get_context());
147
        $this->assertEventContextNotUsed($event);
148
        $this->assertNotEmpty($event->get_name());
149
    }
150
 
151
    /**
152
     * Test fetching unsubscribable forums.
153
     */
11 efrain 154
    public function test_unsubscribable_forums(): void {
1 efrain 155
        global $DB;
156
 
157
        $this->resetAfterTest(true);
158
 
159
        // Create a course, with a forum.
160
        $course = $this->getDataGenerator()->create_course();
161
 
162
        // Create a user enrolled in the course as a student.
163
        list($user) = $this->helper_create_users($course, 1);
164
 
165
        // Must be logged in as the current user.
166
        $this->setUser($user);
167
 
168
        // Without any subscriptions, there should be nothing returned.
169
        $result = \mod_forum\subscriptions::get_unsubscribable_forums();
170
        $this->assertEquals(0, count($result));
171
 
172
        // Create the forums.
173
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
174
        $forceforum = $this->getDataGenerator()->create_module('forum', $options);
175
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
176
        $disallowforum = $this->getDataGenerator()->create_module('forum', $options);
177
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
178
        $chooseforum = $this->getDataGenerator()->create_module('forum', $options);
179
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
180
        $initialforum = $this->getDataGenerator()->create_module('forum', $options);
181
 
182
        // At present the user is only subscribed to the initial forum.
183
        $result = \mod_forum\subscriptions::get_unsubscribable_forums();
184
        $this->assertEquals(1, count($result));
185
 
186
        // Ensure that the user is enrolled in all of the forums except force subscribed.
187
        \mod_forum\subscriptions::subscribe_user($user->id, $disallowforum);
188
        \mod_forum\subscriptions::subscribe_user($user->id, $chooseforum);
189
 
190
        $result = \mod_forum\subscriptions::get_unsubscribable_forums();
191
        $this->assertEquals(3, count($result));
192
 
193
        // Hide the forums.
194
        set_coursemodule_visible($forceforum->cmid, 0);
195
        set_coursemodule_visible($disallowforum->cmid, 0);
196
        set_coursemodule_visible($chooseforum->cmid, 0);
197
        set_coursemodule_visible($initialforum->cmid, 0);
198
        $result = \mod_forum\subscriptions::get_unsubscribable_forums();
199
        $this->assertEquals(0, count($result));
200
 
201
        // Add the moodle/course:viewhiddenactivities capability to the student user.
202
        $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
203
        $context = \context_course::instance($course->id);
204
        assign_capability('moodle/course:viewhiddenactivities', CAP_ALLOW, $roleids['student'], $context);
205
 
206
        // All of the unsubscribable forums should now be listed.
207
        $result = \mod_forum\subscriptions::get_unsubscribable_forums();
208
        $this->assertEquals(3, count($result));
209
    }
210
 
211
    /**
212
     * Test that toggling the forum-level subscription for a different user does not affect their discussion-level
213
     * subscriptions.
214
     */
11 efrain 215
    public function test_forum_subscribe_toggle_as_other(): void {
1 efrain 216
        global $DB;
217
 
218
        $this->resetAfterTest(true);
219
 
220
        // Create a course, with a forum.
221
        $course = $this->getDataGenerator()->create_course();
222
 
223
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
224
        $forum = $this->getDataGenerator()->create_module('forum', $options);
225
 
226
        // Create a user enrolled in the course as a student.
227
        list($author) = $this->helper_create_users($course, 1);
228
 
229
        // Post a discussion to the forum.
230
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
231
 
232
        // Check that the user is currently not subscribed to the forum.
233
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
234
 
235
        // Check that the user is unsubscribed from the discussion too.
236
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
237
 
238
        // Check that we have no records in either of the subscription tables.
239
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
240
            'userid'        => $author->id,
241
            'forum'         => $forum->id,
242
        )));
243
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
244
            'userid'        => $author->id,
245
            'discussion'    => $discussion->id,
246
        )));
247
 
248
        // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
249
        // subscriptions table.
250
        \mod_forum\subscriptions::subscribe_user($author->id, $forum);
251
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
252
            'userid'        => $author->id,
253
            'forum'         => $forum->id,
254
        )));
255
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
256
            'userid'        => $author->id,
257
            'discussion'    => $discussion->id,
258
        )));
259
 
260
        // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
261
        // discussion subscriptions table.
262
        \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
263
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
264
            'userid'        => $author->id,
265
            'forum'         => $forum->id,
266
        )));
267
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
268
            'userid'        => $author->id,
269
            'discussion'    => $discussion->id,
270
        )));
271
 
272
        // Enroling the user in the discussion should add one record to the forum discussion table without modifying the
273
        // form subscriptions.
274
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
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
        )));
283
 
284
        // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
285
        // discussion subscriptions table.
286
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
287
        $this->assertEquals(0, $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
        )));
295
 
296
        // Re-subscribe to the discussion so that we can check the effect of forum-level subscriptions.
297
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
298
        $this->assertEquals(0, $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
        )));
306
 
307
        // Subscribing to the forum should have no effect on the forum discussion subscriptions table if the user did
308
        // not request the change themself.
309
        \mod_forum\subscriptions::subscribe_user($author->id, $forum);
310
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
311
            'userid'        => $author->id,
312
            'forum'         => $forum->id,
313
        )));
314
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
315
            'userid'        => $author->id,
316
            'discussion'    => $discussion->id,
317
        )));
318
 
319
        // Unsubscribing from the forum should have no effect on the forum discussion subscriptions table if the user
320
        // did not request the change themself.
321
        \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
322
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
323
            'userid'        => $author->id,
324
            'forum'         => $forum->id,
325
        )));
326
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
327
            'userid'        => $author->id,
328
            'discussion'    => $discussion->id,
329
        )));
330
 
331
        // Subscribing to the forum should remove the per-discussion subscription preference if the user requested the
332
        // change themself.
333
        \mod_forum\subscriptions::subscribe_user($author->id, $forum, null, true);
334
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
335
            'userid'        => $author->id,
336
            'forum'         => $forum->id,
337
        )));
338
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
339
            'userid'        => $author->id,
340
            'discussion'    => $discussion->id,
341
        )));
342
 
343
        // Now unsubscribe from the current discussion whilst being subscribed to the forum as a whole.
344
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
345
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
346
            'userid'        => $author->id,
347
            'forum'         => $forum->id,
348
        )));
349
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
350
            'userid'        => $author->id,
351
            'discussion'    => $discussion->id,
352
        )));
353
 
354
        // Unsubscribing from the forum should remove the per-discussion subscription preference if the user requested the
355
        // change themself.
356
        \mod_forum\subscriptions::unsubscribe_user($author->id, $forum, null, true);
357
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
358
            'userid'        => $author->id,
359
            'forum'         => $forum->id,
360
        )));
361
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
362
            'userid'        => $author->id,
363
            'discussion'    => $discussion->id,
364
        )));
365
 
366
        // Subscribe to the discussion.
367
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
368
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
369
            'userid'        => $author->id,
370
            'forum'         => $forum->id,
371
        )));
372
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
373
            'userid'        => $author->id,
374
            'discussion'    => $discussion->id,
375
        )));
376
 
377
        // Subscribe to the forum without removing the discussion preferences.
378
        \mod_forum\subscriptions::subscribe_user($author->id, $forum);
379
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
380
            'userid'        => $author->id,
381
            'forum'         => $forum->id,
382
        )));
383
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
384
            'userid'        => $author->id,
385
            'discussion'    => $discussion->id,
386
        )));
387
 
388
        // Unsubscribing from the discussion should result in a change.
389
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
390
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
391
            'userid'        => $author->id,
392
            'forum'         => $forum->id,
393
        )));
394
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
395
            'userid'        => $author->id,
396
            'discussion'    => $discussion->id,
397
        )));
398
 
399
    }
400
 
401
    /**
402
     * Test that a user unsubscribed from a forum is not subscribed to it's discussions by default.
403
     */
11 efrain 404
    public function test_forum_discussion_subscription_forum_unsubscribed(): void {
1 efrain 405
        $this->resetAfterTest(true);
406
 
407
        // Create a course, with a forum.
408
        $course = $this->getDataGenerator()->create_course();
409
 
410
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
411
        $forum = $this->getDataGenerator()->create_module('forum', $options);
412
 
413
        // Create users enrolled in the course as students.
414
        list($author) = $this->helper_create_users($course, 1);
415
 
416
        // Check that the user is currently not subscribed to the forum.
417
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
418
 
419
        // Post a discussion to the forum.
420
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
421
 
422
        // Check that the user is unsubscribed from the discussion too.
423
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
424
    }
425
 
426
    /**
427
     * Test that the act of subscribing to a forum subscribes the user to it's discussions by default.
428
     */
11 efrain 429
    public function test_forum_discussion_subscription_forum_subscribed(): void {
1 efrain 430
        $this->resetAfterTest(true);
431
 
432
        // Create a course, with a forum.
433
        $course = $this->getDataGenerator()->create_course();
434
 
435
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
436
        $forum = $this->getDataGenerator()->create_module('forum', $options);
437
 
438
        // Create users enrolled in the course as students.
439
        list($author) = $this->helper_create_users($course, 1);
440
 
441
        // Enrol the user in the forum.
442
        // If a subscription was added, we get the record ID.
443
        $this->assertIsInt(\mod_forum\subscriptions::subscribe_user($author->id, $forum));
444
 
445
        // If we already have a subscription when subscribing the user, we get a boolean (true).
446
        $this->assertTrue(\mod_forum\subscriptions::subscribe_user($author->id, $forum));
447
 
448
        // Check that the user is currently subscribed to the forum.
449
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
450
 
451
        // Post a discussion to the forum.
452
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
453
 
454
        // Check that the user is subscribed to the discussion too.
455
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
456
    }
457
 
458
    /**
459
     * Test that a user unsubscribed from a forum can be subscribed to a discussion.
460
     */
11 efrain 461
    public function test_forum_discussion_subscription_forum_unsubscribed_discussion_subscribed(): void {
1 efrain 462
        $this->resetAfterTest(true);
463
 
464
        // Create a course, with a forum.
465
        $course = $this->getDataGenerator()->create_course();
466
 
467
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
468
        $forum = $this->getDataGenerator()->create_module('forum', $options);
469
 
470
        // Create a user enrolled in the course as a student.
471
        list($author) = $this->helper_create_users($course, 1);
472
 
473
        // Check that the user is currently not subscribed to the forum.
474
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
475
 
476
        // Post a discussion to the forum.
477
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
478
 
479
        // Attempting to unsubscribe from the discussion should not make a change.
480
        $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion));
481
 
482
        // Then subscribe them to the discussion.
483
        $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
484
 
485
        // Check that the user is still unsubscribed from the forum.
486
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
487
 
488
        // But subscribed to the discussion.
489
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
490
    }
491
 
492
    /**
493
     * Test that a user subscribed to a forum can be unsubscribed from a discussion.
494
     */
11 efrain 495
    public function test_forum_discussion_subscription_forum_subscribed_discussion_unsubscribed(): void {
1 efrain 496
        $this->resetAfterTest(true);
497
 
498
        // Create a course, with a forum.
499
        $course = $this->getDataGenerator()->create_course();
500
 
501
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
502
        $forum = $this->getDataGenerator()->create_module('forum', $options);
503
 
504
        // Create two users enrolled in the course as students.
505
        list($author) = $this->helper_create_users($course, 2);
506
 
507
        // Enrol the student in the forum.
508
        \mod_forum\subscriptions::subscribe_user($author->id, $forum);
509
 
510
        // Check that the user is currently subscribed to the forum.
511
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
512
 
513
        // Post a discussion to the forum.
514
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
515
 
516
        // Then unsubscribe them from the discussion.
517
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
518
 
519
        // Check that the user is still subscribed to the forum.
520
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
521
 
522
        // But unsubscribed from the discussion.
523
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
524
    }
525
 
526
    /**
527
     * Test the effect of toggling the discussion subscription status when subscribed to the forum.
528
     */
11 efrain 529
    public function test_forum_discussion_toggle_forum_subscribed(): void {
1 efrain 530
        global $DB;
531
 
532
        $this->resetAfterTest(true);
533
 
534
        // Create a course, with a forum.
535
        $course = $this->getDataGenerator()->create_course();
536
 
537
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
538
        $forum = $this->getDataGenerator()->create_module('forum', $options);
539
 
540
        // Create two users enrolled in the course as students.
541
        list($author) = $this->helper_create_users($course, 2);
542
 
543
        // Enrol the student in the forum.
544
        \mod_forum\subscriptions::subscribe_user($author->id, $forum);
545
 
546
        // Check that the user is currently subscribed to the forum.
547
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
548
 
549
        // Post a discussion to the forum.
550
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
551
 
552
        // Check that the user is initially subscribed to that discussion.
553
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
554
 
555
        // An attempt to subscribe again should result in a falsey return to indicate that no change was made.
556
        $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
557
 
558
        // And there should be no discussion subscriptions (and one forum subscription).
559
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
560
            'userid'        => $author->id,
561
            'discussion'    => $discussion->id,
562
        )));
563
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
564
            'userid'        => $author->id,
565
            'forum'         => $forum->id,
566
        )));
567
 
568
        // Then unsubscribe them from the discussion.
569
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
570
 
571
        // Check that the user is still subscribed to the forum.
572
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
573
 
574
        // An attempt to unsubscribe again should result in a falsey return to indicate that no change was made.
575
        $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion));
576
 
577
        // And there should be a discussion subscriptions (and one forum subscription).
578
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
579
            'userid'        => $author->id,
580
            'discussion'    => $discussion->id,
581
        )));
582
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
583
            'userid'        => $author->id,
584
            'forum'         => $forum->id,
585
        )));
586
 
587
        // But unsubscribed from the discussion.
588
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
589
 
590
        // There should be a record in the discussion subscription tracking table.
591
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
592
            'userid'        => $author->id,
593
            'discussion'    => $discussion->id,
594
        )));
595
 
596
        // And one in the forum subscription tracking table.
597
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
598
            'userid'        => $author->id,
599
            'forum'         => $forum->id,
600
        )));
601
 
602
        // Now subscribe the user again to the discussion.
603
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
604
 
605
        // Check that the user is still subscribed to the forum.
606
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
607
 
608
        // And is subscribed to the discussion again.
609
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
610
 
611
        // There should be no record in the discussion subscription tracking table.
612
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
613
            'userid'        => $author->id,
614
            'discussion'    => $discussion->id,
615
        )));
616
 
617
        // And one in the forum subscription tracking table.
618
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
619
            'userid'        => $author->id,
620
            'forum'         => $forum->id,
621
        )));
622
 
623
        // And unsubscribe again.
624
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
625
 
626
        // Check that the user is still subscribed to the forum.
627
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
628
 
629
        // But unsubscribed from the discussion.
630
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
631
 
632
        // There should be a record in the discussion subscription tracking table.
633
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
634
            'userid'        => $author->id,
635
            'discussion'    => $discussion->id,
636
        )));
637
 
638
        // And one in the forum subscription tracking table.
639
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
640
            'userid'        => $author->id,
641
            'forum'         => $forum->id,
642
        )));
643
 
644
        // And subscribe the user again to the discussion.
645
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
646
 
647
        // Check that the user is still subscribed to the forum.
648
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
649
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
650
 
651
        // And is subscribed to the discussion again.
652
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
653
 
654
        // There should be no record in the discussion subscription tracking table.
655
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
656
            'userid'        => $author->id,
657
            'discussion'    => $discussion->id,
658
        )));
659
 
660
        // And one in the forum subscription tracking table.
661
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
662
            'userid'        => $author->id,
663
            'forum'         => $forum->id,
664
        )));
665
 
666
        // And unsubscribe again.
667
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
668
 
669
        // Check that the user is still subscribed to the forum.
670
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
671
 
672
        // But unsubscribed from the discussion.
673
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
674
 
675
        // There should be a record in the discussion subscription tracking table.
676
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
677
            'userid'        => $author->id,
678
            'discussion'    => $discussion->id,
679
        )));
680
 
681
        // And one in the forum subscription tracking table.
682
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
683
            'userid'        => $author->id,
684
            'forum'         => $forum->id,
685
        )));
686
 
687
        // Now unsubscribe the user from the forum.
688
        $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user($author->id, $forum, null, true));
689
 
690
        // This removes both the forum_subscriptions, and the forum_discussion_subs records.
691
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
692
            'userid'        => $author->id,
693
            'discussion'    => $discussion->id,
694
        )));
695
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
696
            'userid'        => $author->id,
697
            'forum'         => $forum->id,
698
        )));
699
 
700
        // And should have reset the discussion cache value.
701
        $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $author->id);
702
        $this->assertIsArray($result);
703
        $this->assertFalse(isset($result[$discussion->id]));
704
    }
705
 
706
    /**
707
     * Test the effect of toggling the discussion subscription status when unsubscribed from the forum.
708
     */
11 efrain 709
    public function test_forum_discussion_toggle_forum_unsubscribed(): void {
1 efrain 710
        global $DB;
711
 
712
        $this->resetAfterTest(true);
713
 
714
        // Create a course, with a forum.
715
        $course = $this->getDataGenerator()->create_course();
716
 
717
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
718
        $forum = $this->getDataGenerator()->create_module('forum', $options);
719
 
720
        // Create two users enrolled in the course as students.
721
        list($author) = $this->helper_create_users($course, 2);
722
 
723
        // Check that the user is currently unsubscribed to the forum.
724
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
725
 
726
        // Post a discussion to the forum.
727
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
728
 
729
        // Check that the user is initially unsubscribed to that discussion.
730
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
731
 
732
        // Then subscribe them to the discussion.
733
        $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
734
 
735
        // An attempt to subscribe again should result in a falsey return to indicate that no change was made.
736
        $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
737
 
738
        // Check that the user is still unsubscribed from the forum.
739
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
740
 
741
        // But subscribed to the discussion.
742
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
743
 
744
        // There should be a record in the discussion subscription tracking table.
745
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
746
            'userid'        => $author->id,
747
            'discussion'    => $discussion->id,
748
        )));
749
 
750
        // Now unsubscribe the user again from the discussion.
751
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
752
 
753
        // Check that the user is still unsubscribed from the forum.
754
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
755
 
756
        // And is unsubscribed from the discussion again.
757
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
758
 
759
        // There should be no record in the discussion subscription tracking table.
760
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
761
            'userid'        => $author->id,
762
            'discussion'    => $discussion->id,
763
        )));
764
 
765
        // And subscribe the user again to the discussion.
766
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
767
 
768
        // Check that the user is still unsubscribed from the forum.
769
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
770
 
771
        // And is subscribed to the discussion again.
772
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
773
 
774
        // There should be a record in the discussion subscription tracking table.
775
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
776
            'userid'        => $author->id,
777
            'discussion'    => $discussion->id,
778
        )));
779
 
780
        // And unsubscribe again.
781
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
782
 
783
        // Check that the user is still unsubscribed from the forum.
784
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
785
 
786
        // But unsubscribed from the discussion.
787
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
788
 
789
        // There should be no record in the discussion subscription tracking table.
790
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
791
            'userid'        => $author->id,
792
            'discussion'    => $discussion->id,
793
        )));
794
    }
795
 
796
    /**
797
     * Test that the correct users are returned when fetching subscribed users from a forum where users can choose to
798
     * subscribe and unsubscribe.
799
     */
11 efrain 800
    public function test_fetch_subscribed_users_subscriptions(): void {
1 efrain 801
        global $DB, $CFG;
802
 
803
        $this->resetAfterTest(true);
804
 
805
        // Create a course, with a forum. where users are initially subscribed.
806
        $course = $this->getDataGenerator()->create_course();
807
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
808
        $forum = $this->getDataGenerator()->create_module('forum', $options);
809
 
810
        // Create some user enrolled in the course as a student.
811
        $usercount = 5;
812
        $users = $this->helper_create_users($course, $usercount);
813
 
814
        // All users should be subscribed.
815
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
816
        $this->assertEquals($usercount, count($subscribers));
817
 
818
        // Subscribe the guest user too to the forum - they should never be returned by this function.
819
        $this->getDataGenerator()->enrol_user($CFG->siteguest, $course->id);
820
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
821
        $this->assertEquals($usercount, count($subscribers));
822
 
823
        // Unsubscribe 2 users.
824
        $unsubscribedcount = 2;
825
        for ($i = 0; $i < $unsubscribedcount; $i++) {
826
            \mod_forum\subscriptions::unsubscribe_user($users[$i]->id, $forum);
827
        }
828
 
829
        // The subscription count should now take into account those users who have been unsubscribed.
830
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
831
        $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
832
    }
833
 
834
    /**
835
     * Test that the correct users are returned hwen fetching subscribed users from a forum where users are forcibly
836
     * subscribed.
837
     */
11 efrain 838
    public function test_fetch_subscribed_users_forced(): void {
1 efrain 839
        global $DB;
840
 
841
        $this->resetAfterTest(true);
842
 
843
        // Create a course, with a forum. where users are initially subscribed.
844
        $course = $this->getDataGenerator()->create_course();
845
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
846
        $forum = $this->getDataGenerator()->create_module('forum', $options);
847
 
848
        // Create some user enrolled in the course as a student.
849
        $usercount = 5;
850
        $users = $this->helper_create_users($course, $usercount);
851
 
852
        // All users should be subscribed.
853
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
854
        $this->assertEquals($usercount, count($subscribers));
855
    }
856
 
857
    /**
858
     * Test that unusual combinations of discussion subscriptions do not affect the subscribed user list.
859
     */
11 efrain 860
    public function test_fetch_subscribed_users_discussion_subscriptions(): void {
1 efrain 861
        global $DB;
862
 
863
        $this->resetAfterTest(true);
864
 
865
        // Create a course, with a forum. where users are initially subscribed.
866
        $course = $this->getDataGenerator()->create_course();
867
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
868
        $forum = $this->getDataGenerator()->create_module('forum', $options);
869
 
870
        // Create some user enrolled in the course as a student.
871
        $usercount = 5;
872
        $users = $this->helper_create_users($course, $usercount);
873
 
874
        list($discussion, $post) = $this->helper_post_to_forum($forum, $users[0]);
875
 
876
        // All users should be subscribed.
877
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
878
        $this->assertEquals($usercount, count($subscribers));
879
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
880
        $this->assertEquals($usercount, count($subscribers));
881
 
882
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($users[0]->id, $discussion);
883
 
884
        // All users should be subscribed.
885
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
886
        $this->assertEquals($usercount, count($subscribers));
887
 
888
        // All users should be subscribed.
889
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
890
        $this->assertEquals($usercount, count($subscribers));
891
 
892
        // Manually insert an extra subscription for one of the users.
893
        $record = new \stdClass();
894
        $record->userid = $users[2]->id;
895
        $record->forum = $forum->id;
896
        $record->discussion = $discussion->id;
897
        $record->preference = time();
898
        $DB->insert_record('forum_discussion_subs', $record);
899
 
900
        // The discussion count should not have changed.
901
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
902
        $this->assertEquals($usercount, count($subscribers));
903
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
904
        $this->assertEquals($usercount, count($subscribers));
905
 
906
        // Unsubscribe 2 users.
907
        $unsubscribedcount = 2;
908
        for ($i = 0; $i < $unsubscribedcount; $i++) {
909
            \mod_forum\subscriptions::unsubscribe_user($users[$i]->id, $forum);
910
        }
911
 
912
        // The subscription count should now take into account those users who have been unsubscribed.
913
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
914
        $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
915
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
916
        $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
917
 
918
        // Now subscribe one of those users back to the discussion.
919
        $subscribeddiscussionusers = 1;
920
        for ($i = 0; $i < $subscribeddiscussionusers; $i++) {
921
            \mod_forum\subscriptions::subscribe_user_to_discussion($users[$i]->id, $discussion);
922
        }
923
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
924
        $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
925
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
926
        $this->assertEquals($usercount - $unsubscribedcount + $subscribeddiscussionusers, count($subscribers));
927
    }
928
 
929
    /**
930
     * Test whether a user is force-subscribed to a forum.
931
     */
11 efrain 932
    public function test_force_subscribed_to_forum(): void {
1 efrain 933
        global $DB;
934
 
935
        $this->resetAfterTest(true);
936
 
937
        // Create a course, with a forum.
938
        $course = $this->getDataGenerator()->create_course();
939
 
940
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
941
        $forum = $this->getDataGenerator()->create_module('forum', $options);
942
 
943
        // Create a user enrolled in the course as a student.
944
        $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
945
        $user = $this->getDataGenerator()->create_user();
946
        $this->getDataGenerator()->enrol_user($user->id, $course->id, $roleids['student']);
947
 
948
        // Check that the user is currently subscribed to the forum.
949
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
950
 
951
        // Remove the allowforcesubscribe capability from the user.
952
        $cm = get_coursemodule_from_instance('forum', $forum->id);
953
        $context = \context_module::instance($cm->id);
954
        assign_capability('mod/forum:allowforcesubscribe', CAP_PROHIBIT, $roleids['student'], $context);
955
        $this->assertFalse(has_capability('mod/forum:allowforcesubscribe', $context, $user->id));
956
 
957
        // Check that the user is no longer subscribed to the forum.
958
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
959
    }
960
 
961
    /**
962
     * Test that the subscription cache can be pre-filled.
963
     */
11 efrain 964
    public function test_subscription_cache_prefill(): void {
1 efrain 965
        global $DB;
966
 
967
        $this->resetAfterTest(true);
968
 
969
        // Create a course, with a forum.
970
        $course = $this->getDataGenerator()->create_course();
971
 
972
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
973
        $forum = $this->getDataGenerator()->create_module('forum', $options);
974
 
975
        // Create some users.
976
        $users = $this->helper_create_users($course, 20);
977
 
978
        // Reset the subscription cache.
979
        \mod_forum\subscriptions::reset_forum_cache();
980
 
981
        // Filling the subscription cache should use a query.
982
        $startcount = $DB->perf_get_reads();
983
        $this->assertNull(\mod_forum\subscriptions::fill_subscription_cache($forum->id));
984
        $postfillcount = $DB->perf_get_reads();
985
        $this->assertNotEquals($postfillcount, $startcount);
986
 
987
        // Now fetch some subscriptions from that forum - these should use
988
        // the cache and not perform additional queries.
989
        foreach ($users as $user) {
990
            $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($forum->id, $user->id));
991
        }
992
        $finalcount = $DB->perf_get_reads();
993
        $this->assertEquals(0, $finalcount - $postfillcount);
994
    }
995
 
996
    /**
997
     * Test that the subscription cache can filled user-at-a-time.
998
     */
11 efrain 999
    public function test_subscription_cache_fill(): void {
1 efrain 1000
        global $DB;
1001
 
1002
        $this->resetAfterTest(true);
1003
 
1004
        // Create a course, with a forum.
1005
        $course = $this->getDataGenerator()->create_course();
1006
 
1007
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1008
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1009
 
1010
        // Create some users.
1011
        $users = $this->helper_create_users($course, 20);
1012
 
1013
        // Reset the subscription cache.
1014
        \mod_forum\subscriptions::reset_forum_cache();
1015
 
1016
        // Filling the subscription cache should only use a single query.
1017
        $startcount = $DB->perf_get_reads();
1018
 
1019
        // Fetch some subscriptions from that forum - these should not use the cache and will perform additional queries.
1020
        foreach ($users as $user) {
1021
            $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($forum->id, $user->id));
1022
        }
1023
        $finalcount = $DB->perf_get_reads();
1024
        $this->assertEquals(20, $finalcount - $startcount);
1025
    }
1026
 
1027
    /**
1028
     * Test that the discussion subscription cache can filled course-at-a-time.
1029
     */
11 efrain 1030
    public function test_discussion_subscription_cache_fill_for_course(): void {
1 efrain 1031
        global $DB;
1032
 
1033
        $this->resetAfterTest(true);
1034
 
1035
        // Create a course, with a forum.
1036
        $course = $this->getDataGenerator()->create_course();
1037
 
1038
        // Create the forums.
1039
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
1040
        $disallowforum = $this->getDataGenerator()->create_module('forum', $options);
1041
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
1042
        $chooseforum = $this->getDataGenerator()->create_module('forum', $options);
1043
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1044
        $initialforum = $this->getDataGenerator()->create_module('forum', $options);
1045
 
1046
        // Create some users and keep a reference to the first user.
1047
        $users = $this->helper_create_users($course, 20);
1048
        $user = reset($users);
1049
 
1050
        // Reset the subscription caches.
1051
        \mod_forum\subscriptions::reset_forum_cache();
1052
 
1053
        $startcount = $DB->perf_get_reads();
1054
        $result = \mod_forum\subscriptions::fill_subscription_cache_for_course($course->id, $user->id);
1055
        $this->assertNull($result);
1056
        $postfillcount = $DB->perf_get_reads();
1057
        $this->assertNotEquals($postfillcount, $startcount);
1058
        $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($disallowforum->id, $user->id));
1059
        $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($chooseforum->id, $user->id));
1060
        $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($initialforum->id, $user->id));
1061
        $finalcount = $DB->perf_get_reads();
1062
        $this->assertEquals(0, $finalcount - $postfillcount);
1063
 
1064
        // Test for all users.
1065
        foreach ($users as $user) {
1066
            $result = \mod_forum\subscriptions::fill_subscription_cache_for_course($course->id, $user->id);
1067
            $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($disallowforum->id, $user->id));
1068
            $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($chooseforum->id, $user->id));
1069
            $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($initialforum->id, $user->id));
1070
        }
1071
        $finalcount = $DB->perf_get_reads();
1072
        $this->assertNotEquals($finalcount, $postfillcount);
1073
    }
1074
 
1075
    /**
1076
     * Test that the discussion subscription cache can be forcibly updated for a user.
1077
     */
11 efrain 1078
    public function test_discussion_subscription_cache_prefill(): void {
1 efrain 1079
        global $DB;
1080
 
1081
        $this->resetAfterTest(true);
1082
 
1083
        // Create a course, with a forum.
1084
        $course = $this->getDataGenerator()->create_course();
1085
 
1086
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
1087
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1088
 
1089
        // Create some users.
1090
        $users = $this->helper_create_users($course, 20);
1091
 
1092
        // Post some discussions to the forum.
1093
        $discussions = array();
1094
        $author = $users[0];
1095
        $userwithnosubs = $users[1];
1096
 
1097
        for ($i = 0; $i < 20; $i++) {
1098
            list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1099
            $discussions[] = $discussion;
1100
        }
1101
 
1102
        // Unsubscribe half the users from the half the discussions.
1103
        $forumcount = 0;
1104
        $usercount = 0;
1105
        $userwithsubs = null;
1106
        foreach ($discussions as $data) {
1107
            // Unsubscribe user from all discussions.
1108
            \mod_forum\subscriptions::unsubscribe_user_from_discussion($userwithnosubs->id, $data);
1109
 
1110
            if ($forumcount % 2) {
1111
                continue;
1112
            }
1113
            foreach ($users as $user) {
1114
                if ($usercount % 2) {
1115
                    $userwithsubs = $user;
1116
                    continue;
1117
                }
1118
                \mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $data);
1119
                $usercount++;
1120
            }
1121
            $forumcount++;
1122
        }
1123
 
1124
        // Reset the subscription caches.
1125
        \mod_forum\subscriptions::reset_forum_cache();
1126
        \mod_forum\subscriptions::reset_discussion_cache();
1127
 
1128
        // A user with no subscriptions should only be fetched once.
1129
        $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id, $userwithnosubs->id));
1130
        $startcount = $DB->perf_get_reads();
1131
        $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id, $userwithnosubs->id));
1132
        $this->assertEquals($startcount, $DB->perf_get_reads());
1133
 
1134
        // Confirm subsequent calls properly tries to fetch subs.
1135
        $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id, $userwithsubs->id));
1136
        $this->assertNotEquals($startcount, $DB->perf_get_reads());
1137
 
1138
        // Another read should be performed to get all subscriptions for the forum.
1139
        $startcount = $DB->perf_get_reads();
1140
        $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id));
1141
        $this->assertNotEquals($startcount, $DB->perf_get_reads());
1142
 
1143
        // Reset the subscription caches.
1144
        \mod_forum\subscriptions::reset_forum_cache();
1145
        \mod_forum\subscriptions::reset_discussion_cache();
1146
 
1147
        // Filling the discussion subscription cache should only use a single query.
1148
        $startcount = $DB->perf_get_reads();
1149
        $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id));
1150
        $postfillcount = $DB->perf_get_reads();
1151
        $this->assertNotEquals($postfillcount, $startcount);
1152
 
1153
        // Now fetch some subscriptions from that forum - these should use
1154
        // the cache and not perform additional queries.
1155
        foreach ($users as $user) {
1156
            $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $user->id);
1157
            $this->assertIsArray($result);
1158
        }
1159
        $finalcount = $DB->perf_get_reads();
1160
        $this->assertEquals(0, $finalcount - $postfillcount);
1161
    }
1162
 
1163
    /**
1164
     * Test that the discussion subscription cache can filled user-at-a-time.
1165
     */
11 efrain 1166
    public function test_discussion_subscription_cache_fill(): void {
1 efrain 1167
        global $DB;
1168
 
1169
        $this->resetAfterTest(true);
1170
 
1171
        // Create a course, with a forum.
1172
        $course = $this->getDataGenerator()->create_course();
1173
 
1174
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1175
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1176
 
1177
        // Create some users.
1178
        $users = $this->helper_create_users($course, 20);
1179
 
1180
        // Post some discussions to the forum.
1181
        $discussions = array();
1182
        $author = $users[0];
1183
        for ($i = 0; $i < 20; $i++) {
1184
            list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1185
            $discussions[] = $discussion;
1186
        }
1187
 
1188
        // Unsubscribe half the users from the half the discussions.
1189
        $forumcount = 0;
1190
        $usercount = 0;
1191
        foreach ($discussions as $data) {
1192
            if ($forumcount % 2) {
1193
                continue;
1194
            }
1195
            foreach ($users as $user) {
1196
                if ($usercount % 2) {
1197
                    continue;
1198
                }
1199
                \mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion);
1200
                $usercount++;
1201
            }
1202
            $forumcount++;
1203
        }
1204
 
1205
        // Reset the subscription caches.
1206
        \mod_forum\subscriptions::reset_forum_cache();
1207
        \mod_forum\subscriptions::reset_discussion_cache();
1208
 
1209
        $startcount = $DB->perf_get_reads();
1210
 
1211
        // Now fetch some subscriptions from that forum - these should use
1212
        // the cache and not perform additional queries.
1213
        foreach ($users as $user) {
1214
            $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $user->id);
1215
            $this->assertIsArray($result);
1216
        }
1217
        $finalcount = $DB->perf_get_reads();
1218
        $this->assertNotEquals($finalcount, $startcount);
1219
    }
1220
 
1221
    /**
1222
     * Test that after toggling the forum subscription as another user,
1223
     * the discussion subscription functionality works as expected.
1224
     */
11 efrain 1225
    public function test_forum_subscribe_toggle_as_other_repeat_subscriptions(): void {
1 efrain 1226
        global $DB;
1227
 
1228
        $this->resetAfterTest(true);
1229
 
1230
        // Create a course, with a forum.
1231
        $course = $this->getDataGenerator()->create_course();
1232
 
1233
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
1234
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1235
 
1236
        // Create a user enrolled in the course as a student.
1237
        list($user) = $this->helper_create_users($course, 1);
1238
 
1239
        // Post a discussion to the forum.
1240
        list($discussion, $post) = $this->helper_post_to_forum($forum, $user);
1241
 
1242
        // Confirm that the user is currently not subscribed to the forum.
1243
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1244
 
1245
        // Confirm that the user is unsubscribed from the discussion too.
1246
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum, $discussion->id));
1247
 
1248
        // Confirm that we have no records in either of the subscription tables.
1249
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1250
            'userid'        => $user->id,
1251
            'forum'         => $forum->id,
1252
        )));
1253
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
1254
            'userid'        => $user->id,
1255
            'discussion'    => $discussion->id,
1256
        )));
1257
 
1258
        // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
1259
        // subscriptions table.
1260
        \mod_forum\subscriptions::subscribe_user($user->id, $forum);
1261
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
1262
            'userid'        => $user->id,
1263
            'forum'         => $forum->id,
1264
        )));
1265
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
1266
            'userid'        => $user->id,
1267
            'discussion'    => $discussion->id,
1268
        )));
1269
 
1270
        // Now unsubscribe from the discussion. This should return true.
1271
        $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1272
 
1273
        // Attempting to unsubscribe again should return false because no change was made.
1274
        $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1275
 
1276
        // Subscribing to the discussion again should return truthfully as the subscription preference was removed.
1277
        $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1278
 
1279
        // Attempting to subscribe again should return false because no change was made.
1280
        $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1281
 
1282
        // Now unsubscribe from the discussion. This should return true once more.
1283
        $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1284
 
1285
        // And unsubscribing from the forum but not as a request from the user should maintain their preference.
1286
        \mod_forum\subscriptions::unsubscribe_user($user->id, $forum);
1287
 
1288
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1289
            'userid'        => $user->id,
1290
            'forum'         => $forum->id,
1291
        )));
1292
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
1293
            'userid'        => $user->id,
1294
            'discussion'    => $discussion->id,
1295
        )));
1296
 
1297
        // Subscribing to the discussion should return truthfully because a change was made.
1298
        $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1299
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1300
            'userid'        => $user->id,
1301
            'forum'         => $forum->id,
1302
        )));
1303
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
1304
            'userid'        => $user->id,
1305
            'discussion'    => $discussion->id,
1306
        )));
1307
    }
1308
 
1309
    /**
1310
     * Test that providing a context_module instance to is_subscribed does not result in additional lookups to retrieve
1311
     * the context_module.
1312
     */
11 efrain 1313
    public function test_is_subscribed_cm(): void {
1 efrain 1314
        global $DB;
1315
 
1316
        $this->resetAfterTest(true);
1317
 
1318
        // Create a course, with a forum.
1319
        $course = $this->getDataGenerator()->create_course();
1320
 
1321
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
1322
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1323
 
1324
        // Create a user enrolled in the course as a student.
1325
        list($user) = $this->helper_create_users($course, 1);
1326
 
1327
        // Retrieve the $cm now.
1328
        $cm = get_fast_modinfo($forum->course)->instances['forum'][$forum->id];
1329
 
1330
        // Reset get_fast_modinfo.
1331
        get_fast_modinfo(0, 0, true);
1332
 
1333
        // Call is_subscribed without passing the $cmid - this should result in a lookup and filling of some of the
1334
        // caches. This provides us with consistent data to start from.
1335
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1336
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1337
 
1338
        // Make a note of the number of DB calls.
1339
        $basecount = $DB->perf_get_reads();
1340
 
1341
        // Call is_subscribed - it should give return the correct result (False), and result in no additional queries.
1342
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum, null, $cm));
1343
 
1344
        // The capability check does require some queries, so we don't test it directly.
1345
        // We don't assert here because this is dependant upon linked code which could change at any time.
1346
        $suppliedcmcount = $DB->perf_get_reads() - $basecount;
1347
 
1348
        // Call is_subscribed without passing the $cmid now - this should result in a lookup.
1349
        get_fast_modinfo(0, 0, true);
1350
        $basecount = $DB->perf_get_reads();
1351
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1352
        $calculatedcmcount = $DB->perf_get_reads() - $basecount;
1353
 
1354
        // There should be more queries than when we performed the same check a moment ago.
1355
        $this->assertGreaterThan($suppliedcmcount, $calculatedcmcount);
1356
    }
1357
 
1441 ariadna 1358
    public static function is_subscribable_forums(): array {
1 efrain 1359
        return [
1360
            [
1361
                'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE,
1362
            ],
1363
            [
1364
                'forcesubscribe' => FORUM_CHOOSESUBSCRIBE,
1365
            ],
1366
            [
1367
                'forcesubscribe' => FORUM_INITIALSUBSCRIBE,
1368
            ],
1369
            [
1370
                'forcesubscribe' => FORUM_FORCESUBSCRIBE,
1371
            ],
1372
        ];
1373
    }
1374
 
1441 ariadna 1375
    public static function is_subscribable_provider(): array {
1 efrain 1376
        $data = [];
1441 ariadna 1377
        foreach (self::is_subscribable_forums() as $forum) {
1 efrain 1378
            $data[] = [$forum];
1379
        }
1380
 
1381
        return $data;
1382
    }
1383
 
1384
    /**
1385
     * @dataProvider is_subscribable_provider
1386
     */
11 efrain 1387
    public function test_is_subscribable_logged_out($options): void {
1 efrain 1388
        $this->resetAfterTest(true);
1389
 
1390
        // Create a course, with a forum.
1391
        $course = $this->getDataGenerator()->create_course();
1392
        $options['course'] = $course->id;
1393
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1394
 
1395
        $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
1396
    }
1397
 
1398
    /**
1399
     * @dataProvider is_subscribable_provider
1400
     */
11 efrain 1401
    public function test_is_subscribable_is_guest($options): void {
1 efrain 1402
        global $DB;
1403
        $this->resetAfterTest(true);
1404
 
1405
        $guest = $DB->get_record('user', array('username'=>'guest'));
1406
        $this->setUser($guest);
1407
 
1408
        // Create a course, with a forum.
1409
        $course = $this->getDataGenerator()->create_course();
1410
        $options['course'] = $course->id;
1411
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1412
 
1413
        $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
1414
    }
1415
 
1441 ariadna 1416
    public static function is_subscribable_loggedin_provider(): array {
1 efrain 1417
        return [
1418
            [
1419
                ['forcesubscribe' => FORUM_DISALLOWSUBSCRIBE],
1420
                false,
1421
            ],
1422
            [
1423
                ['forcesubscribe' => FORUM_CHOOSESUBSCRIBE],
1424
                true,
1425
            ],
1426
            [
1427
                ['forcesubscribe' => FORUM_INITIALSUBSCRIBE],
1428
                true,
1429
            ],
1430
            [
1431
                ['forcesubscribe' => FORUM_FORCESUBSCRIBE],
1432
                false,
1433
            ],
1434
        ];
1435
    }
1436
 
1437
    /**
1438
     * @dataProvider is_subscribable_loggedin_provider
1439
     */
11 efrain 1440
    public function test_is_subscribable_loggedin($options, $expect): void {
1 efrain 1441
        $this->resetAfterTest(true);
1442
 
1443
        // Create a course, with a forum.
1444
        $course = $this->getDataGenerator()->create_course();
1445
        $options['course'] = $course->id;
1446
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1447
 
1448
        $user = $this->getDataGenerator()->create_user();
1449
        $this->getDataGenerator()->enrol_user($user->id, $course->id);
1450
        $this->setUser($user);
1451
 
1452
        $this->assertEquals($expect, \mod_forum\subscriptions::is_subscribable($forum));
1453
    }
1454
 
11 efrain 1455
    public function test_get_user_default_subscription(): void {
1 efrain 1456
        global $DB;
1457
        $this->resetAfterTest(true);
1458
 
1459
        // Create a course, with a forum.
1460
        $course = $this->getDataGenerator()->create_course();
1461
        $context = \context_course::instance($course->id);
1462
        $options['course'] = $course->id;
1463
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1464
        $cm = get_coursemodule_from_instance("forum", $forum->id, $course->id);
1465
 
1466
        // Create a user enrolled in the course as a student.
1467
        list($author, $student) = $this->helper_create_users($course, 2, 'student');
1468
        // Post a discussion to the forum.
1469
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1470
 
1471
        // A guest user.
1472
        $this->setUser(0);
1473
        $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1474
        $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1475
 
1476
        // A user enrolled in the course.
1477
        $this->setUser($author->id);
1478
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1479
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1480
 
1481
        // Subscribption disabled.
1482
        $this->setUser($student->id);
1483
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_DISALLOWSUBSCRIBE);
1484
        $forum = $DB->get_record('forum', array('id' => $forum->id));
1485
        $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1486
        $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1487
 
1488
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_FORCESUBSCRIBE);
1489
        $forum = $DB->get_record('forum', array('id' => $forum->id));
1490
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1491
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1492
 
1493
        // Admin user.
1494
        $this->setAdminUser();
1495
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1496
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1497
    }
1498
}