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