Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

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

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