Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
  • Differences Between: [Versions 310 and 311] [Versions 37 and 311] [Versions 38 and 311] [Versions 39 and 311]

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