on-demand release 3.8dev+
[moodle.git] / mod / forum / tests / managers_capability_test.php
CommitLineData
47d38303
RW
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/**
18 * The capability manager tests.
19 *
20 * @package mod_forum
21 * @copyright 2019 Ryan Wyllie <ryan@moodle.com>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25defined('MOODLE_INTERNAL') || die();
26
27global $CFG;
28require_once(__DIR__ . '/generator_trait.php');
29
30use mod_forum\local\managers\capability as capability_manager;
31
32/**
33 * The capability manager tests.
34 *
35 * @package mod_forum
36 * @copyright 2019 Ryan Wyllie <ryan@moodle.com>
37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
15dc885a 38 * @coversDefaultClass \mod_forum\local\managers\capability
47d38303
RW
39 */
40class mod_forum_managers_capability_testcase extends advanced_testcase {
41 // Make use of the test generator trait.
42 use mod_forum_tests_generator_trait;
43
44 /** @var stdClass */
45 private $user;
46
47 /** @var \mod_forum\local\factories\entity */
48 private $entityfactory;
49
50 /** @var \mod_forum\local\factories\manager */
51 private $managerfactory;
52
53 /** @var stdClass */
54 private $course;
55
56 /** @var stdClass */
57 private $forumrecord;
58
59 /** @var stdClass */
60 private $coursemodule;
61
62 /** @var context */
63 private $context;
64
65 /** @var int */
66 private $roleid;
67
68 /** @var \mod_forum\local\entities\discussion */
69 private $discussion;
70
71 /** @var stdClass */
72 private $discussionrecord;
73
74 /** @var \mod_forum\local\entities\post */
75 private $post;
76
77 /** @var stdClass */
78 private $postrecord;
79
80 /**
81 * Setup function before each test.
82 */
83 public function setUp() {
84 global $DB;
85
86 // We must clear the subscription caches. This has to be done both before each test, and after in case of other
87 // tests using these functions.
88 \mod_forum\subscriptions::reset_forum_cache();
89
90 $datagenerator = $this->getDataGenerator();
91 $this->user = $datagenerator->create_user();
92 $this->managerfactory = \mod_forum\local\container::get_manager_factory();
93 $this->entityfactory = \mod_forum\local\container::get_entity_factory();
94 $this->course = $datagenerator->create_course();
95 $this->forumrecord = $datagenerator->create_module('forum', ['course' => $this->course->id]);
96 $this->coursemodule = get_coursemodule_from_instance('forum', $this->forumrecord->id);
97 $this->context = context_module::instance($this->coursemodule->id);
98 $this->roleid = $DB->get_field('role', 'id', ['shortname' => 'teacher'], MUST_EXIST);
99
100 $datagenerator->enrol_user($this->user->id, $this->course->id, 'teacher');
101 [$discussion, $post] = $this->helper_post_to_forum($this->forumrecord, $this->user, ['timemodified' => time() - 100]);
102 $this->discussion = $this->entityfactory->get_discussion_from_stdclass($discussion);
103 $this->discussionrecord = $discussion;
104 $this->post = $this->entityfactory->get_post_from_stdclass(
105 (object) array_merge((array) $post, ['timecreated' => time() - 100])
106 );
107 $this->postrecord = $post;
108
109 $this->setUser($this->user);
110 }
111
112 /**
113 * Tear down function after each test.
114 */
115 public function tearDown() {
116 // We must clear the subscription caches. This has to be done both before each test, and after in case of other
117 // tests using these functions.
118 \mod_forum\subscriptions::reset_forum_cache();
119 }
120
121 /**
122 * Helper function to create a forum entity.
123 *
124 * @param array $forumproperties List of properties to override the prebuilt forum
125 * @return forum_entity
126 */
127 private function create_forum(array $forumproperties = []) {
128 $forumrecord = (object) array_merge((array) $this->forumrecord, $forumproperties);
129 return $this->entityfactory->get_forum_from_stdclass(
130 $forumrecord,
131 $this->context,
132 $this->coursemodule,
133 $this->course
134 );
135 }
136
137 /**
138 * Helper function to assign a capability to the prebuilt role (teacher).
139 *
140 * @param string $capability Name of the capability
141 * @param context|null $context The context to assign the capability in
142 */
143 private function give_capability($capability, $context = null) {
144 $context = $context ?? $this->context;
145 assign_capability($capability, CAP_ALLOW, $this->roleid, $context->id, true);
146 }
147
148 /**
149 * Helper function to prevent a capability to the prebuilt role (teacher).
150 *
151 * @param string $capability Name of the capability
152 * @param context|null $context The context to assign the capability in
153 */
154 private function prevent_capability($capability, $context = null) {
155 $context = $context ?? $this->context;
156 assign_capability($capability, CAP_PREVENT, $this->roleid, $context->id, true);
157 }
158
159 /**
160 * Test can_subscribe_to_forum.
15dc885a
AN
161 *
162 * @covers ::can_subscribe_to_forum
47d38303
RW
163 */
164 public function test_can_subscribe_to_forum() {
165 $this->resetAfterTest();
166
167 $forum = $this->create_forum();
168 $guestuser = $this->getDataGenerator()->create_user();
169 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
170
171 $this->assertFalse($capabilitymanager->can_subscribe_to_forum($guestuser));
172 $this->assertTrue($capabilitymanager->can_subscribe_to_forum($this->user));
173 }
174
175 /**
176 * Test can_create_discussions.
15dc885a
AN
177 *
178 * @covers ::can_create_discussions
47d38303
RW
179 */
180 public function test_can_create_discussions() {
181 $this->resetAfterTest();
182
183 $forum = $this->create_forum();
184 $guestuser = $this->getDataGenerator()->create_user();
185 $user = $this->user;
186 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
187
188 $this->assertFalse($capabilitymanager->can_create_discussions($guestuser));
189
190 $this->prevent_capability('mod/forum:startdiscussion');
191 $this->assertFalse($capabilitymanager->can_create_discussions($user));
192
193 $this->give_capability('mod/forum:startdiscussion');
194 $this->assertTrue($capabilitymanager->can_create_discussions($user));
195
196 $forum = $this->create_forum(['type' => 'news']);
197 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
198
199 $this->prevent_capability('mod/forum:addnews');
200 $this->assertFalse($capabilitymanager->can_create_discussions($user));
201
202 $this->give_capability('mod/forum:addnews');
203 $this->assertTrue($capabilitymanager->can_create_discussions($user));
204
205 $forum = $this->create_forum(['type' => 'qanda']);
206 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
207
208 $this->prevent_capability('mod/forum:addquestion');
209 $this->assertFalse($capabilitymanager->can_create_discussions($user));
210
211 $this->give_capability('mod/forum:addquestion');
212 $this->assertTrue($capabilitymanager->can_create_discussions($user));
213
214 // Test a forum in group mode.
215 $forumrecord = $this->getDataGenerator()->create_module(
216 'forum',
217 ['course' => $this->course->id, 'groupmode' => SEPARATEGROUPS]
218 );
219 $coursemodule = get_coursemodule_from_instance('forum', $forumrecord->id);
220 $context = context_module::instance($coursemodule->id);
221 $forum = $this->entityfactory->get_forum_from_stdclass(
222 $forumrecord,
223 $context,
224 $coursemodule,
225 $this->course
226 );
227
228 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
229
230 $this->assertFalse($capabilitymanager->can_create_discussions($user));
231
232 $this->give_capability('moodle/site:accessallgroups', $context);
233 $this->assertTrue($capabilitymanager->can_create_discussions($user));
234
235 $this->prevent_capability('moodle/site:accessallgroups', $context);
236 $this->assertFalse($capabilitymanager->can_create_discussions($user));
237
238 $group = $this->getDataGenerator()->create_group(['courseid' => $this->course->id]);
239 $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
240
241 $this->assertTrue($capabilitymanager->can_create_discussions($user, $group->id));
242 }
243
244 /**
245 * Test can_access_all_groups.
15dc885a
AN
246 *
247 * @covers ::can_access_all_groups
47d38303
RW
248 */
249 public function test_can_access_all_groups() {
250 $this->resetAfterTest();
251
252 $forum = $this->create_forum();
253 $user = $this->user;
254 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
255
256 $this->prevent_capability('moodle/site:accessallgroups');
257 $this->assertFalse($capabilitymanager->can_access_all_groups($user));
258
259 $this->give_capability('moodle/site:accessallgroups');
260 $this->assertTrue($capabilitymanager->can_access_all_groups($user));
261 }
262
263 /**
264 * Test can_access_group.
15dc885a
AN
265 *
266 * @covers ::can_access_group
47d38303
RW
267 */
268 public function test_can_access_group() {
269 $this->resetAfterTest();
270
271 $forum = $this->create_forum();
272 $user = $this->user;
273 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
274 $group = $this->getDataGenerator()->create_group(['courseid' => $this->course->id]);
275
276 $this->prevent_capability('moodle/site:accessallgroups');
277 $this->assertFalse($capabilitymanager->can_access_group($user, $group->id));
278
279 $this->give_capability('moodle/site:accessallgroups');
280 $this->assertTrue($capabilitymanager->can_access_group($user, $group->id));
281
282 $this->prevent_capability('moodle/site:accessallgroups');
283 $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
284 $this->assertTrue($capabilitymanager->can_access_group($user, $group->id));
285 }
286
287 /**
288 * Test can_view_discussions.
15dc885a
AN
289 *
290 * @covers ::can_view_discussions
47d38303
RW
291 */
292 public function test_can_view_discussions() {
293 $this->resetAfterTest();
294
295 $forum = $this->create_forum();
296 $user = $this->user;
297 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
298
299 $this->prevent_capability('mod/forum:viewdiscussion');
300 $this->assertFalse($capabilitymanager->can_view_discussions($user));
301
302 $this->give_capability('mod/forum:viewdiscussion');
303 $this->assertTrue($capabilitymanager->can_view_discussions($user));
304 }
305
306 /**
307 * Test can_move_discussions.
15dc885a
AN
308 *
309 * @covers ::can_move_discussions
47d38303
RW
310 */
311 public function test_can_move_discussions() {
312 $this->resetAfterTest();
313
314 $forum = $this->create_forum();
315 $user = $this->user;
316 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
317
318 $this->prevent_capability('mod/forum:movediscussions');
319 $this->assertFalse($capabilitymanager->can_move_discussions($user));
320
321 $this->give_capability('mod/forum:movediscussions');
322 $this->assertTrue($capabilitymanager->can_move_discussions($user));
323
324 $forum = $this->create_forum(['type' => 'single']);
325 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
326
327 $this->assertFalse($capabilitymanager->can_move_discussions($user));
328 }
329
330 /**
331 * Test can_pin_discussions.
15dc885a
AN
332 *
333 * @covers ::can_pin_discussions
47d38303
RW
334 */
335 public function test_can_pin_discussions() {
336 $this->resetAfterTest();
337
338 $forum = $this->create_forum();
339 $user = $this->user;
340 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
341
342 $this->prevent_capability('mod/forum:pindiscussions');
343 $this->assertFalse($capabilitymanager->can_pin_discussions($user));
344
345 $this->give_capability('mod/forum:pindiscussions');
346 $this->assertTrue($capabilitymanager->can_pin_discussions($user));
347 }
348
349 /**
350 * Test can_split_discussions.
15dc885a
AN
351 *
352 * @covers ::can_split_discussions
47d38303
RW
353 */
354 public function test_can_split_discussions() {
355 $this->resetAfterTest();
356
357 $forum = $this->create_forum();
358 $user = $this->user;
359 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
360
361 $this->prevent_capability('mod/forum:splitdiscussions');
362 $this->assertFalse($capabilitymanager->can_split_discussions($user));
363
364 $this->give_capability('mod/forum:splitdiscussions');
365 $this->assertTrue($capabilitymanager->can_split_discussions($user));
366
367 $forum = $this->create_forum(['type' => 'single']);
368 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
369
370 $this->assertFalse($capabilitymanager->can_split_discussions($user));
371 }
372
373 /**
374 * Test can_export_discussions.
15dc885a
AN
375 *
376 * @covers ::can_export_discussions
47d38303
RW
377 */
378 public function test_can_export_discussions() {
379 global $CFG;
380 $this->resetAfterTest();
381
382 $CFG->enableportfolios = true;
383 $forum = $this->create_forum();
384 $user = $this->user;
385 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
386
387 $this->prevent_capability('mod/forum:exportdiscussion');
388 $this->assertFalse($capabilitymanager->can_export_discussions($user));
389
390 $this->give_capability('mod/forum:exportdiscussion');
391 $this->assertTrue($capabilitymanager->can_export_discussions($user));
392
393 $CFG->enableportfolios = false;
394
395 $this->assertFalse($capabilitymanager->can_export_discussions($user));
396 }
397
398 /**
399 * Test can_manually_control_post_read_status.
15dc885a
AN
400 *
401 * @covers ::can_manually_control_post_read_status
47d38303
RW
402 */
403 public function test_can_manually_control_post_read_status() {
404 global $CFG, $DB;
405 $this->resetAfterTest();
406
407 $CFG->forum_usermarksread = true;
408 $forum = $this->create_forum();
409 $user = $this->user;
410 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
411 $cache = cache::make('mod_forum', 'forum_is_tracked');
412
413 $user->trackforums = true;
414 $prefid = $DB->insert_record('forum_track_prefs', ['userid' => $user->id, 'forumid' => $forum->get_id()]);
415 $this->assertFalse($capabilitymanager->can_manually_control_post_read_status($user));
416 $cache->purge();
417
418 $DB->delete_records('forum_track_prefs', ['id' => $prefid]);
419 $this->assertTrue($capabilitymanager->can_manually_control_post_read_status($user));
420 $cache->purge();
421
422 $CFG->forum_usermarksread = false;
423
424 $this->assertFalse($capabilitymanager->can_manually_control_post_read_status($user));
425 }
426
427 /**
428 * Test must_post_before_viewing_discussion.
15dc885a
AN
429 *
430 * @covers ::must_post_before_viewing_discussion
47d38303
RW
431 */
432 public function test_must_post_before_viewing_discussion() {
433 $this->resetAfterTest();
434
435 $forum = $this->create_forum();
436 $user = $this->user;
437 $discussion = $this->discussion;
438 $newuser = $this->getDataGenerator()->create_user();
439 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
440 $this->getDataGenerator()->enrol_user($newuser->id, $this->course->id, 'teacher');
441
442 $this->assertFalse($capabilitymanager->must_post_before_viewing_discussion($newuser, $discussion));
443
444 $forum = $this->create_forum(['type' => 'qanda']);
445 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
446
447 $this->prevent_capability('mod/forum:viewqandawithoutposting');
448 $this->assertTrue($capabilitymanager->must_post_before_viewing_discussion($newuser, $discussion));
449
450 $this->give_capability('mod/forum:viewqandawithoutposting');
451 $this->assertFalse($capabilitymanager->must_post_before_viewing_discussion($newuser, $discussion));
452
453 $this->prevent_capability('mod/forum:viewqandawithoutposting');
454 // The pre-generated user has a pre-generated post in the disussion already.
455 $this->assertFalse($capabilitymanager->must_post_before_viewing_discussion($user, $discussion));
456 }
457
458 /**
459 * Test can_subscribe_to_discussion.
15dc885a
AN
460 *
461 * @covers ::can_subscribe_to_discussion
47d38303
RW
462 */
463 public function test_can_subscribe_to_discussion() {
464 $this->resetAfterTest();
465
466 $forum = $this->create_forum();
467 $discussion = $this->discussion;
468 $guestuser = $this->getDataGenerator()->create_user();
469 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
470
471 $this->assertFalse($capabilitymanager->can_subscribe_to_discussion($guestuser, $discussion));
472 $this->assertTrue($capabilitymanager->can_subscribe_to_discussion($this->user, $discussion));
473 }
474
475 /**
476 * Test can_move_discussion.
15dc885a
AN
477 *
478 * @covers ::can_move_discussion
47d38303
RW
479 */
480 public function test_can_move_discussion() {
481 $this->resetAfterTest();
482
483 $forum = $this->create_forum();
484 $discussion = $this->discussion;
485 $user = $this->user;
486 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
487
488 $this->prevent_capability('mod/forum:movediscussions');
489 $this->assertFalse($capabilitymanager->can_move_discussion($user, $discussion));
490
491 $this->give_capability('mod/forum:movediscussions');
492 $this->assertTrue($capabilitymanager->can_move_discussion($user, $discussion));
493
494 $forum = $this->create_forum(['type' => 'single']);
495 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
496
497 $this->assertFalse($capabilitymanager->can_move_discussion($user, $discussion));
498 }
499
500 /**
501 * Test can_pin_discussion.
15dc885a
AN
502 *
503 * @covers ::can_pin_discussion
47d38303
RW
504 */
505 public function test_can_pin_discussion() {
506 $this->resetAfterTest();
507
508 $forum = $this->create_forum();
509 $discussion = $this->discussion;
510 $user = $this->user;
511 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
512
513 $this->prevent_capability('mod/forum:pindiscussions');
514 $this->assertFalse($capabilitymanager->can_pin_discussion($user, $discussion));
515
516 $this->give_capability('mod/forum:pindiscussions');
517 $this->assertTrue($capabilitymanager->can_pin_discussion($user, $discussion));
518 }
519
520 /**
521 * Test can_post_in_discussion.
15dc885a
AN
522 *
523 * @covers ::can_post_in_discussion
47d38303
RW
524 */
525 public function test_can_post_in_discussion() {
526 $this->resetAfterTest();
527
528 $discussion = $this->discussion;
529 $user = $this->user;
530
531 // Locked discussions.
532 $lockedforum = $this->create_forum(['lockdiscussionafter' => 1]);
533 $capabilitymanager = $this->managerfactory->get_capability_manager($lockedforum);
534
535 $this->give_capability('mod/forum:canoverridediscussionlock');
536 $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
537
538 $this->prevent_capability('mod/forum:canoverridediscussionlock');
539 $this->assertFalse($capabilitymanager->can_post_in_discussion($user, $discussion));
540
541 // News forum.
542 $newsforum = $this->create_forum(['type' => 'news']);
543 $capabilitymanager = $this->managerfactory->get_capability_manager($newsforum);
544
545 $this->give_capability('mod/forum:replynews');
546 $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
547
548 $this->prevent_capability('mod/forum:replynews');
549 $this->assertFalse($capabilitymanager->can_post_in_discussion($user, $discussion));
550
551 // General forum.
552 $forum = $this->create_forum();
553 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
554
555 $this->give_capability('mod/forum:replypost');
556 $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
557
558 $this->prevent_capability('mod/forum:replypost');
559 $this->assertFalse($capabilitymanager->can_post_in_discussion($user, $discussion));
560
561 // Forum in separate group mode.
562 $forumrecord = $this->getDataGenerator()->create_module(
563 'forum',
564 ['course' => $this->course->id, 'groupmode' => SEPARATEGROUPS]
565 );
566 $coursemodule = get_coursemodule_from_instance('forum', $forumrecord->id);
567 $context = context_module::instance($coursemodule->id);
568 $forum = $this->entityfactory->get_forum_from_stdclass(
569 $forumrecord,
570 $context,
571 $coursemodule,
572 $this->course
573 );
574 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
575
576 $this->give_capability('moodle/site:accessallgroups', $context);
577 $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
578
579 $this->prevent_capability('moodle/site:accessallgroups', $context);
580 $this->assertFalse($capabilitymanager->can_post_in_discussion($user, $discussion));
581
582 $group = $this->getDataGenerator()->create_group(['courseid' => $this->course->id]);
583 $discussion = $this->entityfactory->get_discussion_from_stdclass(
584 (object) array_merge((array) $this->discussionrecord, ['groupid' => $group->id])
585 );
586
587 $this->assertFalse($capabilitymanager->can_post_in_discussion($user, $discussion));
588
589 $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
590
591 $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
592
593 // Forum in visible group mode.
594 $forumrecord = $this->getDataGenerator()->create_module(
595 'forum',
596 ['course' => $this->course->id, 'groupmode' => VISIBLEGROUPS]
597 );
598 $coursemodule = get_coursemodule_from_instance('forum', $forumrecord->id);
599 $context = context_module::instance($coursemodule->id);
600 $forum = $this->entityfactory->get_forum_from_stdclass(
601 $forumrecord,
602 $context,
603 $coursemodule,
604 $this->course
605 );
606 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
607
608 $this->give_capability('moodle/site:accessallgroups', $context);
609 $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
610
611 $this->prevent_capability('moodle/site:accessallgroups', $context);
612 $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
613
614 $group = $this->getDataGenerator()->create_group(['courseid' => $this->course->id]);
615 $discussion = $this->entityfactory->get_discussion_from_stdclass(
616 (object) array_merge((array) $this->discussionrecord, ['groupid' => $group->id])
617 );
618
619 $this->assertFalse($capabilitymanager->can_post_in_discussion($user, $discussion));
620
621 $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
622
623 $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
624 }
625
626 /**
627 * Test can_edit_post.
15dc885a
AN
628 *
629 * @covers ::can_edit_post
47d38303
RW
630 */
631 public function test_can_edit_post() {
632 global $CFG;
633
634 $this->resetAfterTest();
635
636 $forum = $this->create_forum();
637 $discussion = $this->discussion;
638 // The generated post is created 100 seconds in the past.
639 $post = $this->post;
640 $user = $this->user;
641 $otheruser = $this->getDataGenerator()->create_user();
642 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
643
644 $this->prevent_capability('mod/forum:editanypost');
645
646 // 200 seconds to edit.
647 $CFG->maxeditingtime = 200;
648 $this->assertTrue($capabilitymanager->can_edit_post($user, $discussion, $post));
649
650 // 10 seconds to edit. No longer in editing time.
651 $CFG->maxeditingtime = 10;
652 $this->assertFalse($capabilitymanager->can_edit_post($user, $discussion, $post));
653
654 // Can edit outside of editing time with this capability.
655 $this->give_capability('mod/forum:editanypost');
656 $this->assertTrue($capabilitymanager->can_edit_post($user, $discussion, $post));
657
658 $CFG->maxeditingtime = 200;
659 $this->assertFalse($capabilitymanager->can_edit_post($otheruser, $discussion, $post));
660
661 $this->prevent_capability('mod/forum:editanypost');
662
663 // News forum.
664 $forum = $this->create_forum(['type' => 'news']);
665 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
666 // Discussion hasn't started yet.
667 $discussion = $this->entityfactory->get_discussion_from_stdclass(
668 (object) array_merge((array) $this->discussionrecord, ['timestart' => time() + 100])
669 );
670
671 $this->assertFalse($capabilitymanager->can_edit_post($user, $discussion, $post));
672
673 // Back to a discussion that has started.
674 $discussion = $this->discussion;
675 // Post is a reply.
676 $post = $this->entityfactory->get_post_from_stdclass(
677 (object) array_merge((array) $this->postrecord, ['parent' => 5])
678 );
679
680 $this->assertFalse($capabilitymanager->can_edit_post($user, $discussion, $post));
681
682 $post = $this->post;
683 // Discussion has started and post isn't a reply so we can edit it.
684 $this->assertTrue($capabilitymanager->can_edit_post($user, $discussion, $post));
685
686 // Single forum.
687 $forum = $this->create_forum(['type' => 'single']);
688 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
689
690 // Create a new post that definitely isn't the first post of the discussion.
50b52ef4 691 // Only the author, and a user with editanypost can edit it.
47d38303
RW
692 $post = $this->entityfactory->get_post_from_stdclass(
693 (object) array_merge((array) $this->postrecord, ['id' => $post->get_id() + 100])
694 );
50b52ef4
AN
695 $this->give_capability('mod/forum:editanypost');
696 $this->assertTrue($capabilitymanager->can_edit_post($user, $discussion, $post));
697 $this->assertFalse($capabilitymanager->can_edit_post($otheruser, $discussion, $post));
47d38303
RW
698
699 $post = $this->post;
700 // Set the first post of the discussion to our post.
701 $discussion = $this->entityfactory->get_discussion_from_stdclass(
702 (object) array_merge((array) $this->discussionrecord, ['firstpost' => $post->get_id()])
703 );
704
705 $this->prevent_capability('moodle/course:manageactivities');
706 $this->assertFalse($capabilitymanager->can_edit_post($user, $discussion, $post));
707
708 $this->give_capability('moodle/course:manageactivities');
709 $this->assertTrue($capabilitymanager->can_edit_post($user, $discussion, $post));
710 }
711
712 /**
713 * Test can_delete_post.
15dc885a
AN
714 *
715 * @covers ::can_delete_post
47d38303
RW
716 */
717 public function test_can_delete_post() {
718 global $CFG;
719
720 $this->resetAfterTest();
721
722 // Single forum.
723 $forum = $this->create_forum(['type' => 'single']);
724 // The generated post is created 100 seconds in the past.
725 $post = $this->post;
726 $user = $this->user;
727 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
728
729 // Set the first post of the discussion to our post.
730 $discussion = $this->entityfactory->get_discussion_from_stdclass(
731 (object) array_merge((array) $this->discussionrecord, ['firstpost' => $post->get_id()])
732 );
733
734 // Can't delete the first post of a single discussion forum.
735 $this->assertFalse($capabilitymanager->can_delete_post($user, $discussion, $post));
736
737 // Set the first post of the discussion to something else.
738 $discussion = $this->entityfactory->get_discussion_from_stdclass(
739 (object) array_merge((array) $this->discussionrecord, ['firstpost' => $post->get_id() - 1])
740 );
741
742 $this->assertTrue($capabilitymanager->can_delete_post($user, $discussion, $post));
743
744 // Back to a general forum.
745 $forum = $this->create_forum();
746 $this->prevent_capability('mod/forum:deleteanypost');
747 $this->give_capability('mod/forum:deleteownpost');
748 // 200 second editing time to make sure our post is still within it.
749 $CFG->maxeditingtime = 200;
750
751 // Make the post owned by someone else.
752 $post = $this->entityfactory->get_post_from_stdclass(
753 (object) array_merge((array) $this->postrecord, ['userid' => $user->id - 1])
754 );
755
756 // Can't delete someone else's post.
757 $this->assertFalse($capabilitymanager->can_delete_post($user, $discussion, $post));
758 // Back to our post.
759 $post = $this->post;
760
761 // Not in editing time.
762 $CFG->maxeditingtime = 10;
763 $this->assertFalse($capabilitymanager->can_delete_post($user, $discussion, $post));
764
765 $CFG->maxeditingtime = 200;
766 // Remove the capability to delete own post.
767 $this->prevent_capability('mod/forum:deleteownpost');
768 $this->assertFalse($capabilitymanager->can_delete_post($user, $discussion, $post));
769
770 $this->give_capability('mod/forum:deleteownpost');
771 $this->assertTrue($capabilitymanager->can_delete_post($user, $discussion, $post));
772
773 $this->give_capability('mod/forum:deleteanypost');
774 $CFG->maxeditingtime = 10;
775 $this->assertTrue($capabilitymanager->can_delete_post($user, $discussion, $post));
776 }
777
778 /**
779 * Test can_split_post.
15dc885a
AN
780 *
781 * @covers ::can_split_post
47d38303
RW
782 */
783 public function test_can_split_post() {
784 $this->resetAfterTest();
785
786 $forum = $this->create_forum();
787 $user = $this->user;
788 $discussion = $this->discussion;
789 $post = $this->post;
790 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
791
792 // Make the post a reply.
793 $post = $this->entityfactory->get_post_from_stdclass(
794 (object) array_merge((array) $this->postrecord, ['parent' => 5])
795 );
796
797 $this->prevent_capability('mod/forum:splitdiscussions');
798 $this->assertFalse($capabilitymanager->can_split_post($user, $discussion, $post));
799
800 $this->give_capability('mod/forum:splitdiscussions');
801 $this->assertTrue($capabilitymanager->can_split_post($user, $discussion, $post));
802
803 // Make the post have no parent.
804 $post = $this->entityfactory->get_post_from_stdclass(
805 (object) array_merge((array) $this->postrecord, ['parent' => 0])
806 );
807
808 $this->assertFalse($capabilitymanager->can_split_post($user, $discussion, $post));
809
810 $forum = $this->create_forum(['type' => 'single']);
811 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
812 // Make the post a reply.
813 $post = $this->entityfactory->get_post_from_stdclass(
814 (object) array_merge((array) $this->postrecord, ['parent' => 5])
815 );
816
817 // Can't split a single discussion forum.
818 $this->assertFalse($capabilitymanager->can_split_post($user, $discussion, $post));
15dc885a
AN
819
820 // Make the post a private reply.
821 $post = $this->entityfactory->get_post_from_stdclass(
822 (object) array_merge((array) $this->postrecord, ['parent' => 5, 'privatereplyto' => $user->id])
823 );
824
825 // Can't split at a private reply.
826 $this->assertFalse($capabilitymanager->can_split_post($user, $discussion, $post));
47d38303
RW
827 }
828
829 /**
830 * Test can_reply_to_post.
15dc885a
AN
831 *
832 * @covers ::can_reply_to_post
47d38303
RW
833 */
834 public function test_can_reply_to_post() {
835 $this->resetAfterTest();
836
837 $discussion = $this->discussion;
838 $user = $this->user;
839 $post = $this->post;
840
841 // Locked discussions.
842 $lockedforum = $this->create_forum(['lockdiscussionafter' => 1]);
843 $capabilitymanager = $this->managerfactory->get_capability_manager($lockedforum);
844
845 $this->give_capability('mod/forum:canoverridediscussionlock');
846 $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
847
848 $this->prevent_capability('mod/forum:canoverridediscussionlock');
849 $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
850
851 // News forum.
852 $newsforum = $this->create_forum(['type' => 'news']);
853 $capabilitymanager = $this->managerfactory->get_capability_manager($newsforum);
854
855 $this->give_capability('mod/forum:replynews');
856 $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
857
858 $this->prevent_capability('mod/forum:replynews');
859 $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
860
861 // General forum.
862 $forum = $this->create_forum();
863 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
864
865 $this->give_capability('mod/forum:replypost');
866 $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
867
868 $this->prevent_capability('mod/forum:replypost');
869 $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
870
871 // Forum in separate group mode.
872 $forumrecord = $this->getDataGenerator()->create_module(
873 'forum',
874 ['course' => $this->course->id, 'groupmode' => SEPARATEGROUPS]
875 );
876 $coursemodule = get_coursemodule_from_instance('forum', $forumrecord->id);
877 $context = context_module::instance($coursemodule->id);
878 $forum = $this->entityfactory->get_forum_from_stdclass(
879 $forumrecord,
880 $context,
881 $coursemodule,
882 $this->course
883 );
884 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
885
886 $this->give_capability('moodle/site:accessallgroups', $context);
887 $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
888
889 $this->prevent_capability('moodle/site:accessallgroups', $context);
890 $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
891
892 $group = $this->getDataGenerator()->create_group(['courseid' => $this->course->id]);
893 $discussion = $this->entityfactory->get_discussion_from_stdclass(
894 (object) array_merge((array) $this->discussionrecord, ['groupid' => $group->id])
895 );
896
897 $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
898
899 $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
900
901 $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
902
903 // Forum in visible group mode.
904 $forumrecord = $this->getDataGenerator()->create_module(
905 'forum',
906 ['course' => $this->course->id, 'groupmode' => VISIBLEGROUPS]
907 );
908 $coursemodule = get_coursemodule_from_instance('forum', $forumrecord->id);
909 $context = context_module::instance($coursemodule->id);
910 $forum = $this->entityfactory->get_forum_from_stdclass(
911 $forumrecord,
912 $context,
913 $coursemodule,
914 $this->course
915 );
916 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
917
918 $this->give_capability('moodle/site:accessallgroups', $context);
919 $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
920
921 $this->prevent_capability('moodle/site:accessallgroups', $context);
922 $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
923
924 $group = $this->getDataGenerator()->create_group(['courseid' => $this->course->id]);
925 $discussion = $this->entityfactory->get_discussion_from_stdclass(
926 (object) array_merge((array) $this->discussionrecord, ['groupid' => $group->id])
927 );
928
929 $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
930
931 $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
932
933 $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
15dc885a
AN
934
935 // Make the post a private reply.
936 $post = $this->entityfactory->get_post_from_stdclass(
937 (object) array_merge((array) $this->postrecord, ['parent' => 5, 'privatereplyto' => $user->id])
938 );
939
940 // Can't reply to a a private reply.
941 $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
942 }
943
944 /**
945 * Ensure that can_reply_privately_to_post works as expected.
946 *
947 * @covers ::can_reply_privately_to_post
948 */
949 public function test_can_reply_privately_to_post() {
950 $this->resetAfterTest();
951
952 $forum = $this->create_forum();
953 $discussion = $this->discussion;
954 $user = $this->user;
955 $post = $this->post;
956 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
957
958 // Without the capability, and with a standard post, it is not possible to reply privately.
959 $this->prevent_capability('mod/forum:postprivatereply');
960 $this->assertFalse($capabilitymanager->can_reply_privately_to_post($this->user, $post));
961
962 // With the capability, and a standard post, it is possible to reply privately.
963 $this->give_capability('mod/forum:postprivatereply');
964 $this->assertTrue($capabilitymanager->can_reply_privately_to_post($this->user, $post));
965
966 // Make the post a private reply.
967 $post = $this->entityfactory->get_post_from_stdclass(
968 (object) array_merge((array) $this->postrecord, ['parent' => 5, 'privatereplyto' => $user->id])
969 );
970
971 // Can't ever reply to a a private reply.
972 $this->assertFalse($capabilitymanager->can_reply_privately_to_post($user, $post));
973 }
974
975 /**
976 * Ensure that can_view_post works as expected.
977 *
978 * @covers ::can_view_post
979 */
980 public function test_can_view_post() {
981 $this->resetAfterTest();
982
983 $forum = $this->create_forum();
984 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
985
986 $user = $this->user;
987 $otheruser = $this->getDataGenerator()->create_user();
988
989 $discussion = $this->discussion;
990 $post = $this->post;
991
992 $privatepost = $this->entityfactory->get_post_from_stdclass(
993 (object) array_merge((array) $this->postrecord, ['parent' => $post->get_id(), 'privatereplyto' => $otheruser->id])
994 );
995
996 $this->prevent_capability('mod/forum:readprivatereplies');
997 $this->assertFalse($capabilitymanager->can_view_post($user, $discussion, $privatepost));
998 }
999
1000 /**
1001 * Ensure that can_view_post_shell considers private replies correctly.
1002 *
1003 * @covers ::can_view_post_shell
1004 */
1005 public function test_can_view_post_shell() {
1006 $this->resetAfterTest();
1007
1008 $forum = $this->create_forum();
1009 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1010
1011 $user = $this->user;
1012 $otheruser = $this->getDataGenerator()->create_user();
1013
1014 $discussion = $this->discussion;
1015 $post = $this->post;
1016 $privatepost = $this->entityfactory->get_post_from_stdclass(
1017 (object) array_merge((array) $this->postrecord, ['parent' => $post->get_id(), 'privatereplyto' => $otheruser->id])
1018 );
1019 $privateposttome = $this->entityfactory->get_post_from_stdclass(
1020 (object) array_merge((array) $this->postrecord, ['parent' => $post->get_id(), 'privatereplyto' => $user->id])
1021 );
1022
1023 // Can always view public replies, and those to me.
1024 $this->prevent_capability('mod/forum:readprivatereplies');
1025 $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $post));
1026 $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privateposttome));
1027 $this->assertFalse($capabilitymanager->can_view_post_shell($this->user, $privatepost));
1028
1029 $this->give_capability('mod/forum:readprivatereplies');
1030 $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $post));
1031 $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privateposttome));
1032 $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privatepost));
47d38303
RW
1033 }
1034
1035 /**
1036 * Test can_export_post.
15dc885a
AN
1037 *
1038 * @covers ::can_export_post
47d38303
RW
1039 */
1040 public function test_can_export_post() {
1041 global $CFG;
1042 $this->resetAfterTest();
1043
1044 $forum = $this->create_forum();
1045 $post = $this->post;
1046 $user = $this->user;
1047 $otheruser = $this->getDataGenerator()->create_user();
1048 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1049
1050 $this->getDataGenerator()->enrol_user($otheruser->id, $this->course->id, 'teacher');
1051
1052 $CFG->enableportfolios = true;
1053 $this->give_capability('mod/forum:exportpost');
1054
1055 $this->assertTrue($capabilitymanager->can_export_post($otheruser, $post));
1056
1057 $CFG->enableportfolios = false;
1058 $this->assertFalse($capabilitymanager->can_export_post($otheruser, $post));
1059
1060 $CFG->enableportfolios = true;
1061 $this->prevent_capability('mod/forum:exportpost');
1062 // Can't export another user's post without the exportpost capavility.
1063 $this->assertFalse($capabilitymanager->can_export_post($otheruser, $post));
1064
1065 $this->give_capability('mod/forum:exportownpost');
1066 // Can export own post with the exportownpost capability.
1067 $this->assertTrue($capabilitymanager->can_export_post($user, $post));
1068
1069 $this->prevent_capability('mod/forum:exportownpost');
1070 $this->assertFalse($capabilitymanager->can_export_post($user, $post));
1071 }
1072
1073 /**
1074 * Test can_view_participants.
15dc885a
AN
1075 *
1076 * @covers ::can_view_participants
47d38303
RW
1077 */
1078 public function test_can_view_participants() {
1079 $this->resetAfterTest();
1080
1081 $discussion = $this->discussion;
1082 $user = $this->user;
1083 $otheruser = $this->getDataGenerator()->create_user();
1084
1085 $this->getDataGenerator()->enrol_user($otheruser->id, $this->course->id, 'teacher');
1086
1087 $this->prevent_capability('moodle/course:viewparticipants');
1088 $this->prevent_capability('moodle/course:enrolreview');
1089 $this->prevent_capability('mod/forum:viewqandawithoutposting');
1090
1091 $forum = $this->create_forum();
1092 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1093
1094 $this->assertFalse($capabilitymanager->can_view_participants($otheruser, $discussion));
1095
1096 $this->give_capability('moodle/course:viewparticipants');
1097 $this->assertTrue($capabilitymanager->can_view_participants($otheruser, $discussion));
1098
1099 $this->prevent_capability('moodle/course:viewparticipants');
1100 $this->give_capability('moodle/course:enrolreview');
1101 $this->assertTrue($capabilitymanager->can_view_participants($otheruser, $discussion));
1102
1103 $forum = $this->create_forum(['type' => 'qanda']);
1104 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1105
1106 // Q and A forum requires the user to post before they can view it.
1107 $this->prevent_capability('mod/forum:viewqandawithoutposting');
1108 $this->assertFalse($capabilitymanager->can_view_participants($otheruser, $discussion));
1109
1110 // This user has posted.
1111 $this->assertTrue($capabilitymanager->can_view_participants($user, $discussion));
1112 }
1113
1114 /**
1115 * Test can_view_hidden_posts.
15dc885a
AN
1116 *
1117 * @covers ::can_view_hidden_posts
47d38303
RW
1118 */
1119 public function test_can_view_hidden_posts() {
1120 $this->resetAfterTest();
1121
1122 $forum = $this->create_forum();
1123 $user = $this->user;
1124 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1125
1126 $this->prevent_capability('mod/forum:viewhiddentimedposts');
1127 $this->assertFalse($capabilitymanager->can_view_hidden_posts($user));
1128
1129 $this->give_capability('mod/forum:viewhiddentimedposts');
1130 $this->assertTrue($capabilitymanager->can_view_hidden_posts($user));
1131 }
1132
1133 /**
1134 * Test can_manage_forum.
15dc885a
AN
1135 *
1136 * @covers ::can_manage_forum
47d38303
RW
1137 */
1138 public function test_can_manage_forum() {
1139 $this->resetAfterTest();
1140
1141 $forum = $this->create_forum();
1142 $user = $this->user;
1143 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1144
1145 $this->prevent_capability('moodle/course:manageactivities');
1146 $this->assertFalse($capabilitymanager->can_manage_forum($user));
1147
1148 $this->give_capability('moodle/course:manageactivities');
1149 $this->assertTrue($capabilitymanager->can_manage_forum($user));
1150 }
1151
1152 /**
1153 * Test can_manage_tags.
15dc885a
AN
1154 *
1155 * @covers ::can_manage_tags
47d38303
RW
1156 */
1157 public function test_can_manage_tags() {
1158 global $DB;
1159 $this->resetAfterTest();
1160
1161 $forum = $this->create_forum();
1162 $user = $this->user;
1163 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1164 $context = context_system::instance();
1165 $roleid = $DB->get_field('role', 'id', ['shortname' => 'user'], MUST_EXIST);
1166
1167 assign_capability('moodle/tag:manage', CAP_PREVENT, $roleid, $context->id, true);
1168 $this->assertFalse($capabilitymanager->can_manage_tags($user));
1169
1170 assign_capability('moodle/tag:manage', CAP_ALLOW, $roleid, $context->id, true);
1171 $this->assertTrue($capabilitymanager->can_manage_tags($user));
1172 }
15dc885a
AN
1173
1174 /**
1175 * Ensure that the can_view_any_private_reply works as expected.
1176 *
1177 * @covers ::can_view_any_private_reply
1178 */
1179 public function test_can_view_any_private_reply() {
1180 $this->resetAfterTest();
1181
1182 $forum = $this->create_forum();
1183 $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1184
1185 $this->give_capability('mod/forum:readprivatereplies');
1186 $this->assertTrue($capabilitymanager->can_view_any_private_reply($this->user));
1187 $this->prevent_capability('mod/forum:readprivatereplies');
1188 $this->assertFalse($capabilitymanager->can_view_any_private_reply($this->user));
1189 }
47d38303 1190}