Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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

   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 core_calendar;
  18  
  19  use core_calendar\local\event\container;
  20  
  21  defined('MOODLE_INTERNAL') || die();
  22  
  23  require_once (__DIR__ . '/helpers.php');
  24  
  25  /**
  26   * Class contaning unit tests for the calendar local API.
  27   *
  28   * @package    core_calendar
  29   * @copyright  2017 Mark Nelson <markn@moodle.com>
  30   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31   * @coversDefaultClass \core_calendar\local\api
  32   */
  33  class local_api_test extends \advanced_testcase {
  34  
  35      /**
  36       * Tests set up
  37       */
  38      protected function setUp(): void {
  39          $this->resetAfterTest();
  40      }
  41  
  42      /**
  43       * Create a feedback activity instance and a calendar event for
  44       * that instance.
  45       *
  46       * @param array $feedbackproperties Properties to set on the feedback activity
  47       * @param array $eventproperties Properties to set on the calendar event
  48       * @return array The feedback activity and the calendar event
  49       */
  50      protected function create_feedback_activity_and_event(array $feedbackproperties = [], array $eventproperties = []) {
  51          $generator = $this->getDataGenerator();
  52          $course = $generator->create_course();
  53          $mapper = container::get_event_mapper();
  54          $feedbackgenerator = $generator->get_plugin_generator('mod_feedback');
  55          $feedback = $feedbackgenerator->create_instance(array_merge(
  56              ['course' => $course->id],
  57              $feedbackproperties
  58          ));
  59  
  60          $event = create_event(array_merge(
  61              [
  62                  'courseid' => $course->id,
  63                  'modulename' => 'feedback',
  64                  'instance' => $feedback->id
  65              ],
  66               $eventproperties
  67          ));
  68          $event = $mapper->from_legacy_event_to_event($event);
  69  
  70          return [$feedback, $event];
  71      }
  72  
  73      /**
  74       * Requesting calendar events from a given time should return all events with a sort
  75       * time at or after the requested time. All events prior to that time should not
  76       * be return.
  77       *
  78       * If there are no events on or after the given time then an empty result set should
  79       * be returned.
  80       */
  81      public function test_get_calendar_action_events_by_timesort_after_time() {
  82          $user = $this->getDataGenerator()->create_user();
  83          $course = $this->getDataGenerator()->create_course();
  84          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
  85          $moduleinstance = $generator->create_instance(['course' => $course->id]);
  86  
  87          $this->getDataGenerator()->enrol_user($user->id, $course->id);
  88          $this->resetAfterTest(true);
  89          $this->setAdminUser();
  90  
  91          $params = [
  92              'type' => CALENDAR_EVENT_TYPE_ACTION,
  93              'courseid' => $course->id,
  94              'modulename' => 'assign',
  95              'instance' => $moduleinstance->id,
  96              'userid' => $user->id,
  97              'eventtype' => 'user',
  98              'repeats' => 0,
  99              'timestart' => 1,
 100          ];
 101  
 102          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 1]));
 103          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 2]));
 104          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 3]));
 105          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 4]));
 106          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 5]));
 107          $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 6]));
 108          $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 7]));
 109          $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 8]));
 110  
 111          $this->setUser($user);
 112          $result = \core_calendar\local\api::get_action_events_by_timesort(5);
 113  
 114          $this->assertCount(4, $result);
 115          $this->assertEquals('Event 5', $result[0]->get_name());
 116          $this->assertEquals('Event 6', $result[1]->get_name());
 117          $this->assertEquals('Event 7', $result[2]->get_name());
 118          $this->assertEquals('Event 8', $result[3]->get_name());
 119  
 120          $result = \core_calendar\local\api::get_action_events_by_timesort(9);
 121  
 122          $this->assertEmpty($result);
 123  
 124          $this->setAdminUser();
 125          $result = \core_calendar\local\api::get_action_events_by_timesort(5, null, null, 20, false, $user);
 126          $this->assertCount(4, $result);
 127      }
 128  
 129      /**
 130       * Requesting calendar events before a given time should return all events with a sort
 131       * time at or before the requested time (inclusive). All events after that time
 132       * should not be returned.
 133       *
 134       * If there are no events before the given time then an empty result set should be
 135       * returned.
 136       */
 137      public function test_get_calendar_action_events_by_timesort_before_time() {
 138          $user = $this->getDataGenerator()->create_user();
 139          $course = $this->getDataGenerator()->create_course();
 140          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 141          $moduleinstance = $generator->create_instance(['course' => $course->id]);
 142  
 143          $this->getDataGenerator()->enrol_user($user->id, $course->id);
 144          $this->resetAfterTest(true);
 145          $this->setAdminUser();
 146  
 147          $params = [
 148              'type' => CALENDAR_EVENT_TYPE_ACTION,
 149              'courseid' => $course->id,
 150              'modulename' => 'assign',
 151              'instance' => $moduleinstance->id,
 152              'userid' => 1,
 153              'eventtype' => 'user',
 154              'repeats' => 0,
 155              'timestart' => 1,
 156          ];
 157  
 158          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 2]));
 159          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 3]));
 160          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 4]));
 161          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 5]));
 162          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 6]));
 163          $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 7]));
 164          $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 8]));
 165          $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 9]));
 166  
 167          $this->setUser($user);
 168          $result = \core_calendar\local\api::get_action_events_by_timesort(null, 5);
 169  
 170          $this->assertCount(4, $result);
 171          $this->assertEquals('Event 1', $result[0]->get_name());
 172          $this->assertEquals('Event 2', $result[1]->get_name());
 173          $this->assertEquals('Event 3', $result[2]->get_name());
 174          $this->assertEquals('Event 4', $result[3]->get_name());
 175  
 176          $result = \core_calendar\local\api::get_action_events_by_timesort(null, 1);
 177  
 178          $this->assertEmpty($result);
 179      }
 180  
 181      /**
 182       * Requesting calendar events within a given time range should return all events with
 183       * a sort time between the lower and upper time bound (inclusive).
 184       *
 185       * If there are no events in the given time range then an empty result set should be
 186       * returned.
 187       */
 188      public function test_get_calendar_action_events_by_timesort_time_range() {
 189          $user = $this->getDataGenerator()->create_user();
 190          $course = $this->getDataGenerator()->create_course();
 191          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 192          $moduleinstance = $generator->create_instance(['course' => $course->id]);
 193  
 194          $this->getDataGenerator()->enrol_user($user->id, $course->id);
 195          $this->resetAfterTest(true);
 196          $this->setAdminUser();
 197  
 198          $params = [
 199              'type' => CALENDAR_EVENT_TYPE_ACTION,
 200              'courseid' => $course->id,
 201              'modulename' => 'assign',
 202              'instance' => $moduleinstance->id,
 203              'userid' => 1,
 204              'eventtype' => 'user',
 205              'repeats' => 0,
 206              'timestart' => 1,
 207          ];
 208  
 209          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 1]));
 210          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 2]));
 211          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 3]));
 212          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 4]));
 213          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 5]));
 214          $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 6]));
 215          $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 7]));
 216          $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 8]));
 217  
 218          $this->setUser($user);
 219          $result = \core_calendar\local\api::get_action_events_by_timesort(3, 6);
 220  
 221          $this->assertCount(4, $result);
 222          $this->assertEquals('Event 3', $result[0]->get_name());
 223          $this->assertEquals('Event 4', $result[1]->get_name());
 224          $this->assertEquals('Event 5', $result[2]->get_name());
 225          $this->assertEquals('Event 6', $result[3]->get_name());
 226  
 227          $result = \core_calendar\local\api::get_action_events_by_timesort(10, 15);
 228  
 229          $this->assertEmpty($result);
 230      }
 231  
 232      /**
 233       * Requesting calendar events within a given time range and a limit and offset should return
 234       * the number of events up to the given limit value that have a sort time between the lower
 235       * and uppper time bound (inclusive) where the result set is shifted by the offset value.
 236       *
 237       * If there are no events in the given time range then an empty result set should be
 238       * returned.
 239       */
 240      public function test_get_calendar_action_events_by_timesort_time_limit_offset() {
 241          $user = $this->getDataGenerator()->create_user();
 242          $course = $this->getDataGenerator()->create_course();
 243          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 244          $moduleinstance = $generator->create_instance(['course' => $course->id]);
 245  
 246          $this->getDataGenerator()->enrol_user($user->id, $course->id);
 247          $this->resetAfterTest(true);
 248          $this->setAdminUser();
 249  
 250          $params = [
 251              'type' => CALENDAR_EVENT_TYPE_ACTION,
 252              'courseid' => $course->id,
 253              'modulename' => 'assign',
 254              'instance' => $moduleinstance->id,
 255              'userid' => 1,
 256              'eventtype' => 'user',
 257              'repeats' => 0,
 258              'timestart' => 1,
 259          ];
 260  
 261          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 1]));
 262          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 2]));
 263          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 3]));
 264          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 4]));
 265          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 5]));
 266          $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 6]));
 267          $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 7]));
 268          $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 8]));
 269  
 270          $this->setUser($user);
 271          $result = \core_calendar\local\api::get_action_events_by_timesort(2, 7, $event3->id, 2);
 272  
 273          $this->assertCount(2, $result);
 274          $this->assertEquals('Event 4', $result[0]->get_name());
 275          $this->assertEquals('Event 5', $result[1]->get_name());
 276  
 277          $result = \core_calendar\local\api::get_action_events_by_timesort(2, 7, $event5->id, 2);
 278  
 279          $this->assertCount(2, $result);
 280          $this->assertEquals('Event 6', $result[0]->get_name());
 281          $this->assertEquals('Event 7', $result[1]->get_name());
 282  
 283          $result = \core_calendar\local\api::get_action_events_by_timesort(2, 7, $event7->id, 2);
 284  
 285          $this->assertEmpty($result);
 286      }
 287  
 288      /**
 289       * Test get_calendar_action_events_by_timesort with search feature.
 290       * @covers ::get_action_events_by_timesort
 291       */
 292      public function test_get_calendar_action_events_by_timesort_with_search() {
 293          // Generate data.
 294          $user = $this->getDataGenerator()->create_user();
 295          $course = $this->getDataGenerator()->create_course();
 296          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 297          $moduleinstance = $generator->create_instance(['course' => $course->id]);
 298  
 299          $this->getDataGenerator()->enrol_user($user->id, $course->id);
 300          $this->resetAfterTest(true);
 301          $this->setAdminUser();
 302  
 303          $params = [
 304              'type' => CALENDAR_EVENT_TYPE_ACTION,
 305              'courseid' => $course->id,
 306              'modulename' => 'assign',
 307              'instance' => $moduleinstance->id,
 308              'userid' => 1,
 309              'eventtype' => 'user',
 310              'repeats' => 0,
 311              'timestart' => 1,
 312          ];
 313  
 314          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 1]));
 315          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 2]));
 316          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 3]));
 317          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 4]));
 318          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 5]));
 319          $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 6]));
 320          $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 7]));
 321          $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 8]));
 322          $event9 = create_event(array_merge($params, ['name' => 'Assign with advanced name', 'timesort' => 9]));
 323  
 324          $this->setUser($user);
 325  
 326          // No result found for fake search.
 327          $result = \core_calendar\local\api::get_action_events_by_timesort(0, null, null, 6, false, null, 'Fake search');
 328          $this->assertEmpty($result);
 329  
 330          // Search for event name called 'Event 1'.
 331          $result = \core_calendar\local\api::get_action_events_by_timesort(0, 10, null, 20, false, null, 'Event 1');
 332          $this->assertCount(1, $result);
 333          $this->assertEquals('Event 1', $result[0]->get_name());
 334  
 335          // Search for event name called 'Assign with advanced name'.
 336          $result = \core_calendar\local\api::get_action_events_by_timesort(
 337              0, 10, null, 20, false, null, 'Assign with advanced name');
 338          $this->assertCount(1, $result);
 339          $this->assertEquals('Assign with advanced name', $result[0]->get_name());
 340  
 341          // Search for event name contains 'Assign advanced'.
 342          $result = \core_calendar\local\api::get_action_events_by_timesort(
 343              0, 10, null, 20, false, null, 'Assign advanced');
 344          $this->assertCount(1, $result);
 345          $this->assertEquals('Assign with advanced name', $result[0]->get_name());
 346  
 347          // Search for activity type called 'assign'.
 348          $result = \core_calendar\local\api::get_action_events_by_timesort(0, 10, null, 20, false, null, 'assign');
 349          $this->assertCount(9, $result);
 350          $this->assertEquals('Event 1', $result[0]->get_name());
 351          $this->assertEquals('Event 2', $result[1]->get_name());
 352          $this->assertEquals('Event 3', $result[2]->get_name());
 353          $this->assertEquals('Event 4', $result[3]->get_name());
 354          $this->assertEquals('Event 5', $result[4]->get_name());
 355          $this->assertEquals('Event 6', $result[5]->get_name());
 356          $this->assertEquals('Event 7', $result[6]->get_name());
 357          $this->assertEquals('Event 8', $result[7]->get_name());
 358          $this->assertEquals('Assign with advanced name', $result[8]->get_name());
 359      }
 360  
 361      /**
 362       * Requesting calendar events from a given course and time should return all
 363       * events with a sort time at or after the requested time. All events prior
 364       * to that time should not be return.
 365       *
 366       * If there are no events on or after the given time then an empty result set should
 367       * be returned.
 368       */
 369      public function test_get_calendar_action_events_by_course_after_time() {
 370          $user = $this->getDataGenerator()->create_user();
 371          $course1 = $this->getDataGenerator()->create_course();
 372          $course2 = $this->getDataGenerator()->create_course();
 373          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 374          $moduleinstance1 = $generator->create_instance(['course' => $course1->id]);
 375          $moduleinstance2 = $generator->create_instance(['course' => $course2->id]);
 376  
 377          $this->getDataGenerator()->enrol_user($user->id, $course1->id);
 378          $this->getDataGenerator()->enrol_user($user->id, $course2->id);
 379          $this->resetAfterTest(true);
 380          $this->setUser($user);
 381  
 382          $params = [
 383              'type' => CALENDAR_EVENT_TYPE_ACTION,
 384              'modulename' => 'assign',
 385              'instance' => $moduleinstance1->id,
 386              'userid' => $user->id,
 387              'courseid' => $course1->id,
 388              'eventtype' => 'user',
 389              'repeats' => 0,
 390              'timestart' => 1,
 391          ];
 392  
 393          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 1]));
 394          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 2]));
 395          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 3]));
 396          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 4]));
 397          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 5]));
 398          $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 6]));
 399          $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 7]));
 400          $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 8]));
 401  
 402          $params['courseid'] = $course2->id;
 403          $params['instance'] = $moduleinstance2->id;
 404          $event9 = create_event(array_merge($params, ['name' => 'Event 9', 'timesort' => 1]));
 405          $event10 = create_event(array_merge($params, ['name' => 'Event 10', 'timesort' => 2]));
 406          $event11 = create_event(array_merge($params, ['name' => 'Event 11', 'timesort' => 3]));
 407          $event12 = create_event(array_merge($params, ['name' => 'Event 12', 'timesort' => 4]));
 408          $event13 = create_event(array_merge($params, ['name' => 'Event 13', 'timesort' => 5]));
 409          $event14 = create_event(array_merge($params, ['name' => 'Event 14', 'timesort' => 6]));
 410          $event15 = create_event(array_merge($params, ['name' => 'Event 15', 'timesort' => 7]));
 411          $event16 = create_event(array_merge($params, ['name' => 'Event 16', 'timesort' => 8]));
 412  
 413          $result = \core_calendar\local\api::get_action_events_by_course($course1, 5);
 414  
 415          $this->assertCount(4, $result);
 416          $this->assertEquals('Event 5', $result[0]->get_name());
 417          $this->assertEquals('Event 6', $result[1]->get_name());
 418          $this->assertEquals('Event 7', $result[2]->get_name());
 419          $this->assertEquals('Event 8', $result[3]->get_name());
 420  
 421          $result = \core_calendar\local\api::get_action_events_by_course($course1, 9);
 422  
 423          $this->assertEmpty($result);
 424      }
 425  
 426      /**
 427       * Requesting calendar events for a course and before a given time should return
 428       * all events with a sort time at or before the requested time (inclusive). All
 429       * events after that time should not be returned.
 430       *
 431       * If there are no events before the given time then an empty result set should be
 432       * returned.
 433       */
 434      public function test_get_calendar_action_events_by_course_before_time() {
 435          $user = $this->getDataGenerator()->create_user();
 436          $course1 = $this->getDataGenerator()->create_course();
 437          $course2 = $this->getDataGenerator()->create_course();
 438          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 439          $moduleinstance1 = $generator->create_instance(['course' => $course1->id]);
 440          $moduleinstance2 = $generator->create_instance(['course' => $course2->id]);
 441  
 442          $this->getDataGenerator()->enrol_user($user->id, $course1->id);
 443          $this->getDataGenerator()->enrol_user($user->id, $course2->id);
 444          $this->resetAfterTest(true);
 445          $this->setUser($user);
 446  
 447          $params = [
 448              'type' => CALENDAR_EVENT_TYPE_ACTION,
 449              'modulename' => 'assign',
 450              'instance' => $moduleinstance1->id,
 451              'userid' => $user->id,
 452              'courseid' => $course1->id,
 453              'eventtype' => 'user',
 454              'repeats' => 0,
 455              'timestart' => 1,
 456          ];
 457  
 458          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 2]));
 459          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 3]));
 460          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 4]));
 461          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 5]));
 462          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 6]));
 463          $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 7]));
 464          $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 8]));
 465          $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 9]));
 466  
 467          $params['courseid'] = $course2->id;
 468          $params['instance'] = $moduleinstance2->id;
 469          $event9 = create_event(array_merge($params, ['name' => 'Event 9', 'timesort' => 2]));
 470          $event10 = create_event(array_merge($params, ['name' => 'Event 10', 'timesort' => 3]));
 471          $event11 = create_event(array_merge($params, ['name' => 'Event 11', 'timesort' => 4]));
 472          $event12 = create_event(array_merge($params, ['name' => 'Event 12', 'timesort' => 5]));
 473          $event13 = create_event(array_merge($params, ['name' => 'Event 13', 'timesort' => 6]));
 474          $event14 = create_event(array_merge($params, ['name' => 'Event 14', 'timesort' => 7]));
 475          $event15 = create_event(array_merge($params, ['name' => 'Event 15', 'timesort' => 8]));
 476          $event16 = create_event(array_merge($params, ['name' => 'Event 16', 'timesort' => 9]));
 477  
 478          $result = \core_calendar\local\api::get_action_events_by_course($course1, null, 5);
 479  
 480          $this->assertCount(4, $result);
 481          $this->assertEquals('Event 1', $result[0]->get_name());
 482          $this->assertEquals('Event 2', $result[1]->get_name());
 483          $this->assertEquals('Event 3', $result[2]->get_name());
 484          $this->assertEquals('Event 4', $result[3]->get_name());
 485  
 486          $result = \core_calendar\local\api::get_action_events_by_course($course1, null, 1);
 487  
 488          $this->assertEmpty($result);
 489      }
 490  
 491      /**
 492       * Requesting calendar events for a course and within a given time range should
 493       * return all events with a sort time between the lower and upper time bound
 494       * (inclusive).
 495       *
 496       * If there are no events in the given time range then an empty result set should be
 497       * returned.
 498       */
 499      public function test_get_calendar_action_events_by_course_time_range() {
 500          $user = $this->getDataGenerator()->create_user();
 501          $course1 = $this->getDataGenerator()->create_course();
 502          $course2 = $this->getDataGenerator()->create_course();
 503          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 504          $moduleinstance1 = $generator->create_instance(['course' => $course1->id]);
 505          $moduleinstance2 = $generator->create_instance(['course' => $course2->id]);
 506  
 507          $this->getDataGenerator()->enrol_user($user->id, $course1->id);
 508          $this->getDataGenerator()->enrol_user($user->id, $course2->id);
 509          $this->resetAfterTest(true);
 510          $this->setUser($user);
 511  
 512          $params = [
 513              'type' => CALENDAR_EVENT_TYPE_ACTION,
 514              'modulename' => 'assign',
 515              'instance' => $moduleinstance1->id,
 516              'userid' => $user->id,
 517              'courseid' => $course1->id,
 518              'eventtype' => 'user',
 519              'repeats' => 0,
 520              'timestart' => 1,
 521          ];
 522  
 523          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 1]));
 524          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 2]));
 525          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 3]));
 526          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 4]));
 527          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 5]));
 528          $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 6]));
 529          $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 7]));
 530          $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 8]));
 531  
 532          $params['courseid'] = $course2->id;
 533          $params['instance'] = $moduleinstance2->id;
 534          $event9 = create_event(array_merge($params, ['name' => 'Event 9', 'timesort' => 1]));
 535          $event10 = create_event(array_merge($params, ['name' => 'Event 10', 'timesort' => 2]));
 536          $event11 = create_event(array_merge($params, ['name' => 'Event 11', 'timesort' => 3]));
 537          $event12 = create_event(array_merge($params, ['name' => 'Event 12', 'timesort' => 4]));
 538          $event13 = create_event(array_merge($params, ['name' => 'Event 13', 'timesort' => 5]));
 539          $event14 = create_event(array_merge($params, ['name' => 'Event 14', 'timesort' => 6]));
 540          $event15 = create_event(array_merge($params, ['name' => 'Event 15', 'timesort' => 7]));
 541          $event16 = create_event(array_merge($params, ['name' => 'Event 16', 'timesort' => 8]));
 542  
 543          $result = \core_calendar\local\api::get_action_events_by_course($course1, 3, 6);
 544  
 545          $this->assertCount(4, $result);
 546          $this->assertEquals('Event 3', $result[0]->get_name());
 547          $this->assertEquals('Event 4', $result[1]->get_name());
 548          $this->assertEquals('Event 5', $result[2]->get_name());
 549          $this->assertEquals('Event 6', $result[3]->get_name());
 550  
 551          $result = \core_calendar\local\api::get_action_events_by_course($course1, 10, 15);
 552  
 553          $this->assertEmpty($result);
 554      }
 555  
 556      /**
 557       * Requesting calendar events for a course and within a given time range and a limit
 558       * and offset should return the number of events up to the given limit value that have
 559       * a sort time between the lower and uppper time bound (inclusive) where the result
 560       * set is shifted by the offset value.
 561       *
 562       * If there are no events in the given time range then an empty result set should be
 563       * returned.
 564       */
 565      public function test_get_calendar_action_events_by_course_time_limit_offset() {
 566          $user = $this->getDataGenerator()->create_user();
 567          $course1 = $this->getDataGenerator()->create_course();
 568          $course2 = $this->getDataGenerator()->create_course();
 569          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 570          $moduleinstance1 = $generator->create_instance(['course' => $course1->id]);
 571          $moduleinstance2 = $generator->create_instance(['course' => $course2->id]);
 572  
 573          $this->getDataGenerator()->enrol_user($user->id, $course1->id);
 574          $this->getDataGenerator()->enrol_user($user->id, $course2->id);
 575          $this->resetAfterTest(true);
 576          $this->setUser($user);
 577  
 578          $params = [
 579              'type' => CALENDAR_EVENT_TYPE_ACTION,
 580              'modulename' => 'assign',
 581              'instance' => $moduleinstance1->id,
 582              'userid' => $user->id,
 583              'courseid' => $course1->id,
 584              'eventtype' => 'user',
 585              'repeats' => 0,
 586              'timestart' => 1,
 587          ];
 588  
 589          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 1]));
 590          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 2]));
 591          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 3]));
 592          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 4]));
 593          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 5]));
 594          $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 6]));
 595          $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 7]));
 596          $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 8]));
 597  
 598          $params['courseid'] = $course2->id;
 599          $params['instance'] = $moduleinstance2->id;
 600          $event9 = create_event(array_merge($params, ['name' => 'Event 9', 'timesort' => 1]));
 601          $event10 = create_event(array_merge($params, ['name' => 'Event 10', 'timesort' => 2]));
 602          $event11 = create_event(array_merge($params, ['name' => 'Event 11', 'timesort' => 3]));
 603          $event12 = create_event(array_merge($params, ['name' => 'Event 12', 'timesort' => 4]));
 604          $event13 = create_event(array_merge($params, ['name' => 'Event 13', 'timesort' => 5]));
 605          $event14 = create_event(array_merge($params, ['name' => 'Event 14', 'timesort' => 6]));
 606          $event15 = create_event(array_merge($params, ['name' => 'Event 15', 'timesort' => 7]));
 607          $event16 = create_event(array_merge($params, ['name' => 'Event 16', 'timesort' => 8]));
 608  
 609          $result = \core_calendar\local\api::get_action_events_by_course($course1, 2, 7, $event3->id, 2);
 610  
 611          $this->assertCount(2, $result);
 612          $this->assertEquals('Event 4', $result[0]->get_name());
 613          $this->assertEquals('Event 5', $result[1]->get_name());
 614  
 615          $result = \core_calendar\local\api::get_action_events_by_course($course1, 2, 7, $event5->id, 2);
 616  
 617          $this->assertCount(2, $result);
 618          $this->assertEquals('Event 6', $result[0]->get_name());
 619          $this->assertEquals('Event 7', $result[1]->get_name());
 620  
 621          $result = \core_calendar\local\api::get_action_events_by_course($course1, 2, 7, $event7->id, 2);
 622  
 623          $this->assertEmpty($result);
 624      }
 625  
 626      /**
 627       * Test that get_action_events_by_courses will return a list of events for each
 628       * course you provided as long as the user is enrolled in the course.
 629       */
 630      public function test_get_action_events_by_courses() {
 631          $user = $this->getDataGenerator()->create_user();
 632          $course1 = $this->getDataGenerator()->create_course();
 633          $course2 = $this->getDataGenerator()->create_course();
 634          $course3 = $this->getDataGenerator()->create_course();
 635          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 636          $moduleinstance1 = $generator->create_instance(['course' => $course1->id]);
 637          $moduleinstance2 = $generator->create_instance(['course' => $course2->id]);
 638          $moduleinstance3 = $generator->create_instance(['course' => $course3->id]);
 639  
 640          $this->getDataGenerator()->enrol_user($user->id, $course1->id);
 641          $this->getDataGenerator()->enrol_user($user->id, $course2->id);
 642          $this->getDataGenerator()->enrol_user($user->id, $course3->id);
 643          $this->resetAfterTest(true);
 644          $this->setUser($user);
 645  
 646          $params = [
 647              'type' => CALENDAR_EVENT_TYPE_ACTION,
 648              'modulename' => 'assign',
 649              'instance' => $moduleinstance1->id,
 650              'userid' => $user->id,
 651              'courseid' => $course1->id,
 652              'eventtype' => 'user',
 653              'repeats' => 0,
 654              'timestart' => 1,
 655          ];
 656  
 657          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 1]));
 658          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 2]));
 659  
 660          $params['courseid'] = $course2->id;
 661          $params['instance'] = $moduleinstance2->id;
 662          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 3]));
 663          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 4]));
 664          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 5]));
 665  
 666          $params['courseid'] = $course3->id;
 667          $params['instance'] = $moduleinstance3->id;
 668          $event6 = create_event(array_merge($params, ['name' => 'Event 6', 'timesort' => 6]));
 669          $event7 = create_event(array_merge($params, ['name' => 'Event 7', 'timesort' => 7]));
 670          $event8 = create_event(array_merge($params, ['name' => 'Event 8', 'timesort' => 8]));
 671          $event9 = create_event(array_merge($params, ['name' => 'Event 9', 'timesort' => 9]));
 672  
 673          $result = \core_calendar\local\api::get_action_events_by_courses([], 1);
 674  
 675          $this->assertEmpty($result);
 676  
 677          $result = \core_calendar\local\api::get_action_events_by_courses([$course1], 3);
 678  
 679          $this->assertEmpty($result[$course1->id]);
 680  
 681          $result = \core_calendar\local\api::get_action_events_by_courses([$course1], 1);
 682  
 683          $this->assertCount(2, $result[$course1->id]);
 684          $this->assertEquals('Event 1', $result[$course1->id][0]->get_name());
 685          $this->assertEquals('Event 2', $result[$course1->id][1]->get_name());
 686  
 687          $result = \core_calendar\local\api::get_action_events_by_courses([$course1, $course2], 1);
 688  
 689          $this->assertCount(2, $result[$course1->id]);
 690          $this->assertEquals('Event 1', $result[$course1->id][0]->get_name());
 691          $this->assertEquals('Event 2', $result[$course1->id][1]->get_name());
 692          $this->assertCount(3, $result[$course2->id]);
 693          $this->assertEquals('Event 3', $result[$course2->id][0]->get_name());
 694          $this->assertEquals('Event 4', $result[$course2->id][1]->get_name());
 695          $this->assertEquals('Event 5', $result[$course2->id][2]->get_name());
 696  
 697          $result = \core_calendar\local\api::get_action_events_by_courses([$course1, $course2], 2, 4);
 698  
 699          $this->assertCount(1, $result[$course1->id]);
 700          $this->assertEquals('Event 2', $result[$course1->id][0]->get_name());
 701          $this->assertCount(2, $result[$course2->id]);
 702          $this->assertEquals('Event 3', $result[$course2->id][0]->get_name());
 703          $this->assertEquals('Event 4', $result[$course2->id][1]->get_name());
 704  
 705          $result = \core_calendar\local\api::get_action_events_by_courses([$course1, $course2, $course3], 1, null, 1);
 706  
 707          $this->assertCount(1, $result[$course1->id]);
 708          $this->assertEquals('Event 1', $result[$course1->id][0]->get_name());
 709          $this->assertCount(1, $result[$course2->id]);
 710          $this->assertEquals('Event 3', $result[$course2->id][0]->get_name());
 711          $this->assertCount(1, $result[$course3->id]);
 712          $this->assertEquals('Event 6', $result[$course3->id][0]->get_name());
 713      }
 714  
 715      /**
 716       * Test get_action_events_by_courses with search feature.
 717       * @covers ::get_action_events_by_courses
 718       */
 719      public function test_get_action_events_by_courses_with_search() {
 720          // Generate data.
 721          $user = $this->getDataGenerator()->create_user();
 722          $course1 = $this->getDataGenerator()->create_course(['fullname' => 'Course with advanced name']);
 723          $course2 = $this->getDataGenerator()->create_course(['fullname' => 'Another name']);
 724          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 725          $moduleinstance1 = $generator->create_instance(['course' => $course1->id]);
 726          $moduleinstance2 = $generator->create_instance(['course' => $course2->id]);
 727  
 728          $this->getDataGenerator()->enrol_user($user->id, $course1->id);
 729          $this->getDataGenerator()->enrol_user($user->id, $course2->id);
 730          $this->resetAfterTest(true);
 731          $this->setUser($user);
 732  
 733          $params = [
 734              'type' => CALENDAR_EVENT_TYPE_ACTION,
 735              'modulename' => 'assign',
 736              'instance' => $moduleinstance1->id,
 737              'userid' => $user->id,
 738              'courseid' => $course1->id,
 739              'eventtype' => 'user',
 740              'repeats' => 0,
 741              'timestart' => 1,
 742          ];
 743  
 744          $event1 = create_event(array_merge($params, ['name' => 'Event 1', 'timesort' => 1]));
 745          $event2 = create_event(array_merge($params, ['name' => 'Event 2', 'timesort' => 2]));
 746  
 747          $params['courseid'] = $course2->id;
 748          $params['instance'] = $moduleinstance2->id;
 749          $event3 = create_event(array_merge($params, ['name' => 'Event 3', 'timesort' => 3]));
 750          $event4 = create_event(array_merge($params, ['name' => 'Event 4', 'timesort' => 4]));
 751          $event5 = create_event(array_merge($params, ['name' => 'Event 5', 'timesort' => 5]));
 752  
 753          // No result found for fake search.
 754          $result = \core_calendar\local\api::get_action_events_by_courses(
 755              [$course1, $course2], 1, null, '6', 'Fake search');
 756          $this->assertEmpty($result[$course1->id]);
 757          $this->assertEmpty($result[$course2->id]);
 758  
 759          // Search for course name called 'Course with advanced name'.
 760          $result = \core_calendar\local\api::get_action_events_by_courses(
 761              [$course1, $course2], 1, null, '6', 'Course with advanced name');
 762          $this->assertNotEmpty($result[$course1->id]);
 763          $this->assertEmpty($result[$course2->id]);
 764          $this->assertEquals('Event 1', $result[$course1->id][0]->get_name());
 765          $this->assertEquals('Event 2', $result[$course1->id][1]->get_name());
 766  
 767          // Search for course name contains 'Course advanced'.
 768          $result = \core_calendar\local\api::get_action_events_by_courses(
 769              [$course1, $course2], 1, null, '6', 'Course advanced');
 770          $this->assertNotEmpty($result[$course1->id]);
 771          $this->assertEmpty($result[$course2->id]);
 772          $this->assertEquals('Event 1', $result[$course1->id][0]->get_name());
 773          $this->assertEquals('Event 2', $result[$course1->id][1]->get_name());
 774  
 775          // Search for course name contains 'name'.
 776          $result = \core_calendar\local\api::get_action_events_by_courses(
 777              [$course1, $course2], 1, null, '6', 'name');
 778          $this->assertNotEmpty($result[$course1->id]);
 779          $this->assertNotEmpty($result[$course2->id]);
 780          $this->assertEquals('Event 1', $result[$course1->id][0]->get_name());
 781          $this->assertEquals('Event 2', $result[$course1->id][1]->get_name());
 782          $this->assertEquals('Event 3', $result[$course2->id][0]->get_name());
 783          $this->assertEquals('Event 4', $result[$course2->id][1]->get_name());
 784          $this->assertEquals('Event 5', $result[$course2->id][2]->get_name());
 785      }
 786  
 787      /**
 788       * Test that the get_legacy_events() function only returns activity events that are enabled.
 789       */
 790      public function test_get_legacy_events_with_disabled_module() {
 791          global $DB;
 792  
 793          $this->setAdminUser();
 794  
 795          $course = $this->getDataGenerator()->create_course();
 796  
 797          $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 798          $assigninstance = $assigngenerator->create_instance(['course' => $course->id]);
 799  
 800          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 801          $lessoninstance = $lessongenerator->create_instance(['course' => $course->id]);
 802          $student = $this->getDataGenerator()->create_user();
 803          $this->getDataGenerator()->enrol_user($student->id, $course->id, 'student');
 804          $this->setUser($student);
 805          $events = [
 806              [
 807                  'name' => 'Start of assignment',
 808                  'description' => '',
 809                  'location' => 'Test',
 810                  'format' => 1,
 811                  'courseid' => $course->id,
 812                  'groupid' => 0,
 813                  'userid' => 2,
 814                  'modulename' => 'assign',
 815                  'instance' => $assigninstance->id,
 816                  'eventtype' => 'due',
 817                  'timestart' => time(),
 818                  'timeduration' => 86400,
 819                  'visible' => 1
 820              ], [
 821                  'name' => 'Start of lesson',
 822                  'description' => '',
 823                  'location' => 'Test',
 824                  'format' => 1,
 825                  'courseid' => $course->id,
 826                  'groupid' => 0,
 827                  'userid' => 2,
 828                  'modulename' => 'lesson',
 829                  'instance' => $lessoninstance->id,
 830                  'eventtype' => 'end',
 831                  'timestart' => time(),
 832                  'timeduration' => 86400,
 833                  'visible' => 1
 834              ]
 835          ];
 836          foreach ($events as $event) {
 837              \calendar_event::create($event, false);
 838          }
 839          $timestart = time() - 60;
 840          $timeend = time() + 60;
 841  
 842          // Get all events.
 843          $events = calendar_get_legacy_events($timestart, $timeend, true, 0, true);
 844          $this->assertCount(2, $events);
 845  
 846          // Disable the lesson module.
 847          $modulerecord = $DB->get_record('modules', ['name' => 'lesson']);
 848          $modulerecord->visible = 0;
 849          $DB->update_record('modules', $modulerecord);
 850  
 851          // Check that we only return the assign event.
 852          $events = calendar_get_legacy_events($timestart, $timeend, true, 0, true);
 853          $this->assertCount(1, $events);
 854          $event = reset($events);
 855          $this->assertEquals('assign', $event->modulename);
 856      }
 857  
 858      /**
 859       * Test for \core_calendar\local\api::get_legacy_events() when there are user and group overrides.
 860       */
 861      public function test_get_legacy_events_with_overrides() {
 862          $generator = $this->getDataGenerator();
 863  
 864          $course = $generator->create_course();
 865  
 866          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 867          if (!isset($params['course'])) {
 868              $params['course'] = $course->id;
 869          }
 870  
 871          $instance = $plugingenerator->create_instance($params);
 872  
 873          // Create users.
 874          $useroverridestudent = $generator->create_user();
 875          $group1student = $generator->create_user();
 876          $group2student = $generator->create_user();
 877          $group12student = $generator->create_user();
 878          $nogroupstudent = $generator->create_user();
 879  
 880          // Enrol users.
 881          $generator->enrol_user($useroverridestudent->id, $course->id, 'student');
 882          $generator->enrol_user($group1student->id, $course->id, 'student');
 883          $generator->enrol_user($group2student->id, $course->id, 'student');
 884          $generator->enrol_user($group12student->id, $course->id, 'student');
 885          $generator->enrol_user($nogroupstudent->id, $course->id, 'student');
 886  
 887          // Create groups.
 888          $group1 = $generator->create_group(['courseid' => $course->id]);
 889          $group2 = $generator->create_group(['courseid' => $course->id]);
 890  
 891          // Add members to groups.
 892          $generator->create_group_member(['groupid' => $group1->id, 'userid' => $group1student->id]);
 893          $generator->create_group_member(['groupid' => $group2->id, 'userid' => $group2student->id]);
 894          $generator->create_group_member(['groupid' => $group1->id, 'userid' => $group12student->id]);
 895          $generator->create_group_member(['groupid' => $group2->id, 'userid' => $group12student->id]);
 896          $now = time();
 897  
 898          // Events with the same module name, instance and event type.
 899          $events = [
 900              [
 901                  'name' => 'Assignment 1 due date',
 902                  'description' => '',
 903                  'location' => 'Test',
 904                  'format' => 0,
 905                  'courseid' => $course->id,
 906                  'groupid' => 0,
 907                  'userid' => 2,
 908                  'modulename' => 'assign',
 909                  'instance' => $instance->id,
 910                  'eventtype' => 'due',
 911                  'timestart' => $now,
 912                  'timeduration' => 0,
 913                  'visible' => 1
 914              ], [
 915                  'name' => 'Assignment 1 due date - User override',
 916                  'description' => '',
 917                  'location' => 'Test',
 918                  'format' => 1,
 919                  'courseid' => 0,
 920                  'groupid' => 0,
 921                  'userid' => $useroverridestudent->id,
 922                  'modulename' => 'assign',
 923                  'instance' => $instance->id,
 924                  'eventtype' => 'due',
 925                  'timestart' => $now + 86400,
 926                  'timeduration' => 0,
 927                  'visible' => 1,
 928                  'priority' => CALENDAR_EVENT_USER_OVERRIDE_PRIORITY
 929              ], [
 930                  'name' => 'Assignment 1 due date - Group A override',
 931                  'description' => '',
 932                  'location' => 'Test',
 933                  'format' => 1,
 934                  'courseid' => $course->id,
 935                  'groupid' => $group1->id,
 936                  'userid' => 2,
 937                  'modulename' => 'assign',
 938                  'instance' => $instance->id,
 939                  'eventtype' => 'due',
 940                  'timestart' => $now + (2 * 86400),
 941                  'timeduration' => 0,
 942                  'visible' => 1,
 943                  'priority' => 1,
 944              ], [
 945                  'name' => 'Assignment 1 due date - Group B override',
 946                  'description' => '',
 947                  'location' => 'Test',
 948                  'format' => 1,
 949                  'courseid' => $course->id,
 950                  'groupid' => $group2->id,
 951                  'userid' => 2,
 952                  'modulename' => 'assign',
 953                  'instance' => $instance->id,
 954                  'eventtype' => 'due',
 955                  'timestart' => $now + (3 * 86400),
 956                  'timeduration' => 0,
 957                  'visible' => 1,
 958                  'priority' => 2,
 959              ],
 960          ];
 961  
 962          foreach ($events as $event) {
 963              \calendar_event::create($event, false);
 964          }
 965  
 966          $timestart = $now - 100;
 967          $timeend = $now + (3 * 86400);
 968          $groups = [$group1->id, $group2->id];
 969  
 970          // Get user override events.
 971          $this->setUser($useroverridestudent);
 972          $events = calendar_get_legacy_events($timestart, $timeend, $useroverridestudent->id, $groups, $course->id);
 973          $this->assertCount(1, $events);
 974          $event = reset($events);
 975          $this->assertEquals('Assignment 1 due date - User override', $event->name);
 976  
 977          // Get event for user with override but with the timestart and timeend parameters only covering the original event.
 978          $events = calendar_get_legacy_events($timestart, $now, $useroverridestudent->id, $groups, $course->id);
 979          $this->assertCount(0, $events);
 980  
 981          // Get events for user that does not belong to any group and has no user override events.
 982          $this->setUser($nogroupstudent);
 983          $events = calendar_get_legacy_events($timestart, $timeend, $nogroupstudent->id, $groups, $course->id);
 984          $this->assertCount(1, $events);
 985          $event = reset($events);
 986          $this->assertEquals('Assignment 1 due date', $event->name);
 987  
 988          // Get events for user that belongs to groups A and B and has no user override events.
 989          $this->setUser($group12student);
 990          $events = calendar_get_legacy_events($timestart, $timeend, $group12student->id, $groups, $course->id);
 991          $this->assertCount(1, $events);
 992          $event = reset($events);
 993          $this->assertEquals('Assignment 1 due date - Group A override', $event->name);
 994  
 995          // Get events for user that belongs to group A and has no user override events.
 996          $this->setUser($group1student);
 997          $events = calendar_get_legacy_events($timestart, $timeend, $group1student->id, $groups, $course->id);
 998          $this->assertCount(1, $events);
 999          $event = reset($events);
1000          $this->assertEquals('Assignment 1 due date - Group A override', $event->name);
1001  
1002          // Add repeating events.
1003          $repeatingevents = [
1004              [
1005                  'name' => 'Repeating site event',
1006                  'description' => '',
1007                  'location' => 'Test',
1008                  'format' => 1,
1009                  'courseid' => SITEID,
1010                  'groupid' => 0,
1011                  'userid' => 2,
1012                  'repeatid' => $event->id,
1013                  'modulename' => '0',
1014                  'instance' => 0,
1015                  'eventtype' => 'site',
1016                  'timestart' => $now + 86400,
1017                  'timeduration' => 0,
1018                  'visible' => 1,
1019              ],
1020              [
1021                  'name' => 'Repeating site event',
1022                  'description' => '',
1023                  'location' => 'Test',
1024                  'format' => 1,
1025                  'courseid' => SITEID,
1026                  'groupid' => 0,
1027                  'userid' => 2,
1028                  'repeatid' => $event->id,
1029                  'modulename' => '0',
1030                  'instance' => 0,
1031                  'eventtype' => 'site',
1032                  'timestart' => $now + (2 * 86400),
1033                  'timeduration' => 0,
1034                  'visible' => 1,
1035              ],
1036          ];
1037  
1038          foreach ($repeatingevents as $event) {
1039              \calendar_event::create($event, false);
1040          }
1041  
1042          // Make sure repeating events are not filtered out.
1043          $events = calendar_get_legacy_events($timestart, $timeend, true, true, true);
1044          $this->assertCount(3, $events);
1045      }
1046  
1047      /**
1048       * Setting the start date on the calendar event should update the date
1049       * of the event but should leave the time of day unchanged.
1050       */
1051      public function test_update_event_start_day_updates_date() {
1052          $generator = $this->getDataGenerator();
1053          $user = $generator->create_user();
1054          $roleid = $generator->create_role();
1055          $context = \context_system::instance();
1056          $originalstarttime = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1057          $newstartdate = new \DateTimeImmutable('2018-02-2T10:00:00+08:00');
1058          $expected = new \DateTimeImmutable('2018-02-2T15:00:00+08:00');
1059          $mapper = container::get_event_mapper();
1060  
1061          $generator->role_assign($roleid, $user->id, $context->id);
1062          assign_capability('moodle/calendar:manageownentries', CAP_ALLOW, $roleid, $context, true);
1063  
1064          $this->setUser($user);
1065          $this->resetAfterTest(true);
1066  
1067          $event = create_event([
1068              'name' => 'Test event',
1069              'userid' => $user->id,
1070              'eventtype' => 'user',
1071              'repeats' => 0,
1072              'timestart' => $originalstarttime->getTimestamp(),
1073          ]);
1074          $event = $mapper->from_legacy_event_to_event($event);
1075  
1076          $newEvent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1077          $actual = $newEvent->get_times()->get_start_time();
1078  
1079          $this->assertEquals($expected->getTimestamp(), $actual->getTimestamp());
1080      }
1081  
1082      /**
1083       * A user should not be able to update the start date of the event
1084       * that they don't have the capabilities to modify.
1085       */
1086      public function test_update_event_start_day_no_permission() {
1087          $generator = $this->getDataGenerator();
1088          $user = $generator->create_user();
1089          $roleid = $generator->create_role();
1090          $context = \context_system::instance();
1091          $originalstarttime = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1092          $newstartdate = new \DateTimeImmutable('2018-02-2T10:00:00+08:00');
1093          $expected = new \DateTimeImmutable('2018-02-2T15:00:00+08:00');
1094          $mapper = container::get_event_mapper();
1095  
1096          $generator->role_assign($roleid, $user->id, $context->id);
1097  
1098          $this->setUser($user);
1099          $this->resetAfterTest(true);
1100  
1101          $event = create_event([
1102              'name' => 'Test event',
1103              'userid' => $user->id,
1104              'eventtype' => 'user',
1105              'repeats' => 0,
1106              'timestart' => $originalstarttime->getTimestamp(),
1107          ]);
1108          $event = $mapper->from_legacy_event_to_event($event);
1109  
1110          assign_capability('moodle/calendar:manageownentries', CAP_PROHIBIT, $roleid, $context, true);
1111          $this->expectException('moodle_exception');
1112          $newEvent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1113      }
1114  
1115      /**
1116       * Updating the start day of an event with no maximum cutoff should
1117       * update the corresponding activity property.
1118       *
1119       * Note: This test uses the feedback activity because it requires
1120       * module callbacks to be in place to test.
1121       */
1122      public function test_update_event_start_day_activity_event_no_max() {
1123          global $CFG, $DB;
1124          require_once($CFG->dirroot . '/mod/feedback/lib.php');
1125  
1126          $this->resetAfterTest(true);
1127          $this->setAdminUser();
1128          $timeopen = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1129          $newstartdate = new \DateTimeImmutable('2018-02-2T10:00:00+08:00');
1130          $expected = new \DateTimeImmutable('2018-02-2T15:00:00+08:00');
1131          list($feedback, $event) = $this->create_feedback_activity_and_event(
1132              [
1133                  'timeopen' => $timeopen->getTimestamp(),
1134                  'timeclose' => 0
1135              ],
1136              [
1137                  'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
1138                  'timestart' => $timeopen->getTimestamp()
1139              ]
1140          );
1141          $newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1142          $actual = $newevent->get_times()->get_start_time();
1143          $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
1144  
1145          $this->assertEquals($expected->getTimestamp(), $actual->getTimestamp());
1146          $this->assertEquals($expected->getTimestamp(), $feedback->timeopen);
1147      }
1148  
1149      /**
1150       * Updating the start day of an event belonging to an activity to a value
1151       * less than the maximum cutoff should update the corresponding activity
1152       * property.
1153       *
1154       * Note: This test uses the feedback activity because it requires
1155       * module callbacks to be in place to test.
1156       */
1157      public function test_update_event_start_day_activity_event_less_than_max() {
1158          global $CFG, $DB;
1159          require_once($CFG->dirroot . '/mod/feedback/lib.php');
1160  
1161          $this->resetAfterTest(true);
1162          $this->setAdminUser();
1163          $timeopen = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1164          $timeclose = new \DateTimeImmutable('2019-01-1T15:00:00+08:00');
1165          $newstartdate = new \DateTimeImmutable('2018-02-2T10:00:00+08:00');
1166          $expected = new \DateTimeImmutable('2018-02-2T15:00:00+08:00');
1167          list($feedback, $event) = $this->create_feedback_activity_and_event(
1168              [
1169                  'timeopen' => $timeopen->getTimestamp(),
1170                  'timeclose' => $timeclose->getTimestamp()
1171              ],
1172              [
1173                  'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
1174                  'timestart' => $timeopen->getTimestamp()
1175              ]
1176          );
1177  
1178          $newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1179          $actual = $newevent->get_times()->get_start_time();
1180          $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
1181  
1182          $this->assertEquals($expected->getTimestamp(), $actual->getTimestamp());
1183          $this->assertEquals($expected->getTimestamp(), $feedback->timeopen);
1184      }
1185  
1186      /**
1187       * Updating the start day of an event belonging to an activity to a value
1188       * equal to the maximum cutoff should update the corresponding activity
1189       * property.
1190       *
1191       * Note: This test uses the feedback activity because it requires
1192       * module callbacks to be in place to test.
1193       */
1194      public function test_update_event_start_day_activity_event_equal_to_max() {
1195          global $CFG, $DB;
1196          require_once($CFG->dirroot . '/mod/feedback/lib.php');
1197  
1198          $this->resetAfterTest(true);
1199          $this->setAdminUser();
1200          $timeopen = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1201          $timeclose = new \DateTimeImmutable('2018-02-2T15:00:00+08:00');
1202          $newstartdate = new \DateTimeImmutable('2018-02-2T10:00:00+08:00');
1203          list($feedback, $event) = $this->create_feedback_activity_and_event(
1204              [
1205                  'timeopen' => $timeopen->getTimestamp(),
1206                  'timeclose' => $timeclose->getTimestamp(),
1207              ],
1208              [
1209                  'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
1210                  'timestart' => $timeopen->getTimestamp()
1211              ]
1212          );
1213  
1214          $newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1215          $actual = $newevent->get_times()->get_start_time();
1216          $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
1217  
1218          $this->assertEquals($timeclose->getTimestamp(), $actual->getTimestamp());
1219          $this->assertEquals($timeclose->getTimestamp(), $feedback->timeopen);
1220      }
1221  
1222      /**
1223       * Updating the start day of an event belonging to an activity to a value
1224       * after the maximum cutoff should not update the corresponding activity
1225       * property. Instead it should throw an exception.
1226       *
1227       * Note: This test uses the feedback activity because it requires
1228       * module callbacks to be in place to test.
1229       */
1230      public function test_update_event_start_day_activity_event_after_max() {
1231          global $CFG, $DB;
1232          require_once($CFG->dirroot . '/mod/feedback/lib.php');
1233  
1234          $this->resetAfterTest(true);
1235          $this->setAdminUser();
1236          $timeopen = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1237          $timeclose = new \DateTimeImmutable('2017-02-2T15:00:00+08:00');
1238          $newstartdate = new \DateTimeImmutable('2018-02-2T10:00:00+08:00');
1239          list($feedback, $event) = $this->create_feedback_activity_and_event(
1240              [
1241                  'timeopen' => $timeopen->getTimestamp(),
1242                  'timeclose' => $timeclose->getTimestamp(),
1243              ],
1244              [
1245                  'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
1246                  'timestart' => $timeopen->getTimestamp()
1247              ]
1248          );
1249  
1250          $this->expectException('moodle_exception');
1251          $newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1252      }
1253  
1254      /**
1255       * Updating the start day of an event with no minimum cutoff should
1256       * update the corresponding activity property.
1257       *
1258       * Note: This test uses the feedback activity because it requires
1259       * module callbacks to be in place to test.
1260       */
1261      public function test_update_event_start_day_activity_event_no_min() {
1262          global $CFG, $DB;
1263          require_once($CFG->dirroot . '/mod/feedback/lib.php');
1264  
1265          $this->resetAfterTest(true);
1266          $this->setAdminUser();
1267          $timeclose = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1268          $newstartdate = new \DateTimeImmutable('2016-02-2T10:00:00+08:00');
1269          $expected = new \DateTimeImmutable('2016-02-2T15:00:00+08:00');
1270          list($feedback, $event) = $this->create_feedback_activity_and_event(
1271              [
1272                  'timeopen' => 0,
1273                  'timeclose' => $timeclose->getTimestamp()
1274              ],
1275              [
1276                  'eventtype' => FEEDBACK_EVENT_TYPE_OPEN,
1277                  'timestart' => $timeclose->getTimestamp()
1278              ]
1279          );
1280  
1281          $newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1282          $actual = $newevent->get_times()->get_start_time();
1283          $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
1284  
1285          $this->assertEquals($expected->getTimestamp(), $actual->getTimestamp());
1286          $this->assertEquals($expected->getTimestamp(), $feedback->timeopen);
1287      }
1288  
1289      /**
1290       * Updating the start day of an event belonging to an activity to a value
1291       * greater than the minimum cutoff should update the corresponding activity
1292       * property.
1293       *
1294       * Note: This test uses the feedback activity because it requires
1295       * module callbacks to be in place to test.
1296       */
1297      public function test_update_event_start_day_activity_event_greater_than_min() {
1298          global $CFG, $DB;
1299          require_once($CFG->dirroot . '/mod/feedback/lib.php');
1300  
1301          $this->resetAfterTest(true);
1302          $this->setAdminUser();
1303          $timeopen = new \DateTimeImmutable('2016-01-1T15:00:00+08:00');
1304          $timeclose = new \DateTimeImmutable('2019-01-1T15:00:00+08:00');
1305          $newstartdate = new \DateTimeImmutable('2018-02-2T10:00:00+08:00');
1306          $expected = new \DateTimeImmutable('2018-02-2T15:00:00+08:00');
1307          list($feedback, $event) = $this->create_feedback_activity_and_event(
1308              [
1309                  'timeopen' => $timeopen->getTimestamp(),
1310                  'timeclose' => $timeclose->getTimestamp()
1311              ],
1312              [
1313                  'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
1314                  'timestart' => $timeclose->getTimestamp()
1315              ]
1316          );
1317  
1318          $newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1319          $actual = $newevent->get_times()->get_start_time();
1320          $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
1321  
1322          $this->assertEquals($expected->getTimestamp(), $actual->getTimestamp());
1323          $this->assertEquals($expected->getTimestamp(), $feedback->timeclose);
1324      }
1325  
1326      /**
1327       * Updating the start day of an event belonging to an activity to a value
1328       * equal to the minimum cutoff should update the corresponding activity
1329       * property.
1330       *
1331       * Note: This test uses the feedback activity because it requires
1332       * module callbacks to be in place to test.
1333       */
1334      public function test_update_event_start_day_activity_event_equal_to_min() {
1335          global $CFG, $DB;
1336          require_once($CFG->dirroot . '/mod/feedback/lib.php');
1337  
1338          $this->resetAfterTest(true);
1339          $this->setAdminUser();
1340          $timeopen = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1341          $timeclose = new \DateTimeImmutable('2018-02-2T15:00:00+08:00');
1342          $newstartdate = new \DateTimeImmutable('2017-01-1T10:00:00+08:00');
1343          $expected = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1344          list($feedback, $event) = $this->create_feedback_activity_and_event(
1345              [
1346                  'timeopen' => $timeopen->getTimestamp(),
1347                  'timeclose' => $timeclose->getTimestamp(),
1348              ],
1349              [
1350                  'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
1351                  'timestart' => $timeclose->getTimestamp()
1352              ]
1353          );
1354  
1355          $newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1356          $actual = $newevent->get_times()->get_start_time();
1357          $feedback = $DB->get_record('feedback', ['id' => $feedback->id]);
1358  
1359          $this->assertEquals($expected->getTimestamp(), $actual->getTimestamp());
1360          $this->assertEquals($expected->getTimestamp(), $feedback->timeclose);
1361      }
1362  
1363      /**
1364       * Updating the start day of an event belonging to an activity to a value
1365       * before the minimum cutoff should not update the corresponding activity
1366       * property. Instead it should throw an exception.
1367       *
1368       * Note: This test uses the feedback activity because it requires
1369       * module callbacks to be in place to test.
1370       */
1371      public function test_update_event_start_day_activity_event_before_min() {
1372          global $CFG, $DB;
1373          require_once($CFG->dirroot . '/mod/feedback/lib.php');
1374  
1375          $this->resetAfterTest(true);
1376          $this->setAdminUser();
1377          $timeopen = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1378          $timeclose = new \DateTimeImmutable('2017-02-2T15:00:00+08:00');
1379          $newstartdate = new \DateTimeImmutable('2016-02-2T10:00:00+08:00');
1380          list($feedback, $event) = $this->create_feedback_activity_and_event(
1381              [
1382                  'timeopen' => $timeopen->getTimestamp(),
1383                  'timeclose' => $timeclose->getTimestamp(),
1384              ],
1385              [
1386                  'eventtype' => FEEDBACK_EVENT_TYPE_CLOSE,
1387                  'timestart' => $timeclose->getTimestamp()
1388              ]
1389          );
1390  
1391          $this->expectException('moodle_exception');
1392          $newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1393      }
1394  
1395      /**
1396       * Updating the start day of an overridden event belonging to an activity
1397       * should result in an exception. This is to prevent the drag and drop
1398       * of override events.
1399       *
1400       * Note: This test uses the quiz activity because it requires
1401       * module callbacks to be in place and override event support to test.
1402       */
1403      public function test_update_event_start_day_activity_event_override() {
1404          global $CFG, $DB;
1405          require_once($CFG->dirroot . '/calendar/lib.php');
1406          require_once($CFG->dirroot . '/mod/quiz/lib.php');
1407  
1408          $this->resetAfterTest(true);
1409          $this->setAdminUser();
1410          $mapper = container::get_event_mapper();
1411          $timeopen = new \DateTimeImmutable('2017-01-1T15:00:00+08:00');
1412          $newstartdate = new \DateTimeImmutable('2016-02-2T10:00:00+08:00');
1413          $generator = $this->getDataGenerator();
1414          $user = $generator->create_user();
1415          $course = $generator->create_course();
1416          $quizgenerator = $generator->get_plugin_generator('mod_quiz');
1417          $quiz = $quizgenerator->create_instance([
1418              'course' => $course->id,
1419              'timeopen' => $timeopen->getTimestamp(),
1420          ]);
1421          $event = create_event([
1422              'courseid' => $course->id,
1423              'userid' => $user->id,
1424              'modulename' => 'quiz',
1425              'instance' => $quiz->id,
1426              'eventtype' => QUIZ_EVENT_TYPE_OPEN,
1427              'timestart' => $timeopen->getTimestamp()
1428          ]);
1429          $event = $mapper->from_legacy_event_to_event($event);
1430          $record = (object) [
1431              'quiz' => $quiz->id,
1432              'userid' => $user->id
1433          ];
1434  
1435          $DB->insert_record('quiz_overrides', $record);
1436  
1437          $this->expectException('moodle_exception');
1438          $newevent = \core_calendar\local\api::update_event_start_day($event, $newstartdate);
1439      }
1440  }