Search moodle.org's
Developer Documentation

See Release Notes

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

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