Search moodle.org's
Developer Documentation

See Release Notes

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

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

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