Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

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

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

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace core_calendar;
  18  
  19  /**
  20   * Class contaning unit tests for the calendar lib.
  21   *
  22   * @package    core_calendar
  23   * @copyright  2017 Mark Nelson <markn@moodle.com>
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  class lib_test extends \advanced_testcase {
  27  
  28      /**
  29       * Load required test libraries
  30       */
  31      public static function setUpBeforeClass(): void {
  32          global $CFG;
  33  
  34          require_once("{$CFG->dirroot}/calendar/tests/helpers.php");
  35      }
  36  
  37      /**
  38       * Tests set up
  39       */
  40      protected function setUp(): void {
  41          $this->resetAfterTest();
  42      }
  43  
  44      /**
  45       * Test that the get_events() function only returns activity events that are enabled.
  46       */
  47      public function test_get_events_with_disabled_module() {
  48          global $DB;
  49          $this->setAdminUser();
  50          $generator = $this->getDataGenerator();
  51          $course = $generator->create_course();
  52          $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
  53          $assigninstance = $assigngenerator->create_instance(['course' => $course->id]);
  54          $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
  55          $lessoninstance = $lessongenerator->create_instance(['course' => $course->id]);
  56          $student = $generator->create_user();
  57          $generator->enrol_user($student->id, $course->id, 'student');
  58          $this->setUser($student);
  59          $events = [
  60              [
  61                  'name' => 'Start of assignment',
  62                  'description' => '',
  63                  'location' => 'Test',
  64                  'format' => 1,
  65                  'courseid' => $course->id,
  66                  'groupid' => 0,
  67                  'userid' => 2,
  68                  'modulename' => 'assign',
  69                  'instance' => $assigninstance->id,
  70                  'eventtype' => 'due',
  71                  'timestart' => time(),
  72                  'timeduration' => 86400,
  73                  'visible' => 1
  74              ], [
  75                  'name' => 'Start of lesson',
  76                  'description' => '',
  77                  'location' => 'Test',
  78                  'format' => 1,
  79                  'courseid' => $course->id,
  80                  'groupid' => 0,
  81                  'userid' => 2,
  82                  'modulename' => 'lesson',
  83                  'instance' => $lessoninstance->id,
  84                  'eventtype' => 'end',
  85                  'timestart' => time(),
  86                  'timeduration' => 86400,
  87                  'visible' => 1
  88              ]
  89          ];
  90          foreach ($events as $event) {
  91              \calendar_event::create($event, false);
  92          }
  93          $timestart = time() - 60;
  94          $timeend = time() + 60;
  95          // Get all events.
  96          $events = calendar_get_events($timestart, $timeend, true, 0, true);
  97          $this->assertCount(2, $events);
  98          // Disable the lesson module.
  99          $modulerecord = $DB->get_record('modules', ['name' => 'lesson']);
 100          $modulerecord->visible = 0;
 101          $DB->update_record('modules', $modulerecord);
 102          // Check that we only return the assign event.
 103          $events = calendar_get_events($timestart, $timeend, true, 0, true);
 104          $this->assertCount(1, $events);
 105          $event = reset($events);
 106          $this->assertEquals('assign', $event->modulename);
 107      }
 108  
 109      public function test_get_course_cached() {
 110          // Setup some test courses.
 111          $course1 = $this->getDataGenerator()->create_course();
 112          $course2 = $this->getDataGenerator()->create_course();
 113          $course3 = $this->getDataGenerator()->create_course();
 114  
 115          // Load courses into cache.
 116          $coursecache = null;
 117          calendar_get_course_cached($coursecache, $course1->id);
 118          calendar_get_course_cached($coursecache, $course2->id);
 119          calendar_get_course_cached($coursecache, $course3->id);
 120  
 121          // Verify the cache.
 122          $this->assertArrayHasKey($course1->id, $coursecache);
 123          $cachedcourse1 = $coursecache[$course1->id];
 124          $this->assertEquals($course1->id, $cachedcourse1->id);
 125          $this->assertEquals($course1->shortname, $cachedcourse1->shortname);
 126          $this->assertEquals($course1->fullname, $cachedcourse1->fullname);
 127  
 128          $this->assertArrayHasKey($course2->id, $coursecache);
 129          $cachedcourse2 = $coursecache[$course2->id];
 130          $this->assertEquals($course2->id, $cachedcourse2->id);
 131          $this->assertEquals($course2->shortname, $cachedcourse2->shortname);
 132          $this->assertEquals($course2->fullname, $cachedcourse2->fullname);
 133  
 134          $this->assertArrayHasKey($course3->id, $coursecache);
 135          $cachedcourse3 = $coursecache[$course3->id];
 136          $this->assertEquals($course3->id, $cachedcourse3->id);
 137          $this->assertEquals($course3->shortname, $cachedcourse3->shortname);
 138          $this->assertEquals($course3->fullname, $cachedcourse3->fullname);
 139      }
 140  
 141      /**
 142       * Test the update_subscription() function.
 143       */
 144      public function test_update_subscription() {
 145          $this->resetAfterTest(true);
 146  
 147          $subscription = new \stdClass();
 148          $subscription->eventtype = 'site';
 149          $subscription->name = 'test';
 150          $id = calendar_add_subscription($subscription);
 151  
 152          $subscription = calendar_get_subscription($id);
 153          $subscription->name = 'awesome';
 154          calendar_update_subscription($subscription);
 155          $sub = calendar_get_subscription($id);
 156          $this->assertEquals($subscription->name, $sub->name);
 157  
 158          $subscription = calendar_get_subscription($id);
 159          $subscription->name = 'awesome2';
 160          $subscription->pollinterval = 604800;
 161          calendar_update_subscription($subscription);
 162          $sub = calendar_get_subscription($id);
 163          $this->assertEquals($subscription->name, $sub->name);
 164          $this->assertEquals($subscription->pollinterval, $sub->pollinterval);
 165  
 166          $subscription = new \stdClass();
 167          $subscription->name = 'awesome4';
 168          $this->expectException('coding_exception');
 169          calendar_update_subscription($subscription);
 170      }
 171  
 172      public function test_add_subscription() {
 173          global $DB, $CFG;
 174  
 175          require_once($CFG->dirroot . '/lib/bennu/bennu.inc.php');
 176  
 177          $this->resetAfterTest(true);
 178  
 179          // Test for Microsoft Outlook 2010.
 180          $subscription = new \stdClass();
 181          $subscription->name = 'Microsoft Outlook 2010';
 182          $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE;
 183          $subscription->eventtype = 'site';
 184          $id = calendar_add_subscription($subscription);
 185  
 186          $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/ms_outlook_2010.ics');
 187          $ical = new \iCalendar();
 188          $ical->unserialize($calendar);
 189          $this->assertEquals($ical->parser_errors, array());
 190  
 191          $sub = calendar_get_subscription($id);
 192          calendar_import_events_from_ical($ical, $sub->id);
 193          $count = $DB->count_records('event', array('subscriptionid' => $sub->id));
 194          $this->assertEquals($count, 1);
 195  
 196          // Test for OSX Yosemite.
 197          $subscription = new \stdClass();
 198          $subscription->name = 'OSX Yosemite';
 199          $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE;
 200          $subscription->eventtype = 'site';
 201          $id = calendar_add_subscription($subscription);
 202  
 203          $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/osx_yosemite.ics');
 204          $ical = new \iCalendar();
 205          $ical->unserialize($calendar);
 206          $this->assertEquals($ical->parser_errors, array());
 207  
 208          $sub = calendar_get_subscription($id);
 209          calendar_import_events_from_ical($ical, $sub->id);
 210          $count = $DB->count_records('event', array('subscriptionid' => $sub->id));
 211          $this->assertEquals($count, 1);
 212  
 213          // Test for Google Gmail.
 214          $subscription = new \stdClass();
 215          $subscription->name = 'Google Gmail';
 216          $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE;
 217          $subscription->eventtype = 'site';
 218          $id = calendar_add_subscription($subscription);
 219  
 220          $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/google_gmail.ics');
 221          $ical = new \iCalendar();
 222          $ical->unserialize($calendar);
 223          $this->assertEquals($ical->parser_errors, array());
 224  
 225          $sub = calendar_get_subscription($id);
 226          calendar_import_events_from_ical($ical, $sub->id);
 227          $count = $DB->count_records('event', array('subscriptionid' => $sub->id));
 228          $this->assertEquals($count, 1);
 229  
 230          // Test for ICS file with repeated events.
 231          $subscription = new \stdClass();
 232          $subscription->name = 'Repeated events';
 233          $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE;
 234          $subscription->eventtype = 'site';
 235          $id = calendar_add_subscription($subscription);
 236          $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/repeated_events.ics');
 237          $ical = new \iCalendar();
 238          $ical->unserialize($calendar);
 239          $this->assertEquals($ical->parser_errors, []);
 240  
 241          $sub = calendar_get_subscription($id);
 242          $output = calendar_import_events_from_ical($ical, $sub->id);
 243          $this->assertArrayHasKey('eventsimported', $output);
 244          $this->assertArrayHasKey('eventsskipped', $output);
 245          $this->assertArrayHasKey('eventsupdated', $output);
 246          $this->assertArrayHasKey('eventsdeleted', $output);
 247          $this->assertEquals(1, $output['eventsimported']);
 248          $this->assertEquals(0, $output['eventsskipped']);
 249          $this->assertEquals(0, $output['eventsupdated']);
 250          $this->assertEquals(0, $output['eventsdeleted']);
 251      }
 252  
 253      /**
 254       * Test for calendar_get_legacy_events() when there are user and group overrides.
 255       */
 256      public function test_get_legacy_events_with_overrides() {
 257          $generator = $this->getDataGenerator();
 258  
 259          $course = $generator->create_course();
 260  
 261          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 262          if (!isset($params['course'])) {
 263              $params['course'] = $course->id;
 264          }
 265  
 266          $instance = $plugingenerator->create_instance($params);
 267  
 268          // Create users.
 269          $useroverridestudent = $generator->create_user();
 270          $group1student = $generator->create_user();
 271          $group2student = $generator->create_user();
 272          $group12student = $generator->create_user();
 273          $nogroupstudent = $generator->create_user();
 274  
 275          // Enrol users.
 276          $generator->enrol_user($useroverridestudent->id, $course->id, 'student');
 277          $generator->enrol_user($group1student->id, $course->id, 'student');
 278          $generator->enrol_user($group2student->id, $course->id, 'student');
 279          $generator->enrol_user($group12student->id, $course->id, 'student');
 280          $generator->enrol_user($nogroupstudent->id, $course->id, 'student');
 281  
 282          // Create groups.
 283          $group1 = $generator->create_group(['courseid' => $course->id]);
 284          $group2 = $generator->create_group(['courseid' => $course->id]);
 285  
 286          // Add members to groups.
 287          $generator->create_group_member(['groupid' => $group1->id, 'userid' => $group1student->id]);
 288          $generator->create_group_member(['groupid' => $group2->id, 'userid' => $group2student->id]);
 289          $generator->create_group_member(['groupid' => $group1->id, 'userid' => $group12student->id]);
 290          $generator->create_group_member(['groupid' => $group2->id, 'userid' => $group12student->id]);
 291          $now = time();
 292  
 293          // Events with the same module name, instance and event type.
 294          $events = [
 295              [
 296                  'name' => 'Assignment 1 due date',
 297                  'description' => '',
 298                  'location' => 'Test',
 299                  'format' => 0,
 300                  'courseid' => $course->id,
 301                  'groupid' => 0,
 302                  'userid' => 2,
 303                  'modulename' => 'assign',
 304                  'instance' => $instance->id,
 305                  'eventtype' => 'due',
 306                  'timestart' => $now,
 307                  'timeduration' => 0,
 308                  'visible' => 1
 309              ], [
 310                  'name' => 'Assignment 1 due date - User override',
 311                  'description' => '',
 312                  'location' => 'Test',
 313                  'format' => 1,
 314                  'courseid' => 0,
 315                  'groupid' => 0,
 316                  'userid' => $useroverridestudent->id,
 317                  'modulename' => 'assign',
 318                  'instance' => $instance->id,
 319                  'eventtype' => 'due',
 320                  'timestart' => $now + 86400,
 321                  'timeduration' => 0,
 322                  'visible' => 1,
 323                  'priority' => CALENDAR_EVENT_USER_OVERRIDE_PRIORITY
 324              ], [
 325                  'name' => 'Assignment 1 due date - Group A override',
 326                  'description' => '',
 327                  'location' => 'Test',
 328                  'format' => 1,
 329                  'courseid' => $course->id,
 330                  'groupid' => $group1->id,
 331                  'userid' => 2,
 332                  'modulename' => 'assign',
 333                  'instance' => $instance->id,
 334                  'eventtype' => 'due',
 335                  'timestart' => $now + (2 * 86400),
 336                  'timeduration' => 0,
 337                  'visible' => 1,
 338                  'priority' => 1,
 339              ], [
 340                  'name' => 'Assignment 1 due date - Group B override',
 341                  'description' => '',
 342                  'location' => 'Test',
 343                  'format' => 1,
 344                  'courseid' => $course->id,
 345                  'groupid' => $group2->id,
 346                  'userid' => 2,
 347                  'modulename' => 'assign',
 348                  'instance' => $instance->id,
 349                  'eventtype' => 'due',
 350                  'timestart' => $now + (3 * 86400),
 351                  'timeduration' => 0,
 352                  'visible' => 1,
 353                  'priority' => 2,
 354              ],
 355          ];
 356  
 357          foreach ($events as $event) {
 358              \calendar_event::create($event, false);
 359          }
 360  
 361          $timestart = $now - 100;
 362          $timeend = $now + (3 * 86400);
 363          $groups = [$group1->id, $group2->id];
 364  
 365          // Get user override events.
 366          $this->setUser($useroverridestudent);
 367          $events = calendar_get_legacy_events($timestart, $timeend, $useroverridestudent->id, $groups, $course->id);
 368          $this->assertCount(1, $events);
 369          $event = reset($events);
 370          $this->assertEquals('Assignment 1 due date - User override', $event->name);
 371  
 372          // Get event for user with override but with the timestart and timeend parameters only covering the original event.
 373          $events = calendar_get_legacy_events($timestart, $now, $useroverridestudent->id, $groups, $course->id);
 374          $this->assertCount(0, $events);
 375  
 376          // Get events for user that does not belong to any group and has no user override events.
 377          $this->setUser($nogroupstudent);
 378          $events = calendar_get_legacy_events($timestart, $timeend, $nogroupstudent->id, $groups, $course->id);
 379          $this->assertCount(1, $events);
 380          $event = reset($events);
 381          $this->assertEquals('Assignment 1 due date', $event->name);
 382  
 383          // Get events for user that belongs to groups A and B and has no user override events.
 384          $this->setUser($group12student);
 385          $events = calendar_get_legacy_events($timestart, $timeend, $group12student->id, $groups, $course->id);
 386          $this->assertCount(1, $events);
 387          $event = reset($events);
 388          $this->assertEquals('Assignment 1 due date - Group A override', $event->name);
 389  
 390          // Get events for user that belongs to group A and has no user override events.
 391          $this->setUser($group1student);
 392          $events = calendar_get_legacy_events($timestart, $timeend, $group1student->id, $groups, $course->id);
 393          $this->assertCount(1, $events);
 394          $event = reset($events);
 395          $this->assertEquals('Assignment 1 due date - Group A override', $event->name);
 396  
 397          // Add repeating events.
 398          $repeatingevents = [
 399              [
 400                  'name' => 'Repeating site event',
 401                  'description' => '',
 402                  'location' => 'Test',
 403                  'format' => 1,
 404                  'courseid' => SITEID,
 405                  'groupid' => 0,
 406                  'userid' => 2,
 407                  'repeatid' => $event->id,
 408                  'modulename' => '0',
 409                  'instance' => 0,
 410                  'eventtype' => 'site',
 411                  'timestart' => $now + 86400,
 412                  'timeduration' => 0,
 413                  'visible' => 1,
 414              ],
 415              [
 416                  'name' => 'Repeating site event',
 417                  'description' => '',
 418                  'location' => 'Test',
 419                  'format' => 1,
 420                  'courseid' => SITEID,
 421                  'groupid' => 0,
 422                  'userid' => 2,
 423                  'repeatid' => $event->id,
 424                  'modulename' => '0',
 425                  'instance' => 0,
 426                  'eventtype' => 'site',
 427                  'timestart' => $now + (2 * 86400),
 428                  'timeduration' => 0,
 429                  'visible' => 1,
 430              ],
 431          ];
 432  
 433          foreach ($repeatingevents as $event) {
 434              \calendar_event::create($event, false);
 435          }
 436  
 437          // Make sure repeating events are not filtered out.
 438          $events = calendar_get_legacy_events($timestart, $timeend, true, true, true);
 439          $this->assertCount(3, $events);
 440      }
 441  
 442      public function test_calendar_get_default_courses() {
 443          global $USER, $CFG;
 444  
 445          $this->resetAfterTest(true);
 446  
 447          $generator = $this->getDataGenerator();
 448          $user = $generator->create_user();
 449          $course1 = $generator->create_course();
 450          $course2 = $generator->create_course();
 451          $course3 = $generator->create_course();
 452          $context = \context_course::instance($course1->id);
 453  
 454          $this->setAdminUser();
 455          $admin = clone $USER;
 456  
 457          $teacher = $generator->create_user();
 458          $generator->enrol_user($teacher->id, $course1->id, 'teacher');
 459          $generator->enrol_user($admin->id, $course1->id, 'teacher');
 460  
 461          $CFG->calendar_adminseesall = false;
 462  
 463          $courses = calendar_get_default_courses();
 464          // Only enrolled in one course.
 465          $this->assertCount(1, $courses);
 466          $courses = calendar_get_default_courses($course2->id);
 467          // Enrolled course + current course.
 468          $this->assertCount(2, $courses);
 469          $CFG->calendar_adminseesall = true;
 470          $courses = calendar_get_default_courses();
 471          // All courses + SITE.
 472          $this->assertCount(4, $courses);
 473          $courses = calendar_get_default_courses($course2->id);
 474          // All courses + SITE.
 475          $this->assertCount(4, $courses);
 476  
 477          $this->setUser($teacher);
 478  
 479          $CFG->calendar_adminseesall = false;
 480  
 481          $courses = calendar_get_default_courses();
 482          // Only enrolled in one course.
 483          $this->assertCount(1, $courses);
 484          $courses = calendar_get_default_courses($course2->id);
 485          // Enrolled course only (ignore current).
 486          $this->assertCount(1, $courses);
 487          // This setting should not affect teachers.
 488          $CFG->calendar_adminseesall = true;
 489          $courses = calendar_get_default_courses();
 490          // Only enrolled in one course.
 491          $this->assertCount(1, $courses);
 492          $courses = calendar_get_default_courses($course2->id);
 493          // Enrolled course only (ignore current).
 494          $this->assertCount(1, $courses);
 495  
 496          // Now, log out and test again.
 497          $this->setUser();
 498  
 499          $CFG->calendar_adminseesall = false;
 500  
 501          $courses = calendar_get_default_courses(null, '*', false, $teacher->id);
 502          // Only enrolled in one course.
 503          $this->assertCount(1, $courses);
 504          $courses = calendar_get_default_courses($course2->id, '*', false, $teacher->id);
 505          // Enrolled course only (ignore current).
 506          $this->assertCount(1, $courses);
 507          // This setting should not affect teachers.
 508          $CFG->calendar_adminseesall = true;
 509          $courses = calendar_get_default_courses(null, '*', false, $teacher->id);
 510          // Only enrolled in one course.
 511          $this->assertCount(1, $courses);
 512          $courses = calendar_get_default_courses($course2->id, '*', false, $teacher->id);
 513          // Enrolled course only (ignore current).
 514          $this->assertCount(1, $courses);
 515  
 516      }
 517  
 518      /**
 519       * Confirm that the skip events flag causes the calendar_get_view function
 520       * to avoid querying for the calendar events.
 521       */
 522      public function test_calendar_get_view_skip_events() {
 523          $this->resetAfterTest(true);
 524          $this->setAdminUser();
 525  
 526          $generator = $this->getDataGenerator();
 527          $user = $generator->create_user();
 528          $skipnavigation = true;
 529          $skipevents = true;
 530          $event = create_event([
 531              'eventtype' => 'user',
 532              'userid' => $user->id
 533          ]);
 534  
 535          $this->setUser($user);
 536          $calendar = \calendar_information::create(time() - 10, SITEID, null);
 537  
 538          list($data, $template) = calendar_get_view($calendar, 'day', $skipnavigation, $skipevents);
 539          $this->assertEmpty($data->events);
 540  
 541          $skipevents = false;
 542          list($data, $template) = calendar_get_view($calendar, 'day', $skipnavigation, $skipevents);
 543  
 544          $this->assertEquals($event->id, $data->events[0]->id);
 545      }
 546  
 547      public function test_calendar_get_allowed_event_types_course() {
 548          $generator = $this->getDataGenerator();
 549          $user = $generator->create_user();
 550          $course1 = $generator->create_course(); // Has capability.
 551          $course2 = $generator->create_course(); // Doesn't have capability.
 552          $course3 = $generator->create_course(); // Not enrolled.
 553          $context1 = \context_course::instance($course1->id);
 554          $context2 = \context_course::instance($course2->id);
 555          $context3 = \context_course::instance($course3->id);
 556          $roleid = $generator->create_role();
 557          $contexts = [$context1, $context2, $context3];
 558          $enrolledcourses = [$course1, $course2];
 559  
 560          foreach ($enrolledcourses as $course) {
 561              $generator->enrol_user($user->id, $course->id, 'student');
 562          }
 563  
 564          foreach ($contexts as $context) {
 565              $generator->role_assign($roleid, $user->id, $context->id);
 566          }
 567  
 568          $this->setUser($user);
 569  
 570          // In general for all courses, they don't have the ability to add course events yet.
 571          $types = calendar_get_allowed_event_types();
 572          $this->assertFalse($types['course']);
 573  
 574          assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context1, true);
 575          assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context2, true);
 576  
 577          // The user only has the correct capability in course 1 so that is the only
 578          // one that should be in the results.
 579          $types = calendar_get_allowed_event_types($course1->id);
 580          $this->assertTrue($types['course']);
 581  
 582          // If calling function without specified course,  there is still a course where they have it.
 583          $types = calendar_get_allowed_event_types();
 584          $this->assertTrue($types['course']);
 585  
 586          assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context1, true);
 587  
 588          // The user only now has the correct capability in both course 1 and 2 so we
 589          // expect both to be in the results.
 590          $types = calendar_get_allowed_event_types($course3->id);
 591          $this->assertFalse($types['course']);
 592  
 593          // They now do not have permission in any course.
 594          $types = calendar_get_allowed_event_types();
 595          $this->assertFalse($types['course']);
 596      }
 597  
 598      public function test_calendar_get_allowed_event_types_group_no_acces_to_diff_groups() {
 599          $generator = $this->getDataGenerator();
 600          $user = $generator->create_user();
 601          $course = $generator->create_course();
 602          $context = \context_course::instance($course->id);
 603          $roleid = $generator->create_role();
 604  
 605          $generator->enrol_user($user->id, $course->id, 'student');
 606          $generator->role_assign($roleid, $user->id, $context->id);
 607  
 608          $this->setUser($user);
 609  
 610          assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
 611          assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $roleid, $context, true);
 612  
 613          // The user has the correct capability in the course but they aren't a member
 614          // of any of the groups and don't have the accessallgroups capability.
 615          $types = calendar_get_allowed_event_types($course->id);
 616          $this->assertTrue($types['course']);
 617          $this->assertFalse($types['group']);
 618  
 619          // Same result applies when not providing a specific course as they are only on one course.
 620          $types = calendar_get_allowed_event_types();
 621          $this->assertTrue($types['course']);
 622          $this->assertFalse($types['group']);
 623      }
 624  
 625      public function test_calendar_get_allowed_event_types_group_no_groups() {
 626          $generator = $this->getDataGenerator();
 627          $user = $generator->create_user();
 628          $course = $generator->create_course();
 629          $context = \context_course::instance($course->id);
 630          $roleid = $generator->create_role();
 631          $generator->enrol_user($user->id, $course->id, 'student');
 632          $generator->role_assign($roleid, $user->id, $context->id);
 633          $this->setUser($user);
 634          assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
 635          // The user has the correct capability in the course but there are
 636          // no groups so we shouldn't see a group type.
 637          $types = calendar_get_allowed_event_types($course->id);
 638          $this->assertTrue($types['course']);
 639          $this->assertFalse($types['group']);
 640  
 641          // Same result applies when not providing a specific course as they are only on one course.
 642          $types = calendar_get_allowed_event_types();
 643          $this->assertTrue($types['course']);
 644          $this->assertFalse($types['group']);
 645      }
 646  
 647      public function test_calendar_get_allowed_event_types_group_access_all_groups() {
 648          $generator = $this->getDataGenerator();
 649          $user = $generator->create_user();
 650          $course1 = $generator->create_course();
 651          $course2 = $generator->create_course();
 652          $generator->create_group(array('courseid' => $course1->id));
 653          $generator->create_group(array('courseid' => $course2->id));
 654          $context1 = \context_course::instance($course1->id);
 655          $context2 = \context_course::instance($course2->id);
 656          $roleid = $generator->create_role();
 657          $generator->enrol_user($user->id, $course1->id, 'student');
 658          $generator->enrol_user($user->id, $course2->id, 'student');
 659          $generator->role_assign($roleid, $user->id, $context1->id);
 660          $generator->role_assign($roleid, $user->id, $context2->id);
 661          $this->setUser($user);
 662          assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context1, true);
 663          assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context2, true);
 664          assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context1, true);
 665          assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context2, true);
 666          // The user has the correct capability in the course and has
 667          // the accessallgroups capability.
 668          $types = calendar_get_allowed_event_types($course1->id);
 669          $this->assertTrue($types['group']);
 670  
 671          // Same result applies when not providing a specific course as they are only on one course.
 672          $types = calendar_get_allowed_event_types();
 673          $this->assertTrue($types['group']);
 674      }
 675  
 676      public function test_calendar_get_allowed_event_types_group_no_access_all_groups() {
 677          $generator = $this->getDataGenerator();
 678          $user = $generator->create_user();
 679          $course = $generator->create_course();
 680          $context = \context_course::instance($course->id);
 681          $group1 = $generator->create_group(array('courseid' => $course->id));
 682          $group2 = $generator->create_group(array('courseid' => $course->id));
 683          $roleid = $generator->create_role();
 684          $generator->enrol_user($user->id, $course->id, 'student');
 685          $generator->role_assign($roleid, $user->id, $context->id);
 686          $generator->create_group_member(array('groupid' => $group1->id, 'userid' => $user->id));
 687          $generator->create_group_member(array('groupid' => $group2->id, 'userid' => $user->id));
 688          $this->setUser($user);
 689          assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $roleid, $context, true);
 690          // The user has the correct capability in the course but can't access
 691          // groups that they are not a member of.
 692          $types = calendar_get_allowed_event_types($course->id);
 693          $this->assertFalse($types['group']);
 694  
 695          // Same result applies when not providing a specific course as they are only on one course.
 696          $types = calendar_get_allowed_event_types();
 697          $this->assertFalse($types['group']);
 698  
 699          assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
 700          assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context, true);
 701          $types = calendar_get_allowed_event_types($course->id);
 702          $this->assertTrue($types['group']);
 703  
 704          // Same result applies when not providing a specific course as they are only on one course.
 705          $types = calendar_get_allowed_event_types();
 706          $this->assertTrue($types['group']);
 707      }
 708  
 709      public function test_calendar_get_allowed_event_types_group_cap_no_groups() {
 710          $generator = $this->getDataGenerator();
 711          $user = $generator->create_user();
 712          $course = $generator->create_course();
 713          $context = \context_course::instance($course->id);
 714          $roleid = $generator->create_role();
 715          $group = $generator->create_group(['courseid' => $course->id]);
 716          $generator->enrol_user($user->id, $course->id, 'student');
 717          $generator->role_assign($roleid, $user->id, $context->id);
 718          assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true);
 719  
 720          $this->setUser($user);
 721          $types = calendar_get_allowed_event_types($course->id);
 722          $this->assertFalse($types['course']);
 723          $this->assertFalse($types['group']);
 724  
 725          // Check without specifying a course (same result as user only has one course).
 726          $types = calendar_get_allowed_event_types();
 727          $this->assertFalse($types['course']);
 728          $this->assertFalse($types['group']);
 729      }
 730  
 731      public function test_calendar_get_allowed_event_types_group_cap_has_group() {
 732          $generator = $this->getDataGenerator();
 733          $user = $generator->create_user();
 734          $course = $generator->create_course();
 735          $context = \context_course::instance($course->id);
 736          $roleid = $generator->create_role();
 737          $group = $generator->create_group(['courseid' => $course->id]);
 738          $generator->enrol_user($user->id, $course->id, 'student');
 739          $generator->role_assign($roleid, $user->id, $context->id);
 740          groups_add_member($group, $user);
 741          assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true);
 742  
 743          $this->setUser($user);
 744          $types = calendar_get_allowed_event_types($course->id);
 745          $this->assertFalse($types['course']);
 746          $this->assertTrue($types['group']);
 747  
 748          // Check without specifying a course (same result as user only has one course).
 749          $types = calendar_get_allowed_event_types();
 750          $this->assertFalse($types['course']);
 751          $this->assertTrue($types['group']);
 752      }
 753  
 754      public function test_calendar_get_allowed_event_types_group_cap_access_all_groups() {
 755          $generator = $this->getDataGenerator();
 756          $user = $generator->create_user();
 757          $course = $generator->create_course();
 758          $context = \context_course::instance($course->id);
 759          $roleid = $generator->create_role();
 760          $group = $generator->create_group(['courseid' => $course->id]);
 761          $generator->enrol_user($user->id, $course->id, 'student');
 762          $generator->role_assign($roleid, $user->id, $context->id);
 763          assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true);
 764          assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context, true);
 765  
 766          $this->setUser($user);
 767          $types = calendar_get_allowed_event_types($course->id);
 768          $this->assertFalse($types['course']);
 769          $this->assertTrue($types['group']);
 770  
 771          // Check without specifying a course (same result as user only has one course).
 772          $types = calendar_get_allowed_event_types();
 773          $this->assertFalse($types['course']);
 774          $this->assertTrue($types['group']);
 775      }
 776  
 777      /**
 778       * This is a setup helper function that create some users, courses, groups and group memberships.
 779       * This is useful to prepare the environment for testing the calendar_set_filters function.
 780       *
 781       * @return array An array of ($users, $courses, $coursegroups)
 782       */
 783      protected function setup_test_calendar_set_filters() {
 784          $generator = $this->getDataGenerator();
 785  
 786          // Create some users.
 787          $users = [];
 788          $users[] = $generator->create_user();
 789          $users[] = $generator->create_user();
 790          $users[] = $generator->create_user();
 791  
 792          // Create some courses.
 793          $courses = [];
 794          $courses[] = $generator->create_course();
 795          $courses[] = $generator->create_course();
 796          $courses[] = $generator->create_course();
 797          $courses[] = $generator->create_course();
 798  
 799          // Create some groups.
 800          $coursegroups = [];
 801          $coursegroups[$courses[0]->id] = [];
 802          $coursegroups[$courses[0]->id][] = $generator->create_group(['courseid' => $courses[0]->id]);
 803          $coursegroups[$courses[0]->id][] = $generator->create_group(['courseid' => $courses[0]->id]);
 804          $coursegroups[$courses[2]->id] = [];
 805          $coursegroups[$courses[2]->id][] = $generator->create_group(['courseid' => $courses[2]->id]);
 806          $coursegroups[$courses[2]->id][] = $generator->create_group(['courseid' => $courses[2]->id]);
 807          $coursegroups[$courses[3]->id] = [];
 808          $coursegroups[$courses[3]->id][] = $generator->create_group(['courseid' => $courses[3]->id]);
 809          $coursegroups[$courses[3]->id][] = $generator->create_group(['courseid' => $courses[3]->id]);
 810  
 811          // Create some enrolments and group memberships.
 812          $generator->enrol_user($users[0]->id, $courses[0]->id, 'student');
 813          $generator->create_group_member(['groupid' => $coursegroups[$courses[0]->id][0]->id, 'userid' => $users[0]->id]);
 814          $generator->enrol_user($users[1]->id, $courses[0]->id, 'student');
 815          $generator->create_group_member(['groupid' => $coursegroups[$courses[0]->id][1]->id, 'userid' => $users[1]->id]);
 816          $generator->enrol_user($users[0]->id, $courses[1]->id, 'student');
 817          $generator->enrol_user($users[0]->id, $courses[2]->id, 'student');
 818  
 819          return array($users, $courses, $coursegroups);
 820      }
 821  
 822      /**
 823       * This function tests calendar_set_filters for the case when user is not logged in.
 824       */
 825      public function test_calendar_set_filters_not_logged_in() {
 826          $this->resetAfterTest();
 827  
 828          list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters();
 829  
 830          $defaultcourses = calendar_get_default_courses(null, '*', false, $users[0]->id);
 831          list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses);
 832  
 833          $this->assertEqualsCanonicalizing(
 834                  [$courses[0]->id, $courses[1]->id, $courses[2]->id, SITEID],
 835                  array_values($courseids));
 836          $this->assertFalse($groupids);
 837          $this->assertFalse($userid);
 838      }
 839  
 840      /**
 841       * This function tests calendar_set_filters for the case when no one is logged in, but a user id is provided.
 842       */
 843      public function test_calendar_set_filters_not_logged_in_with_user() {
 844          $this->resetAfterTest();
 845  
 846          list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters();
 847  
 848          $defaultcourses = calendar_get_default_courses(null, '*', false, $users[1]->id);
 849          list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false, $users[1]);
 850  
 851          $this->assertEquals(array($courses[0]->id, SITEID), array_values($courseids));
 852          $this->assertEquals(array($coursegroups[$courses[0]->id][1]->id), $groupids);
 853          $this->assertEquals($users[1]->id, $userid);
 854  
 855          $defaultcourses = calendar_get_default_courses(null, '*', false, $users[0]->id);
 856          list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false, $users[0]);
 857  
 858          $this->assertEqualsCanonicalizing(
 859                  [$courses[0]->id, $courses[1]->id, $courses[2]->id, SITEID],
 860                  array_values($courseids));
 861          $this->assertEquals(array($coursegroups[$courses[0]->id][0]->id), $groupids);
 862          $this->assertEquals($users[0]->id, $userid);
 863  
 864      }
 865  
 866      /**
 867       * This function tests calendar_set_filters for the case when user is logged in, but no user id is provided.
 868       */
 869      public function test_calendar_set_filters_logged_in_no_user() {
 870          $this->resetAfterTest();
 871  
 872          list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters();
 873  
 874          $this->setUser($users[0]);
 875          $defaultcourses = calendar_get_default_courses(null, '*', false, $users[0]->id);
 876          list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false);
 877          $this->assertEqualsCanonicalizing([$courses[0]->id, $courses[1]->id, $courses[2]->id, SITEID], array_values($courseids));
 878          $this->assertEquals(array($coursegroups[$courses[0]->id][0]->id), $groupids);
 879          $this->assertEquals($users[0]->id, $userid);
 880      }
 881  
 882      /**
 883       * This function tests calendar_set_filters for the case when a user is logged in, but another user id is provided.
 884       */
 885      public function test_calendar_set_filters_logged_in_another_user() {
 886          $this->resetAfterTest();
 887  
 888          list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters();
 889  
 890          $this->setUser($users[0]);
 891          $defaultcourses = calendar_get_default_courses(null, '*', false, $users[1]->id);
 892          list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false, $users[1]);
 893  
 894          $this->assertEquals(array($courses[0]->id, SITEID), array_values($courseids));
 895          $this->assertEquals(array($coursegroups[$courses[0]->id][1]->id), $groupids);
 896          $this->assertEquals($users[1]->id, $userid);
 897      }
 898  
 899      /**
 900       *  Test for calendar_view_event_allowed for course event types.
 901       */
 902      public function test_calendar_view_event_allowed_course_event() {
 903          global $USER;
 904  
 905          $this->setAdminUser();
 906  
 907          $generator = $this->getDataGenerator();
 908  
 909          // A student in a course.
 910          $student = $generator->create_user();
 911          // Some user not enrolled in any course.
 912          $someuser = $generator->create_user();
 913  
 914          // A course with manual enrolments.
 915          $manualcourse = $generator->create_course();
 916  
 917          // Enrol the student to the manual enrolment course.
 918          $generator->enrol_user($student->id, $manualcourse->id);
 919  
 920          // A course that allows guest access.
 921          $guestcourse = $generator->create_course(
 922              (object)[
 923                  'shortname' => 'guestcourse',
 924                  'enrol_guest_status_0' => ENROL_INSTANCE_ENABLED,
 925                  'enrol_guest_password_0' => ''
 926              ]);
 927  
 928          $manualevent = (object)[
 929              'name' => 'Manual course event',
 930              'description' => '',
 931              'format' => 1,
 932              'categoryid' => 0,
 933              'courseid' => $manualcourse->id,
 934              'groupid' => 0,
 935              'userid' => $USER->id,
 936              'modulename' => 0,
 937              'instance' => 0,
 938              'eventtype' => 'course',
 939              'timestart' => time(),
 940              'timeduration' => 86400,
 941              'visible' => 1
 942          ];
 943          $caleventmanual = \calendar_event::create($manualevent, false);
 944  
 945          // Create a course event for the course with guest access.
 946          $guestevent = clone $manualevent;
 947          $guestevent->name = 'Guest course event';
 948          $guestevent->courseid = $guestcourse->id;
 949          $caleventguest = \calendar_event::create($guestevent, false);
 950  
 951          // Viewing as admin.
 952          $this->assertTrue(calendar_view_event_allowed($caleventmanual));
 953          $this->assertTrue(calendar_view_event_allowed($caleventguest));
 954  
 955          // Viewing as someone enrolled in a course.
 956          $this->setUser($student);
 957          $this->assertTrue(calendar_view_event_allowed($caleventmanual));
 958  
 959          // Viewing as someone not enrolled in any course.
 960          $this->setUser($someuser);
 961          // Viewing as someone not enrolled in a course without guest access on.
 962          $this->assertFalse(calendar_view_event_allowed($caleventmanual));
 963          // Viewing as someone not enrolled in a course with guest access on.
 964          $this->assertTrue(calendar_view_event_allowed($caleventguest));
 965      }
 966  
 967      /**
 968       *  Test for calendar_get_export_token for current user.
 969       */
 970      public function test_calendar_get_export_token_for_current_user() {
 971          global $USER, $DB, $CFG;
 972  
 973          $this->setAdminUser();
 974  
 975          // Get my token.
 976          $authtoken = calendar_get_export_token($USER);
 977          $expected = sha1($USER->id . $DB->get_field('user', 'password', ['id' => $USER->id]) . $CFG->calendar_exportsalt);
 978  
 979          $this->assertEquals($expected, $authtoken);
 980      }
 981  
 982      /**
 983       *  Test for calendar_get_export_token for another user.
 984       */
 985      public function test_calendar_get_export_token_for_another_user() {
 986          global $CFG;
 987  
 988          // Get any user token.
 989          $generator = $this->getDataGenerator();
 990          $user = $generator->create_user();
 991  
 992          // Get other user token.
 993          $authtoken = calendar_get_export_token($user);
 994          $expected = sha1($user->id . $user->password . $CFG->calendar_exportsalt);
 995  
 996          $this->assertEquals($expected, $authtoken);
 997      }
 998  
 999      /**
1000       *  Test calendar_can_manage_user_event for different users.
1001       *
1002       * @covers ::calendar_can_manage_user_event
1003       */
1004      public function test_calendar_can_manage_user_event() {
1005          global $DB, $USER;
1006          $generator = $this->getDataGenerator();
1007          $sitecontext = \context_system::instance();
1008          $this->resetAfterTest();
1009          $this->setAdminUser();
1010          $user1 = $generator->create_user();
1011          $user2 = $generator->create_user();
1012          $adminevent = create_event([
1013              'eventtype' => 'user',
1014              'userid' => $USER->id,
1015          ]);
1016  
1017          $this->setUser($user1);
1018          $user1event = create_event([
1019              'name' => 'user1 event',
1020              'eventtype' => 'user',
1021              'userid' => $user1->id,
1022          ]);
1023          $this->setUser($user2);
1024          $user2event = create_event([
1025              'name' => 'user2 event',
1026              'eventtype' => 'user',
1027              'userid' => $user2->id,
1028          ]);
1029          $this->setUser($user1);
1030          $result = calendar_can_manage_user_event($user1event);
1031          $this->assertEquals(true, $result);
1032          $result = calendar_can_manage_user_event($user2event);
1033          $this->assertEquals(false, $result);
1034  
1035          $sitemanager = $generator->create_user();
1036  
1037          $managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
1038          role_assign($managerroleid, $sitemanager->id, $sitecontext->id);
1039  
1040          $this->setUser($sitemanager);
1041  
1042          $result = calendar_can_manage_user_event($user1event);
1043          $this->assertEquals(true, $result);
1044          $result = calendar_can_manage_user_event($adminevent);
1045          $this->assertEquals(false, $result);
1046      }
1047  
1048      /**
1049       * Data provider for {@see test_calendar_format_event_location}
1050       *
1051       * @return array[]
1052       */
1053      public function calendar_format_event_location_provider(): array {
1054          return [
1055              'Empty' => ['', ''],
1056              'Text' => ['Barcelona', 'Barcelona'],
1057              'Link (http)' => ['http://example.com', '<a title=".*" href="http://example.com">http://example.com</a>'],
1058              'Link (https)' => ['https://example.com', '<a title=".*" href="https://example.com">https://example.com</a>'],
1059          ];
1060      }
1061  
1062      /**
1063       * Test formatting event location
1064       *
1065       * @param string $location
1066       * @param string $expectedpattern
1067       *
1068       * @covers ::calendar_format_event_location
1069       * @dataProvider calendar_format_event_location_provider
1070       */
1071      public function test_calendar_format_event_location(string $location, string $expectedpattern): void {
1072          $this->resetAfterTest();
1073          $this->setAdminUser();
1074  
1075          $event = create_event(['location' => $location]);
1076          $this->assertMatchesRegularExpression("|^({$expectedpattern})$|", calendar_format_event_location($event));
1077      }
1078  }