Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

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

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