Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   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  
 245      /**
 246       * Test can_access_all_groups.
 247       *
 248       * @covers ::can_access_all_groups
 249       */
 250      public function test_can_access_all_groups() {
 251          $this->resetAfterTest();
 252  
 253          $forum = $this->create_forum();
 254          $user = $this->user;
 255          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 256  
 257          $this->prevent_capability('moodle/site:accessallgroups');
 258          $this->assertFalse($capabilitymanager->can_access_all_groups($user));
 259  
 260          $this->give_capability('moodle/site:accessallgroups');
 261          $this->assertTrue($capabilitymanager->can_access_all_groups($user));
 262      }
 263  
 264      /**
 265       * Test can_access_group.
 266       *
 267       * @covers ::can_access_group
 268       */
 269      public function test_can_access_group() {
 270          $this->resetAfterTest();
 271  
 272          $forum = $this->create_forum();
 273          $user = $this->user;
 274          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 275          $group = $this->getDataGenerator()->create_group(['courseid' => $this->course->id]);
 276  
 277          $this->prevent_capability('moodle/site:accessallgroups');
 278          $this->assertFalse($capabilitymanager->can_access_group($user, $group->id));
 279  
 280          $this->give_capability('moodle/site:accessallgroups');
 281          $this->assertTrue($capabilitymanager->can_access_group($user, $group->id));
 282  
 283          $this->prevent_capability('moodle/site:accessallgroups');
 284          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
 285          $this->assertTrue($capabilitymanager->can_access_group($user, $group->id));
 286      }
 287  
 288      /**
 289       * Test can_view_discussions.
 290       *
 291       * @covers ::can_view_discussions
 292       */
 293      public function test_can_view_discussions() {
 294          $this->resetAfterTest();
 295  
 296          $forum = $this->create_forum();
 297          $user = $this->user;
 298          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 299  
 300          $this->prevent_capability('mod/forum:viewdiscussion');
 301          $this->assertFalse($capabilitymanager->can_view_discussions($user));
 302  
 303          $this->give_capability('mod/forum:viewdiscussion');
 304          $this->assertTrue($capabilitymanager->can_view_discussions($user));
 305      }
 306  
 307      /**
 308       * Test can_move_discussions.
 309       *
 310       * @covers ::can_move_discussions
 311       */
 312      public function test_can_move_discussions() {
 313          $this->resetAfterTest();
 314  
 315          $forum = $this->create_forum();
 316          $user = $this->user;
 317          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 318  
 319          $this->prevent_capability('mod/forum:movediscussions');
 320          $this->assertFalse($capabilitymanager->can_move_discussions($user));
 321  
 322          $this->give_capability('mod/forum:movediscussions');
 323          $this->assertTrue($capabilitymanager->can_move_discussions($user));
 324  
 325          $forum = $this->create_forum(['type' => 'single']);
 326          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 327  
 328          $this->assertFalse($capabilitymanager->can_move_discussions($user));
 329      }
 330  
 331      /**
 332       * Test can_pin_discussions.
 333       *
 334       * @covers ::can_pin_discussions
 335       */
 336      public function test_can_pin_discussions() {
 337          $this->resetAfterTest();
 338  
 339          $forum = $this->create_forum();
 340          $user = $this->user;
 341          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 342  
 343          $this->prevent_capability('mod/forum:pindiscussions');
 344          $this->assertFalse($capabilitymanager->can_pin_discussions($user));
 345  
 346          $this->give_capability('mod/forum:pindiscussions');
 347          $this->assertTrue($capabilitymanager->can_pin_discussions($user));
 348      }
 349  
 350      /**
 351       * Test can_split_discussions.
 352       *
 353       * @covers ::can_split_discussions
 354       */
 355      public function test_can_split_discussions() {
 356          $this->resetAfterTest();
 357  
 358          $forum = $this->create_forum();
 359          $user = $this->user;
 360          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 361  
 362          $this->prevent_capability('mod/forum:splitdiscussions');
 363          $this->assertFalse($capabilitymanager->can_split_discussions($user));
 364  
 365          $this->give_capability('mod/forum:splitdiscussions');
 366          $this->assertTrue($capabilitymanager->can_split_discussions($user));
 367  
 368          $forum = $this->create_forum(['type' => 'single']);
 369          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 370  
 371          $this->assertFalse($capabilitymanager->can_split_discussions($user));
 372      }
 373  
 374      /**
 375       * Test can_export_discussions.
 376       *
 377       * @covers ::can_export_discussions
 378       */
 379      public function test_can_export_discussions() {
 380          global $CFG;
 381          $this->resetAfterTest();
 382  
 383          $CFG->enableportfolios = true;
 384          $forum = $this->create_forum();
 385          $user = $this->user;
 386          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 387  
 388          $this->prevent_capability('mod/forum:exportdiscussion');
 389          $this->assertFalse($capabilitymanager->can_export_discussions($user));
 390  
 391          $this->give_capability('mod/forum:exportdiscussion');
 392          $this->assertTrue($capabilitymanager->can_export_discussions($user));
 393  
 394          $CFG->enableportfolios = false;
 395  
 396          $this->assertFalse($capabilitymanager->can_export_discussions($user));
 397      }
 398  
 399      /**
 400       * Test can_manually_control_post_read_status.
 401       *
 402       * @covers ::can_manually_control_post_read_status
 403       */
 404      public function test_can_manually_control_post_read_status() {
 405          global $CFG, $DB;
 406          $this->resetAfterTest();
 407  
 408          $CFG->forum_usermarksread = true;
 409          $forum = $this->create_forum();
 410          $user = $this->user;
 411          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 412          $cache = cache::make('mod_forum', 'forum_is_tracked');
 413  
 414          $user->trackforums = true;
 415          $prefid = $DB->insert_record('forum_track_prefs', ['userid' => $user->id, 'forumid' => $forum->get_id()]);
 416          $this->assertFalse($capabilitymanager->can_manually_control_post_read_status($user));
 417          $cache->purge();
 418  
 419          $DB->delete_records('forum_track_prefs', ['id' => $prefid]);
 420          $this->assertTrue($capabilitymanager->can_manually_control_post_read_status($user));
 421          $cache->purge();
 422  
 423          $CFG->forum_usermarksread = false;
 424  
 425          $this->assertFalse($capabilitymanager->can_manually_control_post_read_status($user));
 426      }
 427  
 428      /**
 429       * Test must_post_before_viewing_discussion.
 430       *
 431       * @covers ::must_post_before_viewing_discussion
 432       */
 433      public function test_must_post_before_viewing_discussion() {
 434          $this->resetAfterTest();
 435  
 436          $forum = $this->create_forum();
 437          $user = $this->user;
 438          $discussion = $this->discussion;
 439          $newuser = $this->getDataGenerator()->create_user();
 440          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 441          $this->getDataGenerator()->enrol_user($newuser->id, $this->course->id, 'teacher');
 442  
 443          $this->assertFalse($capabilitymanager->must_post_before_viewing_discussion($newuser, $discussion));
 444  
 445          $forum = $this->create_forum(['type' => 'qanda']);
 446          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 447  
 448          $this->prevent_capability('mod/forum:viewqandawithoutposting');
 449          $this->assertTrue($capabilitymanager->must_post_before_viewing_discussion($newuser, $discussion));
 450  
 451          $this->give_capability('mod/forum:viewqandawithoutposting');
 452          $this->assertFalse($capabilitymanager->must_post_before_viewing_discussion($newuser, $discussion));
 453  
 454          $this->prevent_capability('mod/forum:viewqandawithoutposting');
 455          // The pre-generated user has a pre-generated post in the disussion already.
 456          $this->assertFalse($capabilitymanager->must_post_before_viewing_discussion($user, $discussion));
 457      }
 458  
 459      /**
 460       * Test can_subscribe_to_discussion.
 461       *
 462       * @covers ::can_subscribe_to_discussion
 463       */
 464      public function test_can_subscribe_to_discussion() {
 465          $this->resetAfterTest();
 466  
 467          $forum = $this->create_forum();
 468          $discussion = $this->discussion;
 469          $guestuser = $this->getDataGenerator()->create_user();
 470          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 471  
 472          $this->assertFalse($capabilitymanager->can_subscribe_to_discussion($guestuser, $discussion));
 473          $this->assertTrue($capabilitymanager->can_subscribe_to_discussion($this->user, $discussion));
 474      }
 475  
 476      /**
 477       * Test can_move_discussion.
 478       *
 479       * @covers ::can_move_discussion
 480       */
 481      public function test_can_move_discussion() {
 482          $this->resetAfterTest();
 483  
 484          $forum = $this->create_forum();
 485          $discussion = $this->discussion;
 486          $user = $this->user;
 487          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 488  
 489          $this->prevent_capability('mod/forum:movediscussions');
 490          $this->assertFalse($capabilitymanager->can_move_discussion($user, $discussion));
 491  
 492          $this->give_capability('mod/forum:movediscussions');
 493          $this->assertTrue($capabilitymanager->can_move_discussion($user, $discussion));
 494  
 495          $forum = $this->create_forum(['type' => 'single']);
 496          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 497  
 498          $this->assertFalse($capabilitymanager->can_move_discussion($user, $discussion));
 499      }
 500  
 501      /**
 502       * Test can_pin_discussion.
 503       *
 504       * @covers ::can_pin_discussion
 505       */
 506      public function test_can_pin_discussion() {
 507          $this->resetAfterTest();
 508  
 509          $forum = $this->create_forum();
 510          $discussion = $this->discussion;
 511          $user = $this->user;
 512          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 513  
 514          $this->prevent_capability('mod/forum:pindiscussions');
 515          $this->assertFalse($capabilitymanager->can_pin_discussion($user, $discussion));
 516  
 517          $this->give_capability('mod/forum:pindiscussions');
 518          $this->assertTrue($capabilitymanager->can_pin_discussion($user, $discussion));
 519      }
 520  
 521      /**
 522       * Test can_post_in_discussion.
 523       *
 524       * @covers ::can_post_in_discussion
 525       */
 526      public function test_can_post_in_discussion() {
 527          $this->resetAfterTest();
 528  
 529          $discussion = $this->discussion;
 530          $user = $this->user;
 531  
 532          // Locked discussions.
 533          $lockedforum = $this->create_forum(['lockdiscussionafter' => 1]);
 534          $capabilitymanager = $this->managerfactory->get_capability_manager($lockedforum);
 535  
 536          $this->give_capability('mod/forum:canoverridediscussionlock');
 537          $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
 538  
 539          $this->prevent_capability('mod/forum:canoverridediscussionlock');
 540          $this->assertFalse($capabilitymanager->can_post_in_discussion($user, $discussion));
 541  
 542          // News forum.
 543          $newsforum = $this->create_forum(['type' => 'news']);
 544          $capabilitymanager = $this->managerfactory->get_capability_manager($newsforum);
 545  
 546          $this->give_capability('mod/forum:replynews');
 547          $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
 548  
 549          $this->prevent_capability('mod/forum:replynews');
 550          $this->assertFalse($capabilitymanager->can_post_in_discussion($user, $discussion));
 551  
 552          // General forum.
 553          $forum = $this->create_forum();
 554          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 555  
 556          $this->give_capability('mod/forum:replypost');
 557          $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
 558  
 559          $this->prevent_capability('mod/forum:replypost');
 560          $this->assertFalse($capabilitymanager->can_post_in_discussion($user, $discussion));
 561  
 562          // Forum in separate group mode.
 563          $forumrecord = $this->getDataGenerator()->create_module(
 564              'forum',
 565              ['course' => $this->course->id, 'groupmode' => SEPARATEGROUPS]
 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->assertFalse($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          // Forum in visible group mode.
 595          $forumrecord = $this->getDataGenerator()->create_module(
 596              'forum',
 597              ['course' => $this->course->id, 'groupmode' => VISIBLEGROUPS]
 598          );
 599          $coursemodule = get_coursemodule_from_instance('forum', $forumrecord->id);
 600          $context = context_module::instance($coursemodule->id);
 601          $forum = $this->entityfactory->get_forum_from_stdclass(
 602              $forumrecord,
 603              $context,
 604              $coursemodule,
 605              $this->course
 606          );
 607          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 608  
 609          $this->give_capability('moodle/site:accessallgroups', $context);
 610          $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
 611  
 612          $this->prevent_capability('moodle/site:accessallgroups', $context);
 613          $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
 614  
 615          $group = $this->getDataGenerator()->create_group(['courseid' => $this->course->id]);
 616          $discussion = $this->entityfactory->get_discussion_from_stdclass(
 617              (object) array_merge((array) $this->discussionrecord, ['groupid' => $group->id])
 618          );
 619  
 620          $this->assertFalse($capabilitymanager->can_post_in_discussion($user, $discussion));
 621  
 622          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
 623  
 624          $this->assertTrue($capabilitymanager->can_post_in_discussion($user, $discussion));
 625      }
 626  
 627      /**
 628       * Test can_edit_post.
 629       *
 630       * @covers ::can_edit_post
 631       */
 632      public function test_can_edit_post() {
 633          global $CFG;
 634  
 635          $this->resetAfterTest();
 636  
 637          $forum = $this->create_forum();
 638          $discussion = $this->discussion;
 639          // The generated post is created 100 seconds in the past.
 640          $post = $this->post;
 641          $user = $this->user;
 642          $otheruser = $this->getDataGenerator()->create_user();
 643          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 644  
 645          $this->prevent_capability('mod/forum:editanypost');
 646  
 647          // 200 seconds to edit.
 648          $CFG->maxeditingtime = 200;
 649          $this->assertTrue($capabilitymanager->can_edit_post($user, $discussion, $post));
 650  
 651          // 10 seconds to edit. No longer in editing time.
 652          $CFG->maxeditingtime = 10;
 653          $this->assertFalse($capabilitymanager->can_edit_post($user, $discussion, $post));
 654  
 655          // Can edit outside of editing time with this capability.
 656          $this->give_capability('mod/forum:editanypost');
 657          $this->assertTrue($capabilitymanager->can_edit_post($user, $discussion, $post));
 658  
 659          $CFG->maxeditingtime = 200;
 660          $this->assertFalse($capabilitymanager->can_edit_post($otheruser, $discussion, $post));
 661  
 662          $this->prevent_capability('mod/forum:editanypost');
 663  
 664          // News forum.
 665          $forum = $this->create_forum(['type' => 'news']);
 666          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 667          // Discussion hasn't started yet.
 668          $discussion = $this->entityfactory->get_discussion_from_stdclass(
 669              (object) array_merge((array) $this->discussionrecord, ['timestart' => time() + 100])
 670          );
 671  
 672          $this->assertFalse($capabilitymanager->can_edit_post($user, $discussion, $post));
 673  
 674          // Back to a discussion that has started.
 675          $discussion = $this->discussion;
 676          // Post is a reply.
 677          $post = $this->entityfactory->get_post_from_stdclass(
 678              (object) array_merge((array) $this->postrecord, ['parent' => 5])
 679          );
 680  
 681          $this->assertFalse($capabilitymanager->can_edit_post($user, $discussion, $post));
 682  
 683          $post = $this->post;
 684          // Discussion has started and post isn't a reply so we can edit it.
 685          $this->assertTrue($capabilitymanager->can_edit_post($user, $discussion, $post));
 686  
 687          // Single forum.
 688          $forum = $this->create_forum(['type' => 'single']);
 689          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 690  
 691          // Create a new post that definitely isn't the first post of the discussion.
 692          // Only the author, and a user with editanypost can edit it.
 693          $post = $this->entityfactory->get_post_from_stdclass(
 694              (object) array_merge((array) $this->postrecord, ['id' => $post->get_id() + 100])
 695          );
 696          $this->give_capability('mod/forum:editanypost');
 697          $this->assertTrue($capabilitymanager->can_edit_post($user, $discussion, $post));
 698          $this->assertFalse($capabilitymanager->can_edit_post($otheruser, $discussion, $post));
 699  
 700          $post = $this->post;
 701          // Set the first post of the discussion to our post.
 702          $discussion = $this->entityfactory->get_discussion_from_stdclass(
 703              (object) array_merge((array) $this->discussionrecord, ['firstpost' => $post->get_id()])
 704          );
 705  
 706          $this->prevent_capability('moodle/course:manageactivities');
 707          $this->assertFalse($capabilitymanager->can_edit_post($user, $discussion, $post));
 708  
 709          $this->give_capability('moodle/course:manageactivities');
 710          $this->assertTrue($capabilitymanager->can_edit_post($user, $discussion, $post));
 711      }
 712  
 713      /**
 714       * Test can_delete_post.
 715       *
 716       * @covers ::can_delete_post
 717       */
 718      public function test_can_delete_post() {
 719          global $CFG;
 720  
 721          $this->resetAfterTest();
 722  
 723          // Single forum.
 724          $forum = $this->create_forum(['type' => 'single']);
 725          // The generated post is created 100 seconds in the past.
 726          $post = $this->post;
 727          $user = $this->user;
 728          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 729  
 730          // Set the first post of the discussion to our post.
 731          $discussion = $this->entityfactory->get_discussion_from_stdclass(
 732              (object) array_merge((array) $this->discussionrecord, ['firstpost' => $post->get_id()])
 733          );
 734  
 735          // Can't delete the first post of a single discussion forum.
 736          $this->assertFalse($capabilitymanager->can_delete_post($user, $discussion, $post));
 737  
 738          // Set the first post of the discussion to something else.
 739          $discussion = $this->entityfactory->get_discussion_from_stdclass(
 740              (object) array_merge((array) $this->discussionrecord, ['firstpost' => $post->get_id() - 1])
 741          );
 742  
 743          $this->assertTrue($capabilitymanager->can_delete_post($user, $discussion, $post));
 744  
 745          // Back to a general forum.
 746          $forum = $this->create_forum();
 747          $this->prevent_capability('mod/forum:deleteanypost');
 748          $this->give_capability('mod/forum:deleteownpost');
 749          // 200 second editing time to make sure our post is still within it.
 750          $CFG->maxeditingtime = 200;
 751  
 752          // Make the post owned by someone else.
 753          $post = $this->entityfactory->get_post_from_stdclass(
 754              (object) array_merge((array) $this->postrecord, ['userid' => $user->id - 1])
 755          );
 756  
 757          // Can't delete someone else's post.
 758          $this->assertFalse($capabilitymanager->can_delete_post($user, $discussion, $post));
 759          // Back to our post.
 760          $post = $this->post;
 761  
 762          // Not in editing time.
 763          $CFG->maxeditingtime = 10;
 764          $this->assertFalse($capabilitymanager->can_delete_post($user, $discussion, $post));
 765  
 766          $CFG->maxeditingtime = 200;
 767          // Remove the capability to delete own post.
 768          $this->prevent_capability('mod/forum:deleteownpost');
 769          $this->assertFalse($capabilitymanager->can_delete_post($user, $discussion, $post));
 770  
 771          $this->give_capability('mod/forum:deleteownpost');
 772          $this->assertTrue($capabilitymanager->can_delete_post($user, $discussion, $post));
 773  
 774          $this->give_capability('mod/forum:deleteanypost');
 775          $CFG->maxeditingtime = 10;
 776          $this->assertTrue($capabilitymanager->can_delete_post($user, $discussion, $post));
 777      }
 778  
 779      /**
 780       * Test can_split_post.
 781       *
 782       * @covers ::can_split_post
 783       */
 784      public function test_can_split_post() {
 785          $this->resetAfterTest();
 786  
 787          $forum = $this->create_forum();
 788          $user = $this->user;
 789          $discussion = $this->discussion;
 790          $post = $this->post;
 791          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 792  
 793          // Make the post a reply.
 794          $post = $this->entityfactory->get_post_from_stdclass(
 795              (object) array_merge((array) $this->postrecord, ['parent' => 5])
 796          );
 797  
 798          $this->prevent_capability('mod/forum:splitdiscussions');
 799          $this->assertFalse($capabilitymanager->can_split_post($user, $discussion, $post));
 800  
 801          $this->give_capability('mod/forum:splitdiscussions');
 802          $this->assertTrue($capabilitymanager->can_split_post($user, $discussion, $post));
 803  
 804          // Make the post have no parent.
 805          $post = $this->entityfactory->get_post_from_stdclass(
 806              (object) array_merge((array) $this->postrecord, ['parent' => 0])
 807          );
 808  
 809          $this->assertFalse($capabilitymanager->can_split_post($user, $discussion, $post));
 810  
 811          $forum = $this->create_forum(['type' => 'single']);
 812          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 813          // Make the post a reply.
 814          $post = $this->entityfactory->get_post_from_stdclass(
 815              (object) array_merge((array) $this->postrecord, ['parent' => 5])
 816          );
 817  
 818          // Can't split a single discussion forum.
 819          $this->assertFalse($capabilitymanager->can_split_post($user, $discussion, $post));
 820  
 821          // Make the post a private reply.
 822          $post = $this->entityfactory->get_post_from_stdclass(
 823              (object) array_merge((array) $this->postrecord, ['parent' => 5, 'privatereplyto' => $user->id])
 824          );
 825  
 826          // Can't split at a private reply.
 827          $this->assertFalse($capabilitymanager->can_split_post($user, $discussion, $post));
 828      }
 829  
 830      /**
 831       * Test can_reply_to_post.
 832       *
 833       * @covers ::can_reply_to_post
 834       */
 835      public function test_can_reply_to_post() {
 836          $this->resetAfterTest();
 837  
 838          $discussion = $this->discussion;
 839          $user = $this->user;
 840          $post = $this->post;
 841  
 842          // Locked discussions.
 843          $lockedforum = $this->create_forum(['lockdiscussionafter' => 1]);
 844          $capabilitymanager = $this->managerfactory->get_capability_manager($lockedforum);
 845  
 846          $this->give_capability('mod/forum:canoverridediscussionlock');
 847          $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 848  
 849          $this->prevent_capability('mod/forum:canoverridediscussionlock');
 850          $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 851  
 852          // News forum.
 853          $newsforum = $this->create_forum(['type' => 'news']);
 854          $capabilitymanager = $this->managerfactory->get_capability_manager($newsforum);
 855  
 856          $this->give_capability('mod/forum:replynews');
 857          $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 858  
 859          $this->prevent_capability('mod/forum:replynews');
 860          $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 861  
 862          // General forum.
 863          $forum = $this->create_forum();
 864          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 865  
 866          $this->give_capability('mod/forum:replypost');
 867          $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 868  
 869          $this->prevent_capability('mod/forum:replypost');
 870          $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 871  
 872          // Forum in separate group mode.
 873          $forumrecord = $this->getDataGenerator()->create_module(
 874              'forum',
 875              ['course' => $this->course->id, 'groupmode' => SEPARATEGROUPS]
 876          );
 877          $coursemodule = get_coursemodule_from_instance('forum', $forumrecord->id);
 878          $context = context_module::instance($coursemodule->id);
 879          $forum = $this->entityfactory->get_forum_from_stdclass(
 880              $forumrecord,
 881              $context,
 882              $coursemodule,
 883              $this->course
 884          );
 885          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 886  
 887          $this->give_capability('moodle/site:accessallgroups', $context);
 888          $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 889  
 890          $this->prevent_capability('moodle/site:accessallgroups', $context);
 891          $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 892  
 893          $group = $this->getDataGenerator()->create_group(['courseid' => $this->course->id]);
 894          $discussion = $this->entityfactory->get_discussion_from_stdclass(
 895              (object) array_merge((array) $this->discussionrecord, ['groupid' => $group->id])
 896          );
 897  
 898          $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 899  
 900          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
 901  
 902          $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 903  
 904          // Forum in visible group mode.
 905          $forumrecord = $this->getDataGenerator()->create_module(
 906              'forum',
 907              ['course' => $this->course->id, 'groupmode' => VISIBLEGROUPS]
 908          );
 909          $coursemodule = get_coursemodule_from_instance('forum', $forumrecord->id);
 910          $context = context_module::instance($coursemodule->id);
 911          $forum = $this->entityfactory->get_forum_from_stdclass(
 912              $forumrecord,
 913              $context,
 914              $coursemodule,
 915              $this->course
 916          );
 917          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
 918  
 919          $this->give_capability('moodle/site:accessallgroups', $context);
 920          $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 921  
 922          $this->prevent_capability('moodle/site:accessallgroups', $context);
 923          $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 924  
 925          $group = $this->getDataGenerator()->create_group(['courseid' => $this->course->id]);
 926          $discussion = $this->entityfactory->get_discussion_from_stdclass(
 927              (object) array_merge((array) $this->discussionrecord, ['groupid' => $group->id])
 928          );
 929  
 930          $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 931  
 932          $this->getDataGenerator()->create_group_member(['userid' => $user->id, 'groupid' => $group->id]);
 933  
 934          $this->assertTrue($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 935  
 936          // Make the post a private reply.
 937          $post = $this->entityfactory->get_post_from_stdclass(
 938              (object) array_merge((array) $this->postrecord, ['parent' => 5, 'privatereplyto' => $user->id])
 939          );
 940  
 941          // Can't reply to a a private reply.
 942          $this->assertFalse($capabilitymanager->can_reply_to_post($user, $discussion, $post));
 943      }
 944  
 945      /**
 946       * Test for \mod_forum\local\managers\capability::can_reply_to_post() involving Q & A forums.
 947       */
 948      public function test_can_reply_to_post_in_qanda_forum() {
 949          global $CFG;
 950  
 951          $this->resetAfterTest();
 952  
 953          // Set max editing time to 10 seconds.
 954          $CFG->maxeditingtime = 10;
 955  
 956          $qandaforum = $this->create_forum(['type' => 'qanda']);
 957          $datagenerator = $this->getDataGenerator();
 958          $capabilitymanager = $this->managerfactory->get_capability_manager($qandaforum);
 959  
 960          // Student 1.
 961          $student1 = $datagenerator->create_user(['firstname' => 'S1']);
 962          $datagenerator->enrol_user($student1->id, $this->course->id, 'student');
 963          // Confirm Student 1 can reply to the question.
 964          $this->assertTrue($capabilitymanager->can_reply_to_post($student1, $this->discussion, $this->post));
 965  
 966          // Student 2.
 967          $student2 = $datagenerator->create_user(['firstname' => 'S2']);
 968          $datagenerator->enrol_user($student2->id, $this->course->id, 'student');
 969          // Confirm Student 2 can reply to the question.
 970          $this->assertTrue($capabilitymanager->can_reply_to_post($student2, $this->discussion, $this->post));
 971  
 972          // Reply to the question as student 1.
 973          $now = time();
 974          $options = ['parent' => $this->post->get_id(), 'created' => $now - 100];
 975          $student1post = $this->helper_post_to_discussion($this->forumrecord, $this->discussionrecord, $student1, $options);
 976          $student1postentity = $this->entityfactory->get_post_from_stdclass($student1post);
 977  
 978          // Confirm Student 2 cannot reply student 1's answer yet.
 979          $this->assertFalse($capabilitymanager->can_reply_to_post($student2, $this->discussion, $student1postentity));
 980  
 981          // Reply to the question as student 2.
 982          $this->helper_post_to_discussion($this->forumrecord, $this->discussionrecord, $student2, $options);
 983  
 984          // Reinitialise capability manager first to ensure we don't return cached values.
 985          $capabilitymanager = $this->managerfactory->get_capability_manager($qandaforum);
 986  
 987          // Confirm Student 2 can now reply to student 1's answer.
 988          $this->assertTrue($capabilitymanager->can_reply_to_post($student2, $this->discussion, $student1postentity));
 989      }
 990  
 991      /**
 992       * Ensure that can_reply_privately_to_post works as expected.
 993       *
 994       * @covers ::can_reply_privately_to_post
 995       */
 996      public function test_can_reply_privately_to_post() {
 997          $this->resetAfterTest();
 998  
 999          $forum = $this->create_forum();
1000          $discussion = $this->discussion;
1001          $user = $this->user;
1002          $post = $this->post;
1003          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1004  
1005          // Without the capability, and with a standard post, it is not possible to reply privately.
1006          $this->prevent_capability('mod/forum:postprivatereply');
1007          $this->assertFalse($capabilitymanager->can_reply_privately_to_post($this->user, $post));
1008  
1009          // With the capability, and a standard post, it is possible to reply privately.
1010          $this->give_capability('mod/forum:postprivatereply');
1011          $this->assertTrue($capabilitymanager->can_reply_privately_to_post($this->user, $post));
1012  
1013          // Make the post a private reply.
1014          $post = $this->entityfactory->get_post_from_stdclass(
1015              (object) array_merge((array) $this->postrecord, ['parent' => 5, 'privatereplyto' => $user->id])
1016          );
1017  
1018          // Can't ever reply to a a private reply.
1019          $this->assertFalse($capabilitymanager->can_reply_privately_to_post($user, $post));
1020      }
1021  
1022      /**
1023       * Ensure that can_view_post works as expected.
1024       *
1025       * @covers ::can_view_post
1026       */
1027      public function test_can_view_post() {
1028          $this->resetAfterTest();
1029  
1030          $forum = $this->create_forum();
1031          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1032  
1033          $user = $this->user;
1034          $otheruser = $this->getDataGenerator()->create_user();
1035  
1036          $discussion = $this->discussion;
1037          $post = $this->post;
1038  
1039          $privatepost = $this->entityfactory->get_post_from_stdclass(
1040              (object) array_merge((array) $this->postrecord, ['parent' => $post->get_id(), 'privatereplyto' => $otheruser->id])
1041          );
1042  
1043          $this->prevent_capability('mod/forum:readprivatereplies');
1044          $this->assertFalse($capabilitymanager->can_view_post($user, $discussion, $privatepost));
1045      }
1046  
1047      /**
1048       * Ensure that can_view_post_shell considers private replies correctly.
1049       *
1050       * @covers ::can_view_post_shell
1051       */
1052      public function test_can_view_post_shell() {
1053          $this->resetAfterTest();
1054  
1055          $forum = $this->create_forum();
1056          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1057  
1058          $user = $this->user;
1059          $otheruser = $this->getDataGenerator()->create_user();
1060  
1061          $discussion = $this->discussion;
1062          $post = $this->post;
1063          $privatepost = $this->entityfactory->get_post_from_stdclass(
1064              (object) array_merge((array) $this->postrecord, ['parent' => $post->get_id(), 'privatereplyto' => $otheruser->id])
1065          );
1066          $privateposttome = $this->entityfactory->get_post_from_stdclass(
1067              (object) array_merge((array) $this->postrecord, ['parent' => $post->get_id(), 'privatereplyto' => $user->id])
1068          );
1069  
1070          // Can always view public replies, and those to me.
1071          $this->prevent_capability('mod/forum:readprivatereplies');
1072          $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $post));
1073          $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privateposttome));
1074          $this->assertFalse($capabilitymanager->can_view_post_shell($this->user, $privatepost));
1075  
1076          $this->give_capability('mod/forum:readprivatereplies');
1077          $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $post));
1078          $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privateposttome));
1079          $this->assertTrue($capabilitymanager->can_view_post_shell($this->user, $privatepost));
1080      }
1081  
1082      /**
1083       * Test can_export_post.
1084       *
1085       * @covers ::can_export_post
1086       */
1087      public function test_can_export_post() {
1088          global $CFG;
1089          $this->resetAfterTest();
1090  
1091          $forum = $this->create_forum();
1092          $post = $this->post;
1093          $user = $this->user;
1094          $otheruser = $this->getDataGenerator()->create_user();
1095          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1096  
1097          $this->getDataGenerator()->enrol_user($otheruser->id, $this->course->id, 'teacher');
1098  
1099          $CFG->enableportfolios = true;
1100          $this->give_capability('mod/forum:exportpost');
1101  
1102          $this->assertTrue($capabilitymanager->can_export_post($otheruser, $post));
1103  
1104          $CFG->enableportfolios = false;
1105          $this->assertFalse($capabilitymanager->can_export_post($otheruser, $post));
1106  
1107          $CFG->enableportfolios = true;
1108          $this->prevent_capability('mod/forum:exportpost');
1109          // Can't export another user's post without the exportpost capavility.
1110          $this->assertFalse($capabilitymanager->can_export_post($otheruser, $post));
1111  
1112          $this->give_capability('mod/forum:exportownpost');
1113          // Can export own post with the exportownpost capability.
1114          $this->assertTrue($capabilitymanager->can_export_post($user, $post));
1115  
1116          $this->prevent_capability('mod/forum:exportownpost');
1117          $this->assertFalse($capabilitymanager->can_export_post($user, $post));
1118      }
1119  
1120      /**
1121       * Test can_view_participants.
1122       *
1123       * @covers ::can_view_participants
1124       */
1125      public function test_can_view_participants() {
1126          $this->resetAfterTest();
1127  
1128          $discussion = $this->discussion;
1129          $user = $this->user;
1130          $otheruser = $this->getDataGenerator()->create_user();
1131  
1132          $this->getDataGenerator()->enrol_user($otheruser->id, $this->course->id, 'teacher');
1133  
1134          $this->prevent_capability('moodle/course:viewparticipants');
1135          $this->prevent_capability('moodle/course:enrolreview');
1136          $this->prevent_capability('mod/forum:viewqandawithoutposting');
1137  
1138          $forum = $this->create_forum();
1139          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1140  
1141          $this->assertFalse($capabilitymanager->can_view_participants($otheruser, $discussion));
1142  
1143          $this->give_capability('moodle/course:viewparticipants');
1144          $this->assertTrue($capabilitymanager->can_view_participants($otheruser, $discussion));
1145  
1146          $this->prevent_capability('moodle/course:viewparticipants');
1147          $this->give_capability('moodle/course:enrolreview');
1148          $this->assertTrue($capabilitymanager->can_view_participants($otheruser, $discussion));
1149  
1150          $forum = $this->create_forum(['type' => 'qanda']);
1151          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1152  
1153          // Q and A forum requires the user to post before they can view it.
1154          $this->prevent_capability('mod/forum:viewqandawithoutposting');
1155          $this->assertFalse($capabilitymanager->can_view_participants($otheruser, $discussion));
1156  
1157          // This user has posted.
1158          $this->assertTrue($capabilitymanager->can_view_participants($user, $discussion));
1159      }
1160  
1161      /**
1162       * Test can_view_hidden_posts.
1163       *
1164       * @covers ::can_view_hidden_posts
1165       */
1166      public function test_can_view_hidden_posts() {
1167          $this->resetAfterTest();
1168  
1169          $forum = $this->create_forum();
1170          $user = $this->user;
1171          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1172  
1173          $this->prevent_capability('mod/forum:viewhiddentimedposts');
1174          $this->assertFalse($capabilitymanager->can_view_hidden_posts($user));
1175  
1176          $this->give_capability('mod/forum:viewhiddentimedposts');
1177          $this->assertTrue($capabilitymanager->can_view_hidden_posts($user));
1178      }
1179  
1180      /**
1181       * Test can_manage_forum.
1182       *
1183       * @covers ::can_manage_forum
1184       */
1185      public function test_can_manage_forum() {
1186          $this->resetAfterTest();
1187  
1188          $forum = $this->create_forum();
1189          $user = $this->user;
1190          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1191  
1192          $this->prevent_capability('moodle/course:manageactivities');
1193          $this->assertFalse($capabilitymanager->can_manage_forum($user));
1194  
1195          $this->give_capability('moodle/course:manageactivities');
1196          $this->assertTrue($capabilitymanager->can_manage_forum($user));
1197      }
1198  
1199      /**
1200       * Test can_manage_tags.
1201       *
1202       * @covers ::can_manage_tags
1203       */
1204      public function test_can_manage_tags() {
1205          global $DB;
1206          $this->resetAfterTest();
1207  
1208          $forum = $this->create_forum();
1209          $user = $this->user;
1210          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1211          $context = context_system::instance();
1212          $roleid = $DB->get_field('role', 'id', ['shortname' => 'user'], MUST_EXIST);
1213  
1214          assign_capability('moodle/tag:manage', CAP_PREVENT, $roleid, $context->id, true);
1215          $this->assertFalse($capabilitymanager->can_manage_tags($user));
1216  
1217          assign_capability('moodle/tag:manage', CAP_ALLOW, $roleid, $context->id, true);
1218          $this->assertTrue($capabilitymanager->can_manage_tags($user));
1219      }
1220  
1221      /**
1222       * Ensure that the can_view_any_private_reply works as expected.
1223       *
1224       * @covers ::can_view_any_private_reply
1225       */
1226      public function test_can_view_any_private_reply() {
1227          $this->resetAfterTest();
1228  
1229          $forum = $this->create_forum();
1230          $capabilitymanager = $this->managerfactory->get_capability_manager($forum);
1231  
1232          $this->give_capability('mod/forum:readprivatereplies');
1233          $this->assertTrue($capabilitymanager->can_view_any_private_reply($this->user));
1234          $this->prevent_capability('mod/forum:readprivatereplies');
1235          $this->assertFalse($capabilitymanager->can_view_any_private_reply($this->user));
1236      }
1237  
1238  
1239      /**
1240       * Test delete a post with ratings.
1241       */
1242      public function test_validate_delete_post_with_ratings() {
1243          global $DB;
1244          $this->resetAfterTest(true);
1245  
1246          // Setup test data.
1247          $course = $this->getDataGenerator()->create_course();
1248          $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
1249          $user = $this->getDataGenerator()->create_user();
1250          $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
1251          self::getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
1252  
1253          // Add a discussion.
1254          $record = new stdClass();
1255          $record->course = $course->id;
1256          $record->userid = $user->id;
1257          $record->forum = $forum->id;
1258          $record->created =
1259          $discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
1260  
1261          // Add rating.
1262          $post = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
1263          $post->totalscore = 80;
1264          $DB->update_record('forum_posts', $post);
1265  
1266          $vaultfactory = mod_forum\local\container::get_vault_factory();
1267          $forumvault = $vaultfactory->get_forum_vault();
1268          $discussionvault = $vaultfactory->get_discussion_vault();
1269          $postvault = $vaultfactory->get_post_vault();
1270  
1271          $postentity = $postvault->get_from_id($post->id);
1272          $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id());
1273          $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id());
1274          $capabilitymanager = $this->managerfactory->get_capability_manager($forumentity);
1275  
1276          $this->setUser($user);
1277          $this->expectExceptionMessage(get_string('couldnotdeleteratings', 'rating'));
1278          $capabilitymanager->validate_delete_post($user, $discussionentity, $postentity, false);
1279      }
1280  
1281      /**
1282       * Test delete a post with replies.
1283       */
1284      public function test_validate_delete_post_with_replies() {
1285          global $DB;
1286          $this->resetAfterTest(true);
1287  
1288          // Setup test data.
1289          $course = $this->getDataGenerator()->create_course();
1290          $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
1291          $user = $this->getDataGenerator()->create_user();
1292          $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
1293          self::getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
1294  
1295          // Add a discussion.
1296          $record = new stdClass();
1297          $record->course = $course->id;
1298          $record->userid = $user->id;
1299          $record->forum = $forum->id;
1300          $record->created =
1301          $discussion = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
1302  
1303          $parentpost = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
1304          // Add a post.
1305          $record = new stdClass();
1306          $record->course = $course->id;
1307          $record->userid = $user->id;
1308          $record->forum = $forum->id;
1309          $record->discussion = $discussion->id;
1310          $record->parent = $parentpost->id;
1311          $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
1312  
1313          $vaultfactory = mod_forum\local\container::get_vault_factory();
1314          $forumvault = $vaultfactory->get_forum_vault();
1315          $discussionvault = $vaultfactory->get_discussion_vault();
1316          $postvault = $vaultfactory->get_post_vault();
1317  
1318          $postentity = $postvault->get_from_id($parentpost->id);
1319          $discussionentity = $discussionvault->get_from_id($postentity->get_discussion_id());
1320          $forumentity = $forumvault->get_from_id($discussionentity->get_forum_id());
1321          $capabilitymanager = $this->managerfactory->get_capability_manager($forumentity);
1322  
1323          $this->setUser($user);
1324          // Get reply count.
1325          $replycount = $postvault->get_reply_count_for_post_id_in_discussion_id(
1326              $user, $postentity->get_id(), $discussionentity->get_id(), true);
1327          $this->expectExceptionMessage(get_string('couldnotdeletereplies', 'forum'));
1328          $capabilitymanager->validate_delete_post($user, $discussionentity, $postentity, $replycount);
1329      }
1330  
1331  }