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 post vault 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  require_once (__DIR__ . '/generator_trait.php');
  28  
  29  /**
  30   * The post vault 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\vaults\post
  36   */
  37  class mod_forum_vaults_post_testcase extends advanced_testcase {
  38      // Make use of the test generator trait.
  39      use mod_forum_tests_generator_trait;
  40  
  41      /** @var \mod_forum\local\vaults\post */
  42      private $vault;
  43  
  44      /**
  45       * Set up function for tests.
  46       */
  47      public function setUp(): void {
  48          $vaultfactory = \mod_forum\local\container::get_vault_factory();
  49          $this->vault = $vaultfactory->get_post_vault();
  50      }
  51  
  52      /**
  53       * Teardown for all tests.
  54       */
  55      public function tearDown(): void {
  56          unset($this->vault);
  57      }
  58  
  59      /**
  60       * Test get_from_id.
  61       */
  62      public function test_get_from_id() {
  63          $this->resetAfterTest();
  64  
  65          $datagenerator = $this->getDataGenerator();
  66          $user = $datagenerator->create_user();
  67          $course = $datagenerator->create_course();
  68          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
  69          [$discussion, $post] = $this->helper_post_to_forum($forum, $user);
  70  
  71          $postentity = $this->vault->get_from_id($post->id);
  72  
  73          $this->assertEquals($post->id, $postentity->get_id());
  74      }
  75  
  76      /**
  77       * Test get_from_discussion_id.
  78       *
  79       * @covers ::get_from_discussion_id
  80       */
  81      public function test_get_from_discussion_id() {
  82          $this->resetAfterTest();
  83  
  84          $datagenerator = $this->getDataGenerator();
  85          $user = $datagenerator->create_user();
  86          $course = $datagenerator->create_course();
  87          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
  88          [$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
  89          $post2 = $this->helper_reply_to_post($post1, $user);
  90          $post3 = $this->helper_reply_to_post($post1, $user);
  91          [$discussion2, $post4] = $this->helper_post_to_forum($forum, $user);
  92  
  93          $entities = array_values($this->vault->get_from_discussion_id($user, $discussion1->id, false));
  94  
  95          $this->assertCount(3, $entities);
  96          $this->assertEquals($post1->id, $entities[0]->get_id());
  97          $this->assertEquals($post2->id, $entities[1]->get_id());
  98          $this->assertEquals($post3->id, $entities[2]->get_id());
  99  
 100          $entities = array_values($this->vault->get_from_discussion_id($user, $discussion1->id + 1000, false));
 101          $this->assertCount(0, $entities);
 102      }
 103  
 104      /**
 105       * Ensure that selecting posts in a discussion only returns posts that the user can see, when considering private
 106       * replies.
 107       *
 108       * @covers ::get_from_discussion_id
 109       */
 110      public function test_get_from_discussion_id_private_replies() {
 111          $this->resetAfterTest();
 112  
 113          $course = $this->getDataGenerator()->create_course();
 114          $forum = $this->getDataGenerator()->create_module('forum', [
 115              'course' => $course->id,
 116          ]);
 117  
 118          [$student, $otherstudent] = $this->helper_create_users($course, 2, 'student');
 119          [$teacher, $otherteacher] = $this->helper_create_users($course, 2, 'teacher');
 120          [$discussion, $post] = $this->helper_post_to_forum($forum, $teacher);
 121          $reply = $this->helper_post_to_discussion($forum, $discussion, $teacher, [
 122                  'privatereplyto' => $student->id,
 123              ]);
 124  
 125          // The user is the author.
 126          $entities = array_values($this->vault->get_from_discussion_id($teacher, $discussion->id, true));
 127          $this->assertCount(2, $entities);
 128          $this->assertEquals($post->id, $entities[0]->get_id());
 129          $this->assertEquals($reply->id, $entities[1]->get_id());
 130  
 131          // The user is the intended recipient.
 132          $entities = array_values($this->vault->get_from_discussion_id($student, $discussion->id, false));
 133          $this->assertCount(2, $entities);
 134          $this->assertEquals($post->id, $entities[0]->get_id());
 135          $this->assertEquals($reply->id, $entities[1]->get_id());
 136  
 137          // The user is another teacher..
 138          $entities = array_values($this->vault->get_from_discussion_id($otherteacher, $discussion->id, true));
 139          $this->assertCount(2, $entities);
 140          $this->assertEquals($post->id, $entities[0]->get_id());
 141          $this->assertEquals($reply->id, $entities[1]->get_id());
 142  
 143          // The user is a different student.
 144          $entities = array_values($this->vault->get_from_discussion_id($otherstudent, $discussion->id, false));
 145          $this->assertCount(1, $entities);
 146          $this->assertEquals($post->id, $entities[0]->get_id());
 147      }
 148  
 149      /**
 150       * Test get_from_discussion_ids when no discussion ids were provided.
 151       *
 152       * @covers ::get_from_discussion_ids
 153       */
 154      public function test_get_from_discussion_ids_empty() {
 155          $this->resetAfterTest();
 156  
 157          $datagenerator = $this->getDataGenerator();
 158          $user = $datagenerator->create_user();
 159          $course = $datagenerator->create_course();
 160          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 161  
 162          $this->assertEquals([], $this->vault->get_from_discussion_ids($user, [], false));
 163      }
 164  
 165      /**
 166       * Test get_from_discussion_ids.
 167       *
 168       * @covers ::get_from_discussion_ids
 169       */
 170      public function test_get_from_discussion_ids() {
 171          $this->resetAfterTest();
 172  
 173          $datagenerator = $this->getDataGenerator();
 174          $user = $datagenerator->create_user();
 175          $course = $datagenerator->create_course();
 176          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 177          [$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
 178          $post2 = $this->helper_reply_to_post($post1, $user);
 179          $post3 = $this->helper_reply_to_post($post1, $user);
 180          [$discussion2, $post4] = $this->helper_post_to_forum($forum, $user);
 181  
 182          $entities = $this->vault->get_from_discussion_ids($user, [$discussion1->id], false);
 183          $this->assertCount(3, $entities);
 184          $this->assertArrayHasKey($post1->id, $entities); // Order is not guaranteed, so just verify element existence.
 185          $this->assertArrayHasKey($post2->id, $entities);
 186          $this->assertArrayHasKey($post3->id, $entities);
 187  
 188          $entities = $this->vault->get_from_discussion_ids($user, [$discussion1->id, $discussion2->id], false);
 189          $this->assertCount(4, $entities);
 190          $this->assertArrayHasKey($post1->id, $entities); // Order is not guaranteed, so just verify element existence.
 191          $this->assertArrayHasKey($post2->id, $entities);
 192          $this->assertArrayHasKey($post3->id, $entities);
 193          $this->assertArrayHasKey($post4->id, $entities);
 194  
 195          // Test ordering by id descending.
 196          $entities = $this->vault->get_from_discussion_ids($user, [$discussion1->id, $discussion2->id], false, 'id DESC');
 197          $this->assertEquals($post4->id, array_values($entities)[0]->get_id());
 198          $this->assertEquals($post3->id, array_values($entities)[1]->get_id());
 199          $this->assertEquals($post2->id, array_values($entities)[2]->get_id());
 200          $this->assertEquals($post1->id, array_values($entities)[3]->get_id());
 201  
 202          // Test ordering by id ascending.
 203          $entities = $this->vault->get_from_discussion_ids($user, [$discussion1->id, $discussion2->id], false, 'id ASC');
 204          $this->assertEquals($post1->id, array_values($entities)[0]->get_id());
 205          $this->assertEquals($post2->id, array_values($entities)[1]->get_id());
 206          $this->assertEquals($post3->id, array_values($entities)[2]->get_id());
 207          $this->assertEquals($post4->id, array_values($entities)[3]->get_id());
 208      }
 209  
 210      /**
 211       * Ensure that selecting posts in a discussion only returns posts that the user can see, when considering private
 212       * replies.
 213       *
 214       * @covers ::get_from_discussion_ids
 215       */
 216      public function test_get_from_discussion_ids_private_replies() {
 217          $this->resetAfterTest();
 218  
 219          $course = $this->getDataGenerator()->create_course();
 220          $forum = $this->getDataGenerator()->create_module('forum', [
 221              'course' => $course->id,
 222          ]);
 223  
 224          [$student, $otherstudent] = $this->helper_create_users($course, 2, 'student');
 225          [$teacher, $otherteacher] = $this->helper_create_users($course, 2, 'teacher');
 226  
 227          // Create the posts structure below.
 228          // Forum:
 229          // -> Post (student 1)
 230          // ---> Post private reply (teacher 1)
 231          // -> Otherpost (teacher 1)
 232          // ---> Otherpost private reply (teacher 2)
 233          // ---> Otherpost reply (student 1)
 234          // ----> Otherpost reply private reply (teacher 1).
 235          [$discussion, $post] = $this->helper_post_to_forum($forum, $student);
 236          $postprivatereply = $this->helper_reply_to_post($post, $teacher, [
 237              'privatereplyto' => $student->id
 238          ]);
 239          [$otherdiscussion, $otherpost] = $this->helper_post_to_forum($forum, $teacher);
 240          $otherpostprivatereply = $this->helper_reply_to_post($otherpost, $otherteacher, [
 241              'privatereplyto' => $teacher->id,
 242          ]);
 243          $otherpostreply = $this->helper_reply_to_post($otherpost, $student);
 244          $otherpostreplyprivatereply = $this->helper_reply_to_post($otherpostreply, $teacher, [
 245              'privatereplyto' => $student->id
 246          ]);
 247  
 248          // Teacher 1. Request all posts from the vault, telling the vault that the teacher CAN see private replies made by anyone.
 249          $entities = $this->vault->get_from_discussion_ids($teacher, [$discussion->id, $otherdiscussion->id], true);
 250          $this->assertCount(6, $entities);
 251          $this->assertArrayHasKey($post->id, $entities); // Order is not guaranteed, so just verify element existence.
 252          $this->assertArrayHasKey($postprivatereply->id, $entities);
 253          $this->assertArrayHasKey($otherpost->id, $entities);
 254          $this->assertArrayHasKey($otherpostprivatereply->id, $entities);
 255          $this->assertArrayHasKey($otherpostreply->id, $entities);
 256          $this->assertArrayHasKey($otherpostreplyprivatereply->id, $entities);
 257  
 258          // Student 1. Request all posts from the vault, telling the vault that the student CAN'T see private replies made by anyone.
 259          // Teacher2's private reply to otherpost is omitted.
 260          $entities = $this->vault->get_from_discussion_ids($student, [$discussion->id, $otherdiscussion->id], false);
 261          $this->assertCount(5, $entities);
 262          $this->assertArrayHasKey($post->id, $entities); // Order is not guaranteed, so just verify element existence.
 263          $this->assertArrayHasKey($postprivatereply->id, $entities);
 264          $this->assertArrayHasKey($otherpost->id, $entities);
 265          $this->assertArrayHasKey($otherpostreply->id, $entities);
 266          $this->assertArrayHasKey($otherpostreplyprivatereply->id, $entities);
 267  
 268          // Student 1. Request all posts from the vault, telling the vault that student CAN see all private replies made.
 269          // The private reply made by teacher 2 to otherpost is now included.
 270          $entities = $this->vault->get_from_discussion_ids($student, [$discussion->id, $otherdiscussion->id], true);
 271          $this->assertCount(6, $entities);
 272          $this->assertArrayHasKey($post->id, $entities); // Order is not guaranteed, so just verify element existence.
 273          $this->assertArrayHasKey($postprivatereply->id, $entities);
 274          $this->assertArrayHasKey($otherpost->id, $entities);
 275          $this->assertArrayHasKey($otherpostprivatereply->id, $entities);
 276          $this->assertArrayHasKey($otherpostreply->id, $entities);
 277          $this->assertArrayHasKey($otherpostreplyprivatereply->id, $entities);
 278  
 279          // Teacher 2. Request all posts from the vault, telling the vault that teacher2 CAN see all private replies made.
 280          $entities = $this->vault->get_from_discussion_ids($otherteacher, [$discussion->id, $otherdiscussion->id], true);
 281          $this->assertCount(6, $entities);
 282          $this->assertArrayHasKey($post->id, $entities); // Order is not guaranteed, so just verify element existence.
 283          $this->assertArrayHasKey($postprivatereply->id, $entities);
 284          $this->assertArrayHasKey($otherpost->id, $entities);
 285          $this->assertArrayHasKey($otherpostprivatereply->id, $entities);
 286          $this->assertArrayHasKey($otherpostreply->id, $entities);
 287          $this->assertArrayHasKey($otherpostreplyprivatereply->id, $entities);
 288  
 289          // Teacher 2. Request all posts from the vault, telling the vault that teacher2 CANNOT see all private replies made.
 290          // The private replies not relating to teacher 2 directly are omitted.
 291          $entities = $this->vault->get_from_discussion_ids($otherteacher, [$discussion->id, $otherdiscussion->id], false);
 292          $this->assertCount(4, $entities);
 293          $this->assertArrayHasKey($post->id, $entities); // Order is not guaranteed, so just verify element existence.
 294          $this->assertArrayHasKey($otherpost->id, $entities);
 295          $this->assertArrayHasKey($otherpostprivatereply->id, $entities);
 296          $this->assertArrayHasKey($otherpostreply->id, $entities);
 297  
 298          // Student 2. Request all posts from the vault, telling the vault that student2 CAN'T see all private replies made.
 299          // All private replies are omitted, as none relate to student2.
 300          $entities = $this->vault->get_from_discussion_ids($otherstudent, [$discussion->id, $otherdiscussion->id], false);
 301          $this->assertCount(3, $entities);
 302          $this->assertArrayHasKey($post->id, $entities); // Order is not guaranteed, so just verify element existence.
 303          $this->assertArrayHasKey($otherpost->id, $entities);
 304          $this->assertArrayHasKey($otherpostreply->id, $entities);
 305      }
 306  
 307      /**
 308       * Test get_replies_to_post.
 309       *
 310       * @covers ::get_replies_to_post
 311       */
 312      public function test_get_replies_to_post() {
 313          $this->resetAfterTest();
 314  
 315          $datagenerator = $this->getDataGenerator();
 316          $forumgenerator = $datagenerator->get_plugin_generator('mod_forum');
 317          $user = $datagenerator->create_user();
 318          $course = $datagenerator->create_course();
 319          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 320          [$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
 321          // Create a post with the same created time as the parent post to ensure
 322          // we've covered every possible scenario.
 323          $post2 = $forumgenerator->create_post((object) [
 324              'discussion' => $post1->discussion,
 325              'parent' => $post1->id,
 326              'userid' => $user->id,
 327              'mailnow' => 1,
 328              'subject' => 'Some subject',
 329              'created' => $post1->created
 330          ]);
 331          $post3 = $this->helper_reply_to_post($post1, $user);
 332          $post4 = $this->helper_reply_to_post($post2, $user);
 333          [$discussion2, $post5] = $this->helper_post_to_forum($forum, $user);
 334  
 335          $entityfactory = \mod_forum\local\container::get_entity_factory();
 336          $post1 = $entityfactory->get_post_from_stdclass($post1);
 337          $post2 = $entityfactory->get_post_from_stdclass($post2);
 338          $post3 = $entityfactory->get_post_from_stdclass($post3);
 339          $post4 = $entityfactory->get_post_from_stdclass($post4);
 340  
 341          $entities = $this->vault->get_replies_to_post($user, $post1, false);
 342          $this->assertCount(3, $entities);
 343          $this->assertEquals($post2->get_id(), $entities[0]->get_id());
 344          $this->assertEquals($post3->get_id(), $entities[1]->get_id());
 345          $this->assertEquals($post4->get_id(), $entities[2]->get_id());
 346  
 347          $entities = $this->vault->get_replies_to_post($user, $post2, false);
 348          $this->assertCount(1, $entities);
 349          $this->assertEquals($post4->get_id(), $entities[0]->get_id());
 350  
 351          $entities = $this->vault->get_replies_to_post($user, $post3, false);
 352          $this->assertCount(0, $entities);
 353      }
 354  
 355      /**
 356       * Test get_replies_to_post with private replies.
 357       *
 358       * @covers ::get_replies_to_post
 359       */
 360      public function test_get_replies_to_post_private_replies() {
 361          $this->resetAfterTest();
 362  
 363          $course = $this->getDataGenerator()->create_course();
 364          $forum = $this->getDataGenerator()->create_module('forum', [
 365              'course' => $course->id,
 366          ]);
 367  
 368          // Generate a structure:
 369          // Initial post p [student]
 370          // -> Reply pa [otherstudent]
 371          // ---> Reply paa [student]
 372          // ---> Private Reply pab [teacher]
 373          // -> Private Reply pb [teacher]
 374          // -> Reply pc [otherstudent]
 375          // ---> Reply pca [student]
 376          // -----> Reply pcaa [otherstudent]
 377          // -------> Private Reply pcaaa [teacher].
 378  
 379          [$student, $otherstudent] = $this->helper_create_users($course, 2, 'student');
 380          [$teacher, $otherteacher] = $this->helper_create_users($course, 2, 'teacher');
 381  
 382          [$discussion, $p] = $this->helper_post_to_forum($forum, $student);
 383  
 384          $pa = $this->helper_reply_to_post($p, $otherstudent);
 385          $paa = $this->helper_reply_to_post($pa, $student);
 386          $pab = $this->helper_reply_to_post($pa, $teacher, ['privatereplyto' => $otherstudent->id]);
 387  
 388          $pb = $this->helper_reply_to_post($p, $teacher, ['privatereplyto' => $student->id]);
 389  
 390          $pc = $this->helper_reply_to_post($p, $otherteacher);
 391          $pca = $this->helper_reply_to_post($pc, $student);
 392          $pcaa = $this->helper_reply_to_post($pca, $otherstudent);
 393          $pcaaa = $this->helper_reply_to_post($pcaa, $teacher, ['privatereplyto' => $otherstudent->id]);
 394  
 395          $entityfactory = \mod_forum\local\container::get_entity_factory();
 396          $ep = $entityfactory->get_post_from_stdclass($p);
 397          $epa = $entityfactory->get_post_from_stdclass($pa);
 398          $epaa = $entityfactory->get_post_from_stdclass($paa);
 399          $epab = $entityfactory->get_post_from_stdclass($pab);
 400          $epb = $entityfactory->get_post_from_stdclass($pb);
 401          $epc = $entityfactory->get_post_from_stdclass($pc);
 402          $epca = $entityfactory->get_post_from_stdclass($pca);
 403          $epcaa = $entityfactory->get_post_from_stdclass($pcaa);
 404          $epcaaa = $entityfactory->get_post_from_stdclass($pcaaa);
 405  
 406          // As `student`, you should see all public posts, plus all private replies intended for you.
 407          $entities = $this->vault->get_replies_to_post($student, $ep, false);
 408          $this->assertCount(6, $entities);
 409          $this->assertEquals($epa->get_id(), $entities[0]->get_id());
 410          $this->assertEquals($epaa->get_id(), $entities[1]->get_id());
 411          $this->assertEquals($epb->get_id(), $entities[2]->get_id());
 412          $this->assertEquals($epc->get_id(), $entities[3]->get_id());
 413          $this->assertEquals($epca->get_id(), $entities[4]->get_id());
 414          $this->assertEquals($epcaa->get_id(), $entities[5]->get_id());
 415  
 416          $entities = $this->vault->get_replies_to_post($student, $epa, false);
 417          $this->assertCount(1, $entities);
 418          $this->assertEquals($epaa->get_id(), $entities[0]->get_id());
 419  
 420          $this->assertEmpty($this->vault->get_replies_to_post($student, $epaa, false));
 421          $this->assertEmpty($this->vault->get_replies_to_post($student, $epab, false));
 422          $this->assertEmpty($this->vault->get_replies_to_post($student, $epb, false));
 423          $this->assertEmpty($this->vault->get_replies_to_post($student, $epcaa, false));
 424          $this->assertEmpty($this->vault->get_replies_to_post($student, $epcaaa, false));
 425  
 426          $entities = $this->vault->get_replies_to_post($student, $epc, false);
 427          $this->assertCount(2, $entities);
 428          $this->assertEquals($epca->get_id(), $entities[0]->get_id());
 429          $this->assertEquals($epcaa->get_id(), $entities[1]->get_id());
 430  
 431          // As `otherstudent`, you should see all public posts, plus all private replies intended for you.
 432          $entities = $this->vault->get_replies_to_post($otherstudent, $ep, false);
 433          $this->assertCount(7, $entities);
 434          $this->assertEquals($epa->get_id(), $entities[0]->get_id());
 435          $this->assertEquals($epaa->get_id(), $entities[1]->get_id());
 436          $this->assertEquals($epab->get_id(), $entities[2]->get_id());
 437          $this->assertEquals($epc->get_id(), $entities[3]->get_id());
 438          $this->assertEquals($epca->get_id(), $entities[4]->get_id());
 439          $this->assertEquals($epcaa->get_id(), $entities[5]->get_id());
 440          $this->assertEquals($epcaaa->get_id(), $entities[6]->get_id());
 441  
 442          $entities = $this->vault->get_replies_to_post($otherstudent, $epa, false);
 443          $this->assertCount(2, $entities);
 444          $this->assertEquals($epaa->get_id(), $entities[0]->get_id());
 445          $this->assertEquals($epab->get_id(), $entities[1]->get_id());
 446  
 447          $this->assertEmpty($this->vault->get_replies_to_post($otherstudent, $epaa, false));
 448          $this->assertEmpty($this->vault->get_replies_to_post($otherstudent, $epab, false));
 449          $this->assertEmpty($this->vault->get_replies_to_post($otherstudent, $epb, false));
 450          $this->assertEmpty($this->vault->get_replies_to_post($otherstudent, $epcaaa, false));
 451  
 452          $entities = $this->vault->get_replies_to_post($otherstudent, $epc, false);
 453          $this->assertCount(3, $entities);
 454          $this->assertEquals($epca->get_id(), $entities[0]->get_id());
 455          $this->assertEquals($epcaa->get_id(), $entities[1]->get_id());
 456          $this->assertEquals($epcaaa->get_id(), $entities[2]->get_id());
 457  
 458          // The teacher who authored the private replies can see all.
 459          $entities = $this->vault->get_replies_to_post($teacher, $ep, true);
 460          $this->assertCount(8, $entities);
 461          $this->assertEquals($epa->get_id(), $entities[0]->get_id());
 462          $this->assertEquals($epaa->get_id(), $entities[1]->get_id());
 463          $this->assertEquals($epab->get_id(), $entities[2]->get_id());
 464          $this->assertEquals($epb->get_id(), $entities[3]->get_id());
 465          $this->assertEquals($epc->get_id(), $entities[4]->get_id());
 466          $this->assertEquals($epca->get_id(), $entities[5]->get_id());
 467          $this->assertEquals($epcaa->get_id(), $entities[6]->get_id());
 468          $this->assertEquals($epcaaa->get_id(), $entities[7]->get_id());
 469  
 470          $entities = $this->vault->get_replies_to_post($teacher, $epa, true);
 471          $this->assertCount(2, $entities);
 472          $this->assertEquals($epaa->get_id(), $entities[0]->get_id());
 473          $this->assertEquals($epab->get_id(), $entities[1]->get_id());
 474  
 475          $this->assertEmpty($this->vault->get_replies_to_post($teacher, $epaa, true));
 476          $this->assertEmpty($this->vault->get_replies_to_post($teacher, $epab, true));
 477          $this->assertEmpty($this->vault->get_replies_to_post($teacher, $epb, true));
 478          $this->assertEmpty($this->vault->get_replies_to_post($teacher, $epcaaa, true));
 479  
 480          $entities = $this->vault->get_replies_to_post($teacher, $epc, true);
 481          $this->assertCount(3, $entities);
 482          $this->assertEquals($epca->get_id(), $entities[0]->get_id());
 483          $this->assertEquals($epcaa->get_id(), $entities[1]->get_id());
 484          $this->assertEquals($epcaaa->get_id(), $entities[2]->get_id());
 485  
 486          // Any other teacher can also see all.
 487          $entities = $this->vault->get_replies_to_post($otherteacher, $ep, true);
 488          $this->assertCount(8, $entities);
 489          $this->assertEquals($epa->get_id(), $entities[0]->get_id());
 490          $this->assertEquals($epaa->get_id(), $entities[1]->get_id());
 491          $this->assertEquals($epab->get_id(), $entities[2]->get_id());
 492          $this->assertEquals($epb->get_id(), $entities[3]->get_id());
 493          $this->assertEquals($epc->get_id(), $entities[4]->get_id());
 494          $this->assertEquals($epca->get_id(), $entities[5]->get_id());
 495          $this->assertEquals($epcaa->get_id(), $entities[6]->get_id());
 496          $this->assertEquals($epcaaa->get_id(), $entities[7]->get_id());
 497  
 498          $entities = $this->vault->get_replies_to_post($otherteacher, $epa, true);
 499          $this->assertCount(2, $entities);
 500          $this->assertEquals($epaa->get_id(), $entities[0]->get_id());
 501          $this->assertEquals($epab->get_id(), $entities[1]->get_id());
 502  
 503          $this->assertEmpty($this->vault->get_replies_to_post($otherteacher, $epaa, true));
 504          $this->assertEmpty($this->vault->get_replies_to_post($otherteacher, $epab, true));
 505          $this->assertEmpty($this->vault->get_replies_to_post($otherteacher, $epb, true));
 506          $this->assertEmpty($this->vault->get_replies_to_post($otherteacher, $epcaaa, true));
 507  
 508          $entities = $this->vault->get_replies_to_post($otherteacher, $epc, true);
 509          $this->assertCount(3, $entities);
 510          $this->assertEquals($epca->get_id(), $entities[0]->get_id());
 511          $this->assertEquals($epcaa->get_id(), $entities[1]->get_id());
 512          $this->assertEquals($epcaaa->get_id(), $entities[2]->get_id());
 513      }
 514  
 515      /**
 516       * Test get_reply_count_for_discussion_ids when no discussion ids were provided.
 517       *
 518       * @covers ::get_reply_count_for_discussion_ids
 519       */
 520      public function test_get_reply_count_for_discussion_ids_empty() {
 521          $this->resetAfterTest();
 522  
 523          $datagenerator = $this->getDataGenerator();
 524          $user = $datagenerator->create_user();
 525          $course = $datagenerator->create_course();
 526          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 527  
 528          $this->assertCount(0, $this->vault->get_reply_count_for_discussion_ids($user, [], false));
 529      }
 530  
 531      /**
 532       * Test get_reply_count_for_discussion_ids.
 533       *
 534       * @covers ::get_reply_count_for_discussion_ids
 535       */
 536      public function test_get_reply_count_for_discussion_ids() {
 537          $this->resetAfterTest();
 538  
 539          $datagenerator = $this->getDataGenerator();
 540          $user = $datagenerator->create_user();
 541          $course = $datagenerator->create_course();
 542          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 543          [$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
 544          $post2 = $this->helper_reply_to_post($post1, $user);
 545          $post3 = $this->helper_reply_to_post($post1, $user);
 546          $post4 = $this->helper_reply_to_post($post2, $user);
 547          [$discussion2, $post5] = $this->helper_post_to_forum($forum, $user);
 548          $post6 = $this->helper_reply_to_post($post5, $user);
 549          [$discussion3, $post7] = $this->helper_post_to_forum($forum, $user);
 550  
 551          $counts = $this->vault->get_reply_count_for_discussion_ids($user, [$discussion1->id], false);
 552          $this->assertCount(1, $counts);
 553          $this->assertEquals(3, $counts[$discussion1->id]);
 554  
 555          $counts = $this->vault->get_reply_count_for_discussion_ids($user, [$discussion1->id, $discussion2->id], false);
 556          $this->assertCount(2, $counts);
 557          $this->assertEquals(3, $counts[$discussion1->id]);
 558          $this->assertEquals(1, $counts[$discussion2->id]);
 559  
 560          $counts = $this->vault->get_reply_count_for_discussion_ids($user, [
 561              $discussion1->id,
 562              $discussion2->id,
 563              $discussion3->id
 564          ], false);
 565          $this->assertCount(2, $counts);
 566          $this->assertEquals(3, $counts[$discussion1->id]);
 567          $this->assertEquals(1, $counts[$discussion2->id]);
 568  
 569          $counts = $this->vault->get_reply_count_for_discussion_ids($user, [
 570              $discussion1->id,
 571              $discussion2->id,
 572              $discussion3->id,
 573              $discussion3->id + 1000
 574          ], false);
 575          $this->assertCount(2, $counts);
 576          $this->assertEquals(3, $counts[$discussion1->id]);
 577          $this->assertEquals(1, $counts[$discussion2->id]);
 578      }
 579  
 580      /**
 581       * Test get_reply_count_for_discussion_ids.
 582       *
 583       * @covers ::get_reply_count_for_discussion_ids
 584       */
 585      public function test_get_reply_count_for_discussion_ids_private_replies() {
 586          $this->resetAfterTest();
 587  
 588          $course = $this->getDataGenerator()->create_course();
 589          $forum = $this->getDataGenerator()->create_module('forum', [
 590              'course' => $course->id,
 591          ]);
 592  
 593          // Generate a structure:
 594          // Initial post p [student]
 595          // -> Reply pa [otherstudent]
 596          // ---> Reply paa [student]
 597          // ---> Private Reply pab [teacher]
 598          // -> Private Reply pb [teacher]
 599          // -> Reply pc [otherstudent]
 600          // ---> Reply pca [student]
 601          // -----> Reply pcaa [otherstudent]
 602          // -------> Private Reply pcaaa [teacher].
 603  
 604          [$student, $otherstudent] = $this->helper_create_users($course, 2, 'student');
 605          [$teacher, $otherteacher] = $this->helper_create_users($course, 2, 'teacher');
 606  
 607          [$discussion, $p] = $this->helper_post_to_forum($forum, $student);
 608  
 609          $pa = $this->helper_reply_to_post($p, $otherstudent);
 610          $paa = $this->helper_reply_to_post($pa, $student);
 611          $pab = $this->helper_reply_to_post($pa, $teacher, ['privatereplyto' => $otherstudent->id]);
 612  
 613          $pb = $this->helper_reply_to_post($p, $teacher, ['privatereplyto' => $student->id]);
 614  
 615          $pc = $this->helper_reply_to_post($p, $otherteacher);
 616          $pca = $this->helper_reply_to_post($pc, $student);
 617          $pcaa = $this->helper_reply_to_post($pca, $otherstudent);
 618          $pcaaa = $this->helper_reply_to_post($pcaa, $teacher, ['privatereplyto' => $otherstudent->id]);
 619  
 620          $this->assertEquals([$discussion->id => 6],
 621              $this->vault->get_reply_count_for_discussion_ids($student, [$discussion->id], false));
 622          $this->assertEquals([$discussion->id => 7],
 623              $this->vault->get_reply_count_for_discussion_ids($otherstudent, [$discussion->id], false));
 624          $this->assertEquals([$discussion->id => 8],
 625              $this->vault->get_reply_count_for_discussion_ids($teacher, [$discussion->id], true));
 626          $this->assertEquals([$discussion->id => 8],
 627              $this->vault->get_reply_count_for_discussion_ids($otherteacher, [$discussion->id], true));
 628      }
 629  
 630      /**
 631       * Test get_reply_count_for_discussion_id.
 632       *
 633       * @covers ::get_reply_count_for_post_id_in_discussion_id
 634       */
 635      public function test_get_reply_count_for_post_id_in_discussion_id() {
 636          $this->resetAfterTest();
 637  
 638          $datagenerator = $this->getDataGenerator();
 639          $user = $datagenerator->create_user();
 640          $course = $datagenerator->create_course();
 641          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 642          [$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
 643          $post2 = $this->helper_reply_to_post($post1, $user);
 644          $post3 = $this->helper_reply_to_post($post1, $user);
 645          $post4 = $this->helper_reply_to_post($post2, $user);
 646          [$discussion2, $post5] = $this->helper_post_to_forum($forum, $user);
 647          $post6 = $this->helper_reply_to_post($post5, $user);
 648          [$discussion3, $post7] = $this->helper_post_to_forum($forum, $user);
 649  
 650          $this->assertEquals(3,
 651              $this->vault->get_reply_count_for_post_id_in_discussion_id($user, $post1->id, $discussion1->id, false));
 652          $this->assertEquals(1,
 653              $this->vault->get_reply_count_for_post_id_in_discussion_id($user, $post5->id, $discussion2->id, false));
 654          $this->assertEquals(0,
 655              $this->vault->get_reply_count_for_post_id_in_discussion_id($user, $post7->id, $discussion3->id, false));
 656          $this->assertEquals(0,
 657              $this->vault->get_reply_count_for_post_id_in_discussion_id($user, $post7->id + 1000, $discussion3->id, false));
 658      }
 659  
 660      /**
 661       * Test get_reply_count_for_post_id_in_discussion_id.
 662       *
 663       * @covers ::get_reply_count_for_post_id_in_discussion_id
 664       */
 665      public function test_get_reply_count_for_post_id_in_discussion_id_private_replies() {
 666          $this->resetAfterTest();
 667  
 668          $course = $this->getDataGenerator()->create_course();
 669          $forum = $this->getDataGenerator()->create_module('forum', [
 670              'course' => $course->id,
 671          ]);
 672  
 673          // Generate a structure:
 674          // Initial post p [student]
 675          // -> Reply pa [otherstudent]
 676          // ---> Reply paa [student]
 677          // ---> Private Reply pab [teacher]
 678          // -> Private Reply pb [teacher]
 679          // -> Reply pc [otherstudent]
 680          // ---> Reply pca [student]
 681          // -----> Reply pcaa [otherstudent]
 682          // -------> Private Reply pcaaa [teacher].
 683  
 684          [$student, $otherstudent] = $this->helper_create_users($course, 2, 'student');
 685          [$teacher, $otherteacher] = $this->helper_create_users($course, 2, 'teacher');
 686  
 687          [$discussion, $p] = $this->helper_post_to_forum($forum, $student);
 688  
 689          $pa = $this->helper_reply_to_post($p, $otherstudent);
 690          $paa = $this->helper_reply_to_post($pa, $student);
 691          $pab = $this->helper_reply_to_post($pa, $teacher, ['privatereplyto' => $otherstudent->id]);
 692  
 693          $pb = $this->helper_reply_to_post($p, $teacher, ['privatereplyto' => $student->id]);
 694  
 695          $pc = $this->helper_reply_to_post($p, $otherteacher);
 696          $pca = $this->helper_reply_to_post($pc, $student);
 697          $pcaa = $this->helper_reply_to_post($pca, $otherstudent);
 698          $pcaaa = $this->helper_reply_to_post($pcaa, $teacher, ['privatereplyto' => $otherstudent->id]);
 699  
 700          $this->assertEquals(6,
 701              $this->vault->get_reply_count_for_post_id_in_discussion_id($student, $p->id, $discussion->id, false));
 702          $this->assertEquals(7,
 703              $this->vault->get_reply_count_for_post_id_in_discussion_id($otherstudent, $p->id, $discussion->id, false));
 704          $this->assertEquals(8,
 705              $this->vault->get_reply_count_for_post_id_in_discussion_id($teacher, $p->id, $discussion->id, true));
 706          $this->assertEquals(8,
 707              $this->vault->get_reply_count_for_post_id_in_discussion_id($otherteacher, $p->id, $discussion->id, true));
 708      }
 709  
 710      /**
 711       * Test get_unread_count_for_discussion_ids.
 712       *
 713       * @covers ::get_unread_count_for_discussion_ids
 714       */
 715      public function test_get_unread_count_for_discussion_ids() {
 716          global $CFG;
 717          $this->resetAfterTest();
 718  
 719          $datagenerator = $this->getDataGenerator();
 720          $user = $datagenerator->create_user();
 721          $otheruser = $datagenerator->create_user();
 722          $course = $datagenerator->create_course();
 723          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 724          [$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
 725          $post2 = $this->helper_reply_to_post($post1, $user);
 726          $post3 = $this->helper_reply_to_post($post1, $user);
 727          $post4 = $this->helper_reply_to_post($post2, $user);
 728          [$discussion2, $post5] = $this->helper_post_to_forum($forum, $user);
 729          $post6 = $this->helper_reply_to_post($post5, $user);
 730  
 731          $modgenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum');
 732          $post7 = $modgenerator->create_post((object) [
 733              'discussion' => $post5->discussion,
 734              'parent' => $post5->id,
 735              'userid' => $user->id,
 736              'mailnow' => 1,
 737              'subject' => 'old post',
 738              // Two days ago which makes it an "old post".
 739              'modified' => time() - 172800
 740          ]);
 741  
 742          forum_tp_add_read_record($user->id, $post1->id);
 743          forum_tp_add_read_record($user->id, $post4->id);
 744          $CFG->forum_oldpostdays = 1;
 745  
 746          $counts = $this->vault->get_unread_count_for_discussion_ids($user, [$discussion1->id], false);
 747          $this->assertCount(1, $counts);
 748          $this->assertEquals(2, $counts[$discussion1->id]);
 749  
 750          $counts = $this->vault->get_unread_count_for_discussion_ids($user, [$discussion1->id, $discussion2->id], false);
 751          $this->assertCount(2, $counts);
 752          $this->assertEquals(2, $counts[$discussion1->id]);
 753          $this->assertEquals(2, $counts[$discussion2->id]);
 754  
 755          $counts = $this->vault->get_unread_count_for_discussion_ids($user, [
 756              $discussion1->id,
 757              $discussion2->id,
 758              $discussion2->id + 1000
 759          ], false);
 760          $this->assertCount(2, $counts);
 761          $this->assertEquals(2, $counts[$discussion1->id]);
 762          $this->assertEquals(2, $counts[$discussion2->id]);
 763  
 764          $counts = $this->vault->get_unread_count_for_discussion_ids($otheruser, [$discussion1->id, $discussion2->id], false);
 765          $this->assertCount(2, $counts);
 766          $this->assertEquals(4, $counts[$discussion1->id]);
 767          $this->assertEquals(2, $counts[$discussion2->id]);
 768      }
 769  
 770      /**
 771       * Test get_unread_count_for_discussion_ids when no discussion ids were provided.
 772       *
 773       * @covers ::get_unread_count_for_discussion_ids
 774       */
 775      public function test_get_unread_count_for_discussion_ids_empty() {
 776          $this->resetAfterTest();
 777  
 778          $datagenerator = $this->getDataGenerator();
 779          $user = $datagenerator->create_user();
 780          $course = $datagenerator->create_course();
 781          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 782  
 783          $this->assertEquals([], $this->vault->get_unread_count_for_discussion_ids($user, [], false));
 784      }
 785  
 786      /**
 787       * Test get_latest_posts_for_discussion_ids.
 788       *
 789       * @covers ::get_latest_posts_for_discussion_ids
 790       */
 791      public function test_get_latest_posts_for_discussion_ids() {
 792          $this->resetAfterTest();
 793  
 794          $datagenerator = $this->getDataGenerator();
 795          $course = $datagenerator->create_course();
 796          [$teacher, $otherteacher] = $this->helper_create_users($course, 2, 'teacher');
 797          [$user, $user2] = $this->helper_create_users($course, 2, 'student');
 798          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 799          [$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
 800          $post2 = $this->helper_reply_to_post($post1, $user);
 801          $post3 = $this->helper_reply_to_post($post1, $user);
 802          $post4 = $this->helper_reply_to_post($post2, $user);
 803          [$discussion2, $post5] = $this->helper_post_to_forum($forum, $user);
 804          $post6 = $this->helper_reply_to_post($post5, $user);
 805          [$discussion3, $post7] = $this->helper_post_to_forum($forum, $user);
 806          $post8 = $this->helper_post_to_discussion($forum, $discussion3, $teacher, [
 807              'privatereplyto' => $user->id,
 808          ]);
 809  
 810          $ids = $this->vault->get_latest_posts_for_discussion_ids($user, [$discussion1->id], false);
 811          $this->assertCount(1, $ids);
 812          $this->assertEquals($post4->id, $ids[$discussion1->id]->get_id());
 813  
 814          $ids = $this->vault->get_latest_posts_for_discussion_ids($user,
 815              [$discussion1->id, $discussion2->id], false);
 816          $this->assertCount(2, $ids);
 817          $this->assertEquals($post4->id, $ids[$discussion1->id]->get_id());
 818          $this->assertEquals($post6->id, $ids[$discussion2->id]->get_id());
 819  
 820          $ids = $this->vault->get_latest_posts_for_discussion_ids($user,
 821              [$discussion1->id, $discussion2->id, $discussion3->id], false);
 822          $this->assertCount(3, $ids);
 823          $this->assertEquals($post4->id, $ids[$discussion1->id]->get_id());
 824          $this->assertEquals($post6->id, $ids[$discussion2->id]->get_id());
 825          $this->assertEquals($post8->id, $ids[$discussion3->id]->get_id());
 826  
 827          // Checks the user who doesn't have access to the private reply.
 828          $ids = $this->vault->get_latest_posts_for_discussion_ids($user2,
 829              [$discussion1->id, $discussion2->id, $discussion3->id], false);
 830          $this->assertCount(3, $ids);
 831          $this->assertEquals($post4->id, $ids[$discussion1->id]->get_id());
 832          $this->assertEquals($post6->id, $ids[$discussion2->id]->get_id());
 833          $this->assertEquals($post7->id, $ids[$discussion3->id]->get_id());
 834  
 835          // Checks the user with the private reply to.
 836          $ids = $this->vault->get_latest_posts_for_discussion_ids($user, [
 837              $discussion1->id,
 838              $discussion2->id,
 839              $discussion3->id,
 840              $discussion3->id + 1000
 841          ], false);
 842          $this->assertCount(3, $ids);
 843          $this->assertEquals($post4->id, $ids[$discussion1->id]->get_id());
 844          $this->assertEquals($post6->id, $ids[$discussion2->id]->get_id());
 845          $this->assertEquals($post8->id, $ids[$discussion3->id]->get_id());
 846      }
 847  
 848      /**
 849       * Test get_latest_posts_for_discussion_ids when no discussion ids were provided.
 850       *
 851       * @covers ::get_latest_posts_for_discussion_ids
 852       */
 853      public function test_get_latest_posts_for_discussion_ids_empty() {
 854          $this->resetAfterTest();
 855  
 856          $datagenerator = $this->getDataGenerator();
 857          $user = $datagenerator->create_user();
 858          $course = $datagenerator->create_course();
 859          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 860  
 861          $this->assertEquals([], $this->vault->get_latest_posts_for_discussion_ids($user, [], false));
 862      }
 863  
 864      /**
 865       * Test get_first_post_for_discussion_ids.
 866       *
 867       * @covers ::get_first_post_for_discussion_ids
 868       */
 869      public function test_get_first_post_for_discussion_ids() {
 870          $this->resetAfterTest();
 871  
 872          $datagenerator = $this->getDataGenerator();
 873          $user = $datagenerator->create_user();
 874          $course = $datagenerator->create_course();
 875          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 876          [$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
 877          $post2 = $this->helper_reply_to_post($post1, $user);
 878          $post3 = $this->helper_reply_to_post($post1, $user);
 879          $post4 = $this->helper_reply_to_post($post2, $user);
 880          [$discussion2, $post5] = $this->helper_post_to_forum($forum, $user);
 881          $post6 = $this->helper_reply_to_post($post5, $user);
 882          [$discussion3, $post7] = $this->helper_post_to_forum($forum, $user);
 883  
 884          $firstposts = $this->vault->get_first_post_for_discussion_ids([$discussion1->id]);
 885          $this->assertCount(1, $firstposts);
 886          $this->assertEquals($post1->id, reset($firstposts)->get_id());
 887  
 888          $firstposts = $this->vault->get_first_post_for_discussion_ids([$discussion1->id, $discussion2->id]);
 889          $this->assertCount(2, $firstposts);
 890          $this->assertEquals($post1->id, $firstposts[$post1->id]->get_id());
 891          $this->assertEquals($post5->id, $firstposts[$post5->id]->get_id());
 892  
 893          $firstposts = $this->vault->get_first_post_for_discussion_ids([$discussion1->id, $discussion2->id, $discussion3->id]);
 894          $this->assertCount(3, $firstposts);
 895          $this->assertEquals($post1->id, $firstposts[$post1->id]->get_id());
 896          $this->assertEquals($post5->id, $firstposts[$post5->id]->get_id());
 897          $this->assertEquals($post7->id, $firstposts[$post7->id]->get_id());
 898  
 899          $firstposts = $this->vault->get_first_post_for_discussion_ids([
 900              $discussion1->id,
 901              $discussion2->id,
 902              $discussion3->id,
 903              $discussion3->id + 1000
 904          ]);
 905          $this->assertCount(3, $firstposts);
 906          $this->assertEquals($post1->id, $firstposts[$post1->id]->get_id());
 907          $this->assertEquals($post5->id, $firstposts[$post5->id]->get_id());
 908          $this->assertEquals($post7->id, $firstposts[$post7->id]->get_id());
 909      }
 910  
 911      /**
 912       * Test get_first_post_for_discussion_ids when no discussion ids were provided.
 913       *
 914       * @covers ::get_first_post_for_discussion_ids
 915       */
 916      public function test_get_first_post_for_discussion_ids_empty() {
 917          $this->resetAfterTest();
 918  
 919          $datagenerator = $this->getDataGenerator();
 920          $user = $datagenerator->create_user();
 921          $course = $datagenerator->create_course();
 922          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 923  
 924          $this->assertEquals([], $this->vault->get_first_post_for_discussion_ids([]));
 925      }
 926  
 927      /**
 928       * Test get_from_filters.
 929       *
 930       * @covers ::get_from_filters
 931       */
 932      public function test_get_from_filters() {
 933          $this->resetAfterTest();
 934  
 935          $datagenerator = $this->getDataGenerator();
 936          $course = $datagenerator->create_course();
 937          [$user, $user2] = $this->helper_create_users($course, 2, 'student');
 938          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
 939  
 940          [$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
 941          $post2 = $this->helper_reply_to_post($post1, $user);
 942          $post3 = $this->helper_reply_to_post($post1, $user);
 943  
 944          [$discussion2, $post4] = $this->helper_post_to_forum($forum, $user);
 945          $discussionids = [$discussion1->id, $discussion2->id];
 946  
 947          $userids = [$user->id];
 948          $entities = array_values($this->vault->get_from_filters($user,
 949              ['discussionids' => $discussionids, 'userids' => $userids],
 950              true,
 951              'id ASC'));
 952  
 953          $this->assertCount(4, $entities);
 954          $this->assertEquals($post1->id, $entities[0]->get_id());
 955          $this->assertEquals($post2->id, $entities[1]->get_id());
 956          $this->assertEquals($post3->id, $entities[2]->get_id());
 957          $this->assertEquals($post4->id, $entities[3]->get_id());
 958  
 959          $entities = $this->vault->get_from_filters($user, ['discussionids' => $discussion1->id, 'userids' => $userids],
 960                  false);
 961          $this->assertCount(3, $entities);
 962          $this->assertArrayHasKey($post1->id, $entities);
 963          $this->assertArrayHasKey($post2->id, $entities);
 964          $this->assertArrayHasKey($post3->id, $entities);
 965  
 966          $discussionids = [$discussion1->id, $discussion2->id];
 967          $userids = [$user->id, $user2->id];
 968          $entities = $this->vault->get_from_filters($user, ['discussionids' => $discussionids, 'userids' => $userids],
 969                  false);
 970          $this->assertCount(4, $entities);
 971          $this->assertArrayHasKey($post1->id, $entities);
 972          $this->assertArrayHasKey($post2->id, $entities);
 973          $this->assertArrayHasKey($post3->id, $entities);
 974          $this->assertArrayHasKey($post4->id, $entities);
 975  
 976          // Test ordering by id descending.
 977          $entities = $this->vault->get_from_filters($user, ['discussionids' => $discussionids, 'userids' => $user->id],
 978                  false, 'id DESC');
 979          $this->assertEquals($post4->id, array_values($entities)[0]->get_id());
 980          $this->assertEquals($post3->id, array_values($entities)[1]->get_id());
 981          $this->assertEquals($post2->id, array_values($entities)[2]->get_id());
 982          $this->assertEquals($post1->id, array_values($entities)[3]->get_id());
 983  
 984          // Test ordering by id ascending.
 985          $entities = $this->vault->get_from_filters($user, ['discussionids' => $discussionids, 'userids' => $user->id],
 986              false, 'id ASC');
 987          $this->assertEquals($post1->id, array_values($entities)[0]->get_id());
 988          $this->assertEquals($post2->id, array_values($entities)[1]->get_id());
 989          $this->assertEquals($post3->id, array_values($entities)[2]->get_id());
 990          $this->assertEquals($post4->id, array_values($entities)[3]->get_id());
 991      }
 992  
 993      public function test_get_from_filters_from_to_dates() {
 994          $this->resetAfterTest();
 995  
 996          $datagenerator = $this->getDataGenerator();
 997          $course = $datagenerator->create_course();
 998          [$user, $user2] = $this->helper_create_users($course, 2, 'student');
 999          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
1000  
1001          [$discussion1, $post1] = $this->helper_post_to_forum($forum, $user);
1002  
1003          $date = new DateTime('2019-07-05');
1004          $post2 = $this->helper_reply_to_post($post1, $user, ['created' => $date->getTimestamp()]);
1005          $post3 = $this->helper_reply_to_post($post1, $user, ['created' => $date->getTimestamp()]);
1006          $date->modify('+1 month');
1007          $post4 = $this->helper_reply_to_post($post1, $user, ['created' => $date->getTimestamp()]);
1008          $post5 = $this->helper_reply_to_post($post1, $user, ['created' => $date->getTimestamp()]);
1009          $post6 = $this->helper_reply_to_post($post1, $user, ['created' => $date->getTimestamp()]);
1010  
1011          [$discussion2, $post4] = $this->helper_post_to_forum($forum, $user);
1012  
1013          $datefilter = new DateTime('2019-07-01');
1014          $filters = ['from' => $datefilter->getTimestamp()];
1015          $entities = $this->vault->get_from_filters($user, $filters, false);
1016          $this->assertCount(7, $entities);
1017  
1018          $filters['to'] = $datefilter->modify('+1 month')->getTimestamp();
1019          $entities = $this->vault->get_from_filters($user, $filters, false);
1020          $this->assertCount(2, $entities);
1021      }
1022  
1023      /**
1024       * Test get_from_filters when no discussion ids were provided.
1025       *
1026       * @covers ::get_from_filters
1027       */
1028      public function test_get_from_filters_empty() {
1029          $this->resetAfterTest();
1030  
1031          $datagenerator = $this->getDataGenerator();
1032          $course = $datagenerator->create_course();
1033          [$student1] = $this->helper_create_users($course, 1, 'student');
1034          $forum = $datagenerator->create_module('forum', ['course' => $course->id]);
1035          $this->helper_post_to_forum($forum, $student1);
1036          $this->assertEquals([], $this->vault->get_from_filters($student1, [], false));
1037      }
1038  
1039      /**
1040       * Ensure that selecting posts in a discussion only returns posts that the user can see, when considering private
1041       * replies.
1042       *
1043       * @covers ::get_from_filters
1044       */
1045      public function test_get_from_filters_private_replies() {
1046          $this->resetAfterTest();
1047  
1048          $course = $this->getDataGenerator()->create_course();
1049          $forum = $this->getDataGenerator()->create_module('forum', [
1050              'course' => $course->id,
1051          ]);
1052  
1053          [$student, $otherstudent] = $this->helper_create_users($course, 2, 'student');
1054          [$teacher, $otherteacher] = $this->helper_create_users($course, 2, 'teacher');
1055  
1056          // Create the posts structure below.
1057          // Forum:
1058          // -> Post (student 1)
1059          // ---> Post private reply (teacher 1)
1060          // -> Otherpost (teacher 1)
1061          // ---> Otherpost private reply (teacher 2)
1062          // ---> Otherpost reply (student 1)
1063          // ----> Otherpost reply private reply (teacher 1).
1064          [$discussion, $post] = $this->helper_post_to_forum($forum, $student);
1065          $postprivatereply = $this->helper_reply_to_post($post, $teacher, [
1066              'privatereplyto' => $student->id
1067          ]);
1068          [$otherdiscussion, $otherpost] = $this->helper_post_to_forum($forum, $teacher);
1069          $otherpostprivatereply = $this->helper_reply_to_post($otherpost, $otherteacher, [
1070              'privatereplyto' => $teacher->id,
1071          ]);
1072          $otherpostreply = $this->helper_reply_to_post($otherpost, $student);
1073          $otherpostreplyprivatereply = $this->helper_reply_to_post($otherpostreply, $teacher, [
1074              'privatereplyto' => $student->id
1075          ]);
1076  
1077          $userids = [$otherstudent->id, $teacher->id, $otherteacher->id];
1078          $discussionids = [$discussion->id, $otherdiscussion->id];
1079  
1080          // Teacher 1. Request all posts from the vault, telling the vault that the teacher CAN see private replies made by anyone.
1081          $entities = $this->vault->get_from_filters($teacher, ['discussionids' => $discussionids, 'userids' => $userids],
1082              true);
1083          $this->assertCount(4, $entities);
1084          $this->assertArrayHasKey($postprivatereply->id, $entities);
1085          $this->assertArrayHasKey($otherpost->id, $entities);
1086          $this->assertArrayHasKey($otherpostprivatereply->id, $entities);
1087          $this->assertArrayHasKey($otherpostreplyprivatereply->id, $entities);
1088  
1089          // Student 1. Request all posts from the vault, telling the vault that the student CAN'T see private replies made by anyone.
1090          // Teacher2's private reply to otherpost is omitted.
1091          $entities = $this->vault->get_from_filters($student, ['discussionids' => $discussionids, 'userids' => $userids],
1092                  false);
1093          $this->assertCount(3, $entities);
1094          $this->assertArrayHasKey($postprivatereply->id, $entities);
1095          $this->assertArrayHasKey($otherpost->id, $entities);
1096          $this->assertArrayHasKey($otherpostreplyprivatereply->id, $entities);
1097  
1098          // Student 1. Request all posts from the vault, telling the vault that student CAN see all private replies made.
1099          // The private reply made by teacher 2 to otherpost is now included.
1100          $entities = $this->vault->get_from_filters($student, ['discussionids' => $discussionids, 'userids' => $userids],
1101                  true);
1102          $this->assertCount(4, $entities);
1103          $this->assertArrayHasKey($postprivatereply->id, $entities);
1104          $this->assertArrayHasKey($otherpost->id, $entities);
1105          $this->assertArrayHasKey($otherpostprivatereply->id, $entities);
1106          $this->assertArrayHasKey($otherpostreplyprivatereply->id, $entities);
1107  
1108          // Teacher 2. Request all posts from the vault, telling the vault that teacher2 CAN see all private replies made.
1109          $entities = $this->vault->get_from_filters($otherteacher,
1110                  ['discussionids' => $discussionids, 'userids' => $userids], true);
1111          $this->assertCount(4, $entities);
1112          $this->assertArrayHasKey($otherpost->id, $entities);
1113          $this->assertArrayHasKey($otherpostprivatereply->id, $entities);
1114          $this->assertArrayHasKey($otherpostreplyprivatereply->id, $entities);
1115  
1116          // Teacher 2. Request all posts from the vault, telling the vault that teacher2 CANNOT see all private replies made.
1117          // The private replies not relating to teacher 2 directly are omitted.
1118          $entities = $this->vault->get_from_filters($otherteacher,
1119                  ['discussionids' => $discussionids, 'userids' => $userids], false);
1120          $this->assertCount(2, $entities);
1121          $this->assertArrayHasKey($otherpost->id, $entities);
1122          $this->assertArrayHasKey($otherpostprivatereply->id, $entities);
1123  
1124          // Student 2. Request all posts from the vault, telling the vault that student2 CAN'T see all private replies made.
1125          // All private replies are omitted, as none relate to student2.
1126          $entities = $this->vault->get_from_filters($otherstudent,
1127                  ['discussionids' => $discussionids, 'userids' => $userids], false);
1128          $this->assertCount(1, $entities);
1129          $this->assertArrayHasKey($otherpost->id, $entities);
1130  
1131      }
1132  }