MDL-64063 core_calendar: Unit test for suspended users.
[moodle.git] / calendar / tests / externallib_test.php
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/>.
17 /**
18  * External calendar functions unit tests
19  *
20  * @package    core_calendar
21  * @category   external
22  * @copyright  2012 Ankit Agarwal
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
30 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
32 /**
33  * External course functions unit tests
34  *
35  * @package    core_calendar
36  * @category   external
37  * @copyright  2012 Ankit Agarwal
38  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  * @since Moodle 2.5
40  */
41 class core_calendar_externallib_testcase extends externallib_advanced_testcase {
43     /**
44      * Tests set up
45      */
46     protected function setUp() {
47         global $CFG;
48         require_once($CFG->dirroot . '/calendar/externallib.php');
49     }
51     /** Create calendar events or update them
52      * Set $prop->id, if you want to do an update instead of creating an new event
53      *
54      * @param string $name        Event title
55      * @param int    $userid      User id
56      * @param string $type        Event type
57      * @param int    $repeats     Number of repeated events to create
58      * @param int    $timestart   Time stamp of the event start
59      * @param mixed  $prop        List of event properties as array or object
60      * @return mixed              Event object or false;
61      * @since Moodle 2.5
62      */
64     public static function create_calendar_event($name, $userid = 0, $type = 'user', $repeats = 0, $timestart  = null, $prop = null) {
65         global $CFG, $DB, $SITE;
67         require_once("$CFG->dirroot/calendar/lib.php");
68         if (!empty($prop)) {
69             if (is_array($prop)) {
70                 $prop = (object)$prop;
71             }
72         } else {
73             $prop = new stdClass();
74         }
75         $prop->name = $name;
76         if (empty($prop->eventtype)) {
77             $prop->eventtype = $type;
78         }
79         if (empty($prop->repeats)) {
80             $prop->repeats = $repeats;
81         }
82         if (empty($prop->timestart)) {
83             $prop->timestart = time();
84         }
85         if (empty($prop->timeduration)) {
86             $prop->timeduration = 0;
87         }
88         if (empty($prop->timesort)) {
89             $prop->timesort = 0;
90         }
91         if (empty($prop->type)) {
92             $prop->type = CALENDAR_EVENT_TYPE_STANDARD;
93         }
94         if (empty($prop->repeats)) {
95             $prop->repeat = 0;
96         } else {
97             $prop->repeat = 1;
98         }
99         if (empty($prop->userid)) {
100             if (!empty($userid)) {
101                 $prop->userid = $userid;
102             } else {
103                 $prop->userid = 0;
104             }
105         }
106         if (!isset($prop->courseid)) {
107             $prop->courseid = $SITE->id;
108         }
110         // Determine event priority.
111         if ($prop->courseid == 0 && isset($prop->groupid) && $prop->groupid == 0 && !empty($prop->userid)) {
112             // User override event.
113             $prop->priority = CALENDAR_EVENT_USER_OVERRIDE_PRIORITY;
114         } else if ($prop->courseid != $SITE->id && !empty($prop->groupid)) {
115             // Group override event.
116             $priorityparams = ['courseid' => $prop->courseid, 'groupid' => $prop->groupid];
117             // Group override event with the highest priority.
118             $groupevents = $DB->get_records('event', $priorityparams, 'priority DESC', 'id, priority', 0, 1);
119             $priority = 1;
120             if (!empty($groupevents)) {
121                 $event = reset($groupevents);
122                 if (!empty($event->priority)) {
123                     $priority = $event->priority + 1;
124                 }
125             }
126             $prop->priority = $priority;
127         }
129         $event = new calendar_event($prop);
130         return $event->create($prop);
131     }
133     public function test_create_calendar_events () {
134         global $DB, $USER;
136         $this->setAdminUser();
137         $this->resetAfterTest();
138         $prevcount = count($DB->get_records("event"));
140         // Create a few events and do asserts.
141         $this->create_calendar_event('test', $USER->id);
142         $where = $DB->sql_compare_text('name') ." = ?";
143         $count = count($DB->get_records_select("event", $where, array('test')));
144         $this->assertEquals(1, $count);
145         $aftercount = count($DB->get_records("event"));
146         $this->assertEquals($prevcount + 1, $aftercount);
148         $this->create_calendar_event('user', $USER->id, 'user', 3);
149         $where = $DB->sql_compare_text('name') ." = ?";
150         $count = count($DB->get_records_select("event", $where, array('user')));
152         $this->assertEquals(3, $count);
153         $aftercount = count($DB->get_records("event"));
154         $this->assertEquals($prevcount + 4, $aftercount);
156     }
158     /**
159      * Test delete_calendar_events
160      *
161      * @expectedException moodle_exception
162      */
163     public function test_delete_calendar_events() {
164         global $DB, $USER;
166         $this->resetAfterTest(true);
167         $this->setAdminUser();
169         // Create a few stuff to test with.
170         $user = $this->getDataGenerator()->create_user();
171         $course = $this->getDataGenerator()->create_course();
172         $record = new stdClass();
173         $record->courseid = $course->id;
174         $group = $this->getDataGenerator()->create_group($record);
176         $notdeletedcount = $DB->count_records('event');
178         // Let's create a few events.
179         $siteevent = $this->create_calendar_event('site', $USER->id, 'site');
180         $record = new stdClass();
181         $record->courseid = $course->id;
182         $courseevent = $this->create_calendar_event('course', $USER->id, 'course', 2, time(), $record);
183         $userevent = $this->create_calendar_event('user', $USER->id);
184         $record = new stdClass();
185         $record->courseid = $course->id;
186         $record->groupid = $group->id;
187         $groupevent = $this->create_calendar_event('group', $USER->id, 'group', 0, time(), $record);
189         // Now lets try to delete stuff with proper rights.
190         $events = array(
191                 array('eventid' => $siteevent->id, 'repeat' => 0),
192                 array('eventid' => $courseevent->id, 'repeat' => 1),
193                 array('eventid' => $userevent->id, 'repeat' => 0),
194                 array('eventid' => $groupevent->id, 'repeat' => 0)
195                 );
196         core_calendar_external::delete_calendar_events($events);
198         // Check to see if things were deleted properly.
199         $deletedcount = $DB->count_records('event');
200         $this->assertEquals($notdeletedcount, $deletedcount);
202         // Let's create a few events.
203         $siteevent = $this->create_calendar_event('site', $USER->id, 'site');
204         $record = new stdClass();
205         $record->courseid = $course->id;
206         $courseevent = $this->create_calendar_event('course', $USER->id, 'course', 3, time(), $record);
207         $userevent = $this->create_calendar_event('user', $USER->id);
208         $record = new stdClass();
209         $record->courseid = $course->id;
210         $record->groupid = $group->id;
211         $groupevent = $this->create_calendar_event('group', $USER->id, 'group', 0, time(), $record);
213         $this->setuser($user);
214         $sitecontext = context_system::instance();
215         $coursecontext = context_course::instance($course->id);
216         $usercontext = context_user::instance($user->id);
217         $role = $DB->get_record('role', array('shortname' => 'student'));
218         $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
220         // Remove all caps.
221         $this->unassignUserCapability('moodle/calendar:manageentries', $sitecontext->id, $role->id);
222         $this->unassignUserCapability('moodle/calendar:manageentries', $coursecontext->id, $role->id);
223         $this->unassignUserCapability('moodle/calendar:managegroupentries', $coursecontext->id, $role->id);
224         $this->unassignUserCapability('moodle/calendar:manageownentries', $usercontext->id, $role->id);
226         // Assign proper caps and attempt delete.
227          $this->assignUserCapability('moodle/calendar:manageentries', $sitecontext->id, $role->id);
228          $events = array(
229                 array('eventid' => $siteevent->id, 'repeat' => 0),
230                 );
231         core_calendar_external::delete_calendar_events($events);
232         $deletedcount = $DB->count_records('event');
233         $count = $notdeletedcount+5;
234         $this->assertEquals($count, $deletedcount);
236          $this->assignUserCapability('moodle/calendar:manageentries', $sitecontext->id, $role->id);
237          $events = array(
238                 array('eventid' => $courseevent->id, 'repeat' => 0),
239                 );
240         core_calendar_external::delete_calendar_events($events);
241         $deletedcount = $DB->count_records('event');
242         $count = $notdeletedcount+4;
243         $this->assertEquals($count, $deletedcount);
245          $this->assignUserCapability('moodle/calendar:manageownentries', $usercontext->id, $role->id);
246          $events = array(
247                 array('eventid' => $userevent->id, 'repeat' => 0),
248                 );
249         core_calendar_external::delete_calendar_events($events);
250         $deletedcount = $DB->count_records('event');
251         $count = $notdeletedcount+3;
252         $this->assertEquals($count, $deletedcount);
254          $this->assignUserCapability('moodle/calendar:managegroupentries', $coursecontext->id, $role->id);
255          $events = array(
256                 array('eventid' => $groupevent->id, 'repeat' => 0),
257                 );
258         core_calendar_external::delete_calendar_events($events);
259         $deletedcount = $DB->count_records('event');
260         $count = $notdeletedcount+2;
261         $this->assertEquals($count, $deletedcount);
263         $notdeletedcount = $deletedcount;
265         // Let us try deleting without caps.
267         $siteevent = $this->create_calendar_event('site', $USER->id, 'site');
268         $record = new stdClass();
269         $record->courseid = $course->id;
270         $courseevent = $this->create_calendar_event('course', $USER->id, 'course', 3, time(), $record);
271         $userevent = $this->create_calendar_event('user', $USER->id);
272         $record = new stdClass();
273         $record->courseid = $course->id;
274         $record->groupid = $group->id;
275         $groupevent = $this->create_calendar_event('group', $USER->id, 'group', 0, time(), $record);
277         $this->setGuestUser();
279         $events = array(
280             array('eventid' => $siteevent->id, 'repeat' => 0),
281             array('eventid' => $courseevent->id, 'repeat' => 0),
282             array('eventid' => $userevent->id, 'repeat' => 0),
283             array('eventid' => $groupevent->id, 'repeat' => 0)
284         );
285         core_calendar_external::delete_calendar_events($events);
286     }
288     /**
289      * Test get_calendar_events
290      */
291     public function test_get_calendar_events() {
292         global $DB, $USER;
294         $this->resetAfterTest(true);
295         set_config('calendar_adminseesall', 1);
296         $this->setAdminUser();
298         // Create a few stuff to test with.
299         $user = $this->getDataGenerator()->create_user();
300         $user2 = $this->getDataGenerator()->create_user();
301         $course = $this->getDataGenerator()->create_course();
303         $category = $this->getDataGenerator()->create_category();
305         $category2 = $this->getDataGenerator()->create_category();
306         $category2b = $this->getDataGenerator()->create_category(['parent' => $category2->id]);
307         $course3 = $this->getDataGenerator()->create_course(['category' => $category2b->id]);
309         $role = $DB->get_record('role', array('shortname' => 'student'));
310         $this->getDataGenerator()->enrol_user($user2->id, $course3->id, $role->id);
312         $record = new stdClass();
313         $record->courseid = $course->id;
314         $group = $this->getDataGenerator()->create_group($record);
316         $beforecount = $DB->count_records('event');
318         // Let's create a few events.
319         $siteevent = $this->create_calendar_event('site', $USER->id, 'site');
321         // This event will have description with an inline fake image.
322         $draftidfile = file_get_unused_draft_itemid();
323         $usercontext = context_course::instance($course->id);
324         $filerecord = array(
325             'contextid' => $usercontext->id,
326             'component' => 'user',
327             'filearea'  => 'draft',
328             'itemid'    => $draftidfile,
329             'filepath'  => '/',
330             'filename'  => 'fakeimage.png',
331         );
332         $fs = get_file_storage();
333         $fs->create_file_from_string($filerecord, 'img contents');
335         $record = new stdClass();
336         $record->courseid = $course->id;
337         $record->groupid = 0;
338         $record->description = array(
339             'format' => FORMAT_HTML,
340             'text' => 'Text with img <img src="@@PLUGINFILE@@/fakeimage.png">',
341             'itemid' => $draftidfile
342         );
343         $courseevent = $this->create_calendar_event('course', $USER->id, 'course', 2, time(), $record);
345         $record = new stdClass();
346         $record->courseid = 0;
347         $record->groupid = 0;
348         $userevent = $this->create_calendar_event('user', $USER->id, 'user', 0, time(), $record);
350         $record = new stdClass();
351         $record->courseid = $course->id;
352         $record->groupid = $group->id;
353         $groupevent = $this->create_calendar_event('group', $USER->id, 'group', 0, time(), $record);
355         $paramevents = array ('eventids' => array($siteevent->id), 'courseids' => array($course->id),
356                 'groupids' => array($group->id), 'categoryids' => array($category->id));
358         $options = array ('siteevents' => true, 'userevents' => true);
359         $events = core_calendar_external::get_calendar_events($paramevents, $options);
360         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
362         // Check to see if we got all events.
363         $this->assertEquals(5, count($events['events']));
364         $this->assertEquals(0, count($events['warnings']));
365         $options = array ('siteevents' => true, 'userevents' => true, 'timeend' => time() + 7*WEEKSECS);
366         $events = core_calendar_external::get_calendar_events($paramevents, $options);
367         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
368         $this->assertEquals(5, count($events['events']));
369         $this->assertEquals(0, count($events['warnings']));
371         // Expect the same URL in the description of two different events (because they are repeated).
372         $coursecontext = context_course::instance($course->id);
373         $expectedurl = "webservice/pluginfile.php/$coursecontext->id/calendar/event_description/$courseevent->id/fakeimage.png";
374         $withdescription = 0;
375         foreach ($events['events'] as $event) {
376             if (!empty($event['description'])) {
377                 $withdescription++;
378                 $this->assertContains($expectedurl, $event['description']);
379             }
380         }
381         $this->assertEquals(2, $withdescription);
383         // Let's play around with caps.
385         // Create user event for the user $user.
386         $record = new stdClass();
387         $record->courseid = 0;
388         $record->groupid = 0;
389         $this->create_calendar_event('user', $user->id, 'user', 0, time(), $record);
391         $this->setUser($user);
392         $events = core_calendar_external::get_calendar_events($paramevents, $options);
393         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
394         $this->assertEquals(2, count($events['events'])); // site, user.
395         $this->assertEquals(2, count($events['warnings'])); // course, group.
397         $role = $DB->get_record('role', array('shortname' => 'student'));
398         $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
399         $events = core_calendar_external::get_calendar_events($paramevents, $options);
400         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
401         $this->assertEquals(4, count($events['events'])); // site, user, both course events.
402         $this->assertEquals(1, count($events['warnings'])); // group.
404         $options = array ('siteevents' => true, 'userevents' => true, 'timeend' => time() + HOURSECS);
405         $events = core_calendar_external::get_calendar_events($paramevents, $options);
406         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
407         $this->assertEquals(3, count($events['events'])); // site, user, one course event.
408         $this->assertEquals(1, count($events['warnings'])); // group.
410         groups_add_member($group, $user);
411         $events = core_calendar_external::get_calendar_events($paramevents, $options);
412         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
413         $this->assertEquals(4, count($events['events'])); // site, user, group, one course event.
414         $this->assertEquals(0, count($events['warnings']));
416         $paramevents = array ('courseids' => array($course->id), 'groupids' => array($group->id));
417         $events = core_calendar_external::get_calendar_events($paramevents, $options);
418         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
419         $this->assertEquals(4, count($events['events'])); // site, user, group, one course event.
420         $this->assertEquals(0, count($events['warnings']));
422         $paramevents = array ('groupids' => array($group->id, 23));
423         $events = core_calendar_external::get_calendar_events($paramevents, $options);
424         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
425         $this->assertEquals(3, count($events['events'])); // site, user, group.
426         $this->assertEquals(1, count($events['warnings']));
428         $paramevents = array ('courseids' => array(23));
429         $events = core_calendar_external::get_calendar_events($paramevents, $options);
430         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
431         $this->assertEquals(2, count($events['events'])); // site, user.
432         $this->assertEquals(1, count($events['warnings']));
434         $paramevents = array ();
435         $options = array ('siteevents' => false, 'userevents' => false, 'timeend' => time() + 7*WEEKSECS);
436         $events = core_calendar_external::get_calendar_events($paramevents, $options);
437         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
438         $this->assertEquals(0, count($events['events'])); // nothing returned.
439         $this->assertEquals(0, count($events['warnings']));
441         $paramevents = array ('eventids' => array($siteevent->id, $groupevent->id));
442         $options = array ('siteevents' => false, 'userevents' => false, 'timeend' => time() + 7*WEEKSECS);
443         $events = core_calendar_external::get_calendar_events($paramevents, $options);
444         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
445         $this->assertEquals(2, count($events['events'])); // site, group.
446         $this->assertEquals(0, count($events['warnings']));
448         $paramevents = array ('eventids' => array($siteevent->id));
449         $events = core_calendar_external::get_calendar_events($paramevents, $options);
450         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
451         $this->assertEquals(1, count($events['events'])); // site.
452         $this->assertEquals(0, count($events['warnings']));
454         // Try getting a course event by its id.
455         $paramevents = array ('eventids' => array($courseevent->id));
456         $events = core_calendar_external::get_calendar_events($paramevents, $options);
457         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
458         $this->assertEquals(1, count($events['events']));
459         $this->assertEquals(0, count($events['warnings']));
461         // Now, create an activity event.
462         $this->setAdminUser();
463         $nexttime = time() + DAYSECS;
464         $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id, 'duedate' => $nexttime));
466         $this->setUser($user);
467         $paramevents = array ('courseids' => array($course->id));
468         $options = array ('siteevents' => true, 'userevents' => true, 'timeend' => time() + WEEKSECS);
469         $events = core_calendar_external::get_calendar_events($paramevents, $options);
470         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
472         $this->assertCount(5, $events['events']);
474         // Hide the assignment.
475         set_coursemodule_visible($assign->cmid, 0);
476         // Empty all the caches that may be affected  by this change.
477         accesslib_clear_all_caches_for_unit_testing();
478         course_modinfo::clear_instance_cache();
480         $events = core_calendar_external::get_calendar_events($paramevents, $options);
481         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
482         // Expect one less.
483         $this->assertCount(4, $events['events']);
485         // Create some category events.
486         $this->setAdminUser();
487         $record = new stdClass();
488         $record->courseid = 0;
489         $record->categoryid = $category->id;
490         $record->timestart = time() - DAYSECS;
491         $catevent1 = $this->create_calendar_event('category a', $USER->id, 'category', 0, time(), $record);
493         $record = new stdClass();
494         $record->courseid = 0;
495         $record->categoryid = $category2->id;
496         $record->timestart = time() + DAYSECS;
497         $catevent2 = $this->create_calendar_event('category b', $USER->id, 'category', 0, time(), $record);
499         // Now as student, make sure we get the events of the courses I am enrolled.
500         $this->setUser($user2);
501         $paramevents = array('categoryids' => array($category2b->id));
502         $options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false);
503         $events = core_calendar_external::get_calendar_events($paramevents, $options);
504         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
506         // Should be just one, since there's just one category event of the course I am enrolled (course3 - cat2b).
507         $this->assertEquals(1, count($events['events']));
508         $this->assertEquals($catevent2->id, $events['events'][0]['id']);
509         $this->assertEquals($category2->id, $events['events'][0]['categoryid']);
510         $this->assertEquals(0, count($events['warnings']));
512         // Now get category events but by course (there aren't course events in the course).
513         $paramevents = array('courseids' => array($course3->id));
514         $options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false);
515         $events = core_calendar_external::get_calendar_events($paramevents, $options);
516         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
517         $this->assertEquals(1, count($events['events']));
518         $this->assertEquals($catevent2->id, $events['events'][0]['id']);
519         $this->assertEquals(0, count($events['warnings']));
521         // Empty events in one where I'm not enrolled and one parent category
522         // (parent of a category where this is a course where the user is enrolled).
523         $paramevents = array('categoryids' => array($category2->id, $category->id));
524         $options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false);
525         $events = core_calendar_external::get_calendar_events($paramevents, $options);
526         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
527         $this->assertEquals(1, count($events['events']));
528         $this->assertEquals($catevent2->id, $events['events'][0]['id']);
529         $this->assertEquals(0, count($events['warnings']));
531         // Admin can see all category events.
532         $this->setAdminUser();
533         $paramevents = array('categoryids' => array($category->id, $category2->id, $category2b->id));
534         $options = array('timeend' => time() + 7 * WEEKSECS, 'userevents' => false, 'siteevents' => false);
535         $events = core_calendar_external::get_calendar_events($paramevents, $options);
536         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
537         $this->assertEquals(2, count($events['events']));
538         $this->assertEquals(0, count($events['warnings']));
539         $this->assertEquals($catevent1->id, $events['events'][0]['id']);
540         $this->assertEquals($category->id, $events['events'][0]['categoryid']);
541         $this->assertEquals($catevent2->id, $events['events'][1]['id']);
542         $this->assertEquals($category2->id, $events['events'][1]['categoryid']);
543     }
545     /**
546      * Test core_calendar_external::create_calendar_events
547      */
548     public function test_core_create_calendar_events() {
549         global $DB, $USER, $SITE;
551         $this->resetAfterTest(true);
552         $this->setAdminUser();
554         // Create a few stuff to test with.
555         $user = $this->getDataGenerator()->create_user();
556         $course = $this->getDataGenerator()->create_course();
557         $record = new stdClass();
558         $record->courseid = $course->id;
559         $group = $this->getDataGenerator()->create_group($record);
561         $prevcount = $DB->count_records('event');
563         // Let's create a few events.
564         $events = array (
565                 array('name' => 'site', 'courseid' => $SITE->id, 'eventtype' => 'site'),
566                 array('name' => 'course', 'courseid' => $course->id, 'eventtype' => 'course', 'repeats' => 2),
567                 array('name' => 'group', 'courseid' => $course->id, 'groupid' => $group->id, 'eventtype' => 'group'),
568                 array('name' => 'user')
569                 );
570         $eventsret = core_calendar_external::create_calendar_events($events);
571         $eventsret = external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);
573         // Check to see if things were created properly.
574         $aftercount = $DB->count_records('event');
575         $this->assertEquals($prevcount + 5, $aftercount);
576         $this->assertEquals(5, count($eventsret['events']));
577         $this->assertEquals(0, count($eventsret['warnings']));
579         $sitecontext = context_system::instance();
580         $coursecontext = context_course::instance($course->id);
582         $this->setUser($user);
583         $prevcount = $aftercount;
584         $events = array (
585                 array('name' => 'course', 'courseid' => $course->id, 'eventtype' => 'course', 'repeats' => 2),
586                 array('name' => 'group', 'courseid' => $course->id, 'groupid' => $group->id, 'eventtype' => 'group'),
587                 array('name' => 'user')
588         );
589         $role = $DB->get_record('role', array('shortname' => 'student'));
590         $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
591         groups_add_member($group, $user);
592         $this->assignUserCapability('moodle/calendar:manageentries', $coursecontext->id, $role->id);
593         $this->assignUserCapability('moodle/calendar:managegroupentries', $coursecontext->id, $role->id);
594         $eventsret = core_calendar_external::create_calendar_events($events);
595         $eventsret = external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);
596         // Check to see if things were created properly.
597         $aftercount = $DB->count_records('event');
598         $this->assertEquals($prevcount + 4, $aftercount);
599         $this->assertEquals(4, count($eventsret['events']));
600         $this->assertEquals(0, count($eventsret['warnings']));
602         // Check to see nothing was created without proper permission.
603         $this->setGuestUser();
604         $prevcount = $DB->count_records('event');
605         $eventsret = core_calendar_external::create_calendar_events($events);
606         $eventsret = external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);
607         $aftercount = $DB->count_records('event');
608         $this->assertEquals($prevcount, $aftercount);
609         $this->assertEquals(0, count($eventsret['events']));
610         $this->assertEquals(3, count($eventsret['warnings']));
612         $this->setUser($user);
613         $this->unassignUserCapability('moodle/calendar:manageentries', $coursecontext->id, $role->id);
614         $this->unassignUserCapability('moodle/calendar:managegroupentries', $coursecontext->id, $role->id);
615         $prevcount = $DB->count_records('event');
616         $eventsret = core_calendar_external::create_calendar_events($events);
617         $eventsret = external_api::clean_returnvalue(core_calendar_external::create_calendar_events_returns(), $eventsret);
618         $aftercount = $DB->count_records('event');
619         $this->assertEquals($prevcount + 1, $aftercount); // User event.
620         $this->assertEquals(1, count($eventsret['events']));
621         $this->assertEquals(2, count($eventsret['warnings']));
622     }
624     /**
625      * Requesting calendar events from a given time should return all events with a sort
626      * time at or after the requested time. All events prior to that time should not
627      * be return.
628      *
629      * If there are no events on or after the given time then an empty result set should
630      * be returned.
631      */
632     public function test_get_calendar_action_events_by_timesort_after_time() {
633         $user = $this->getDataGenerator()->create_user();
634         $course = $this->getDataGenerator()->create_course();
635         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
636         $moduleinstance = $generator->create_instance(['course' => $course->id]);
638         $this->getDataGenerator()->enrol_user($user->id, $course->id);
639         $this->resetAfterTest(true);
640         $this->setUser($user);
642         $params = [
643             'type' => CALENDAR_EVENT_TYPE_ACTION,
644             'modulename' => 'assign',
645             'instance' => $moduleinstance->id,
646             'courseid' => $course->id,
647         ];
649         $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 1]));
650         $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2]));
651         $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3]));
652         $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4]));
653         $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5]));
654         $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6]));
655         $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7]));
656         $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8]));
658         $result = core_calendar_external::get_calendar_action_events_by_timesort(5);
659         $result = external_api::clean_returnvalue(
660             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
661             $result
662         );
663         $events = $result['events'];
665         $this->assertCount(4, $events);
666         $this->assertEquals('Event 5', $events[0]['name']);
667         $this->assertEquals('Event 6', $events[1]['name']);
668         $this->assertEquals('Event 7', $events[2]['name']);
669         $this->assertEquals('Event 8', $events[3]['name']);
670         $this->assertEquals($event5->id, $result['firstid']);
671         $this->assertEquals($event8->id, $result['lastid']);
673         $result = core_calendar_external::get_calendar_action_events_by_timesort(9);
674         $result = external_api::clean_returnvalue(
675             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
676             $result
677         );
679         $this->assertEmpty($result['events']);
680         $this->assertNull($result['firstid']);
681         $this->assertNull($result['lastid']);
682     }
684     /**
685      * Requesting calendar events before a given time should return all events with a sort
686      * time at or before the requested time (inclusive). All events after that time
687      * should not be returned.
688      *
689      * If there are no events before the given time then an empty result set should be
690      * returned.
691      */
692     public function test_get_calendar_action_events_by_timesort_before_time() {
693         $user = $this->getDataGenerator()->create_user();
694         $course = $this->getDataGenerator()->create_course();
695         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
696         $moduleinstance = $generator->create_instance(['course' => $course->id]);
698         $this->getDataGenerator()->enrol_user($user->id, $course->id);
699         $this->resetAfterTest(true);
700         $this->setUser($user);
702         $params = [
703             'type' => CALENDAR_EVENT_TYPE_ACTION,
704             'modulename' => 'assign',
705             'instance' => $moduleinstance->id,
706             'courseid' => $course->id,
707         ];
709         $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2]));
710         $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3]));
711         $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4]));
712         $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5]));
713         $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6]));
714         $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7]));
715         $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8]));
716         $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 9]));
718         $result = core_calendar_external::get_calendar_action_events_by_timesort(null, 5);
719         $result = external_api::clean_returnvalue(
720             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
721             $result
722         );
723         $events = $result['events'];
725         $this->assertCount(4, $events);
726         $this->assertEquals('Event 1', $events[0]['name']);
727         $this->assertEquals('Event 2', $events[1]['name']);
728         $this->assertEquals('Event 3', $events[2]['name']);
729         $this->assertEquals('Event 4', $events[3]['name']);
730         $this->assertEquals($event1->id, $result['firstid']);
731         $this->assertEquals($event4->id, $result['lastid']);
733         $result = core_calendar_external::get_calendar_action_events_by_timesort(null, 1);
734         $result = external_api::clean_returnvalue(
735             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
736             $result
737         );
739         $this->assertEmpty($result['events']);
740         $this->assertNull($result['firstid']);
741         $this->assertNull($result['lastid']);
742     }
744     /**
745      * Test retrieving event that was overridden for a user
746      */
747     public function test_get_calendar_events_override() {
748         $user = $this->getDataGenerator()->create_user();
749         $user2 = $this->getDataGenerator()->create_user();
750         $teacher = $this->getDataGenerator()->create_user();
751         $anotheruser = $this->getDataGenerator()->create_user();
752         $course = $this->getDataGenerator()->create_course();
753         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
754         $moduleinstance = $generator->create_instance(['course' => $course->id]);
756         $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
757         $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
758         $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
759         $this->resetAfterTest(true);
760         $this->setAdminUser();
762         $params = [
763             'type' => CALENDAR_EVENT_TYPE_ACTION,
764             'modulename' => 'assign',
765             'instance' => $moduleinstance->id,
766         ];
768         $now = time();
769         // Create two events - one for everybody in the course and one only for the first student.
770         $event1 = $this->create_calendar_event('Base event', 0, 'due', 0, $now + DAYSECS, $params + ['courseid' => $course->id]);
771         $event2 = $this->create_calendar_event('User event', $user->id, 'due', 0, $now + 2*DAYSECS, $params + ['courseid' => 0]);
773         // Retrieve course events for the second student - only one "Base event" is returned.
774         $this->setUser($user2);
775         $paramevents = array('courseids' => array($course->id));
776         $options = array ('siteevents' => true, 'userevents' => true);
777         $events = core_calendar_external::get_calendar_events($paramevents, $options);
778         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
779         $this->assertEquals(1, count($events['events']));
780         $this->assertEquals(0, count($events['warnings']));
781         $this->assertEquals('Base event', $events['events'][0]['name']);
783         // Retrieve events for the first student - both events are returned.
784         $this->setUser($user);
785         $events = core_calendar_external::get_calendar_events($paramevents, $options);
786         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
787         $this->assertEquals(2, count($events['events']));
788         $this->assertEquals(0, count($events['warnings']));
789         $this->assertEquals('Base event', $events['events'][0]['name']);
790         $this->assertEquals('User event', $events['events'][1]['name']);
792         // Retrieve events by id as a teacher, 'User event' should be returned since teacher has access to this course.
793         $this->setUser($teacher);
794         $paramevents = ['eventids' => [$event2->id]];
795         $events = core_calendar_external::get_calendar_events($paramevents, $options);
796         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
797         $this->assertEquals(1, count($events['events']));
798         $this->assertEquals(0, count($events['warnings']));
799         $this->assertEquals('User event', $events['events'][0]['name']);
801         // Retrieve events by id as another user, nothing should be returned.
802         $this->setUser($anotheruser);
803         $paramevents = ['eventids' => [$event2->id, $event1->id]];
804         $events = core_calendar_external::get_calendar_events($paramevents, $options);
805         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
806         $this->assertEquals(0, count($events['events']));
807         $this->assertEquals(0, count($events['warnings']));
808     }
810     /**
811      * Requesting calendar events within a given time range should return all events with
812      * a sort time between the lower and upper time bound (inclusive).
813      *
814      * If there are no events in the given time range then an empty result set should be
815      * returned.
816      */
817     public function test_get_calendar_action_events_by_timesort_time_range() {
818         $user = $this->getDataGenerator()->create_user();
819         $course = $this->getDataGenerator()->create_course();
820         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
821         $moduleinstance = $generator->create_instance(['course' => $course->id]);
823         $this->getDataGenerator()->enrol_user($user->id, $course->id);
824         $this->resetAfterTest(true);
825         $this->setUser($user);
827         $params = [
828             'type' => CALENDAR_EVENT_TYPE_ACTION,
829             'modulename' => 'assign',
830             'instance' => $moduleinstance->id,
831             'courseid' => $course->id,
832         ];
834         $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 1]));
835         $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2]));
836         $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3]));
837         $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4]));
838         $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5]));
839         $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6]));
840         $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7]));
841         $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8]));
843         $result = core_calendar_external::get_calendar_action_events_by_timesort(3, 6);
844         $result = external_api::clean_returnvalue(
845             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
846             $result
847         );
848         $events = $result['events'];
850         $this->assertCount(4, $events);
851         $this->assertEquals('Event 3', $events[0]['name']);
852         $this->assertEquals('Event 4', $events[1]['name']);
853         $this->assertEquals('Event 5', $events[2]['name']);
854         $this->assertEquals('Event 6', $events[3]['name']);
855         $this->assertEquals($event3->id, $result['firstid']);
856         $this->assertEquals($event6->id, $result['lastid']);
858         $result = core_calendar_external::get_calendar_action_events_by_timesort(10, 15);
859         $result = external_api::clean_returnvalue(
860             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
861             $result
862         );
864         $this->assertEmpty($result['events']);
865         $this->assertNull($result['firstid']);
866         $this->assertNull($result['lastid']);
867     }
869     /**
870      * Requesting calendar events within a given time range and a limit and offset should return
871      * the number of events up to the given limit value that have a sort time between the lower
872      * and uppper time bound (inclusive) where the result set is shifted by the offset value.
873      *
874      * If there are no events in the given time range then an empty result set should be
875      * returned.
876      */
877     public function test_get_calendar_action_events_by_timesort_time_limit_offset() {
878         $user = $this->getDataGenerator()->create_user();
879         $course = $this->getDataGenerator()->create_course();
880         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
881         $moduleinstance = $generator->create_instance(['course' => $course->id]);
883         $this->getDataGenerator()->enrol_user($user->id, $course->id);
884         $this->resetAfterTest(true);
885         $this->setUser($user);
887         $params = [
888             'type' => CALENDAR_EVENT_TYPE_ACTION,
889             'modulename' => 'assign',
890             'instance' => $moduleinstance->id,
891             'courseid' => $course->id,
892         ];
894         $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 1]));
895         $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2]));
896         $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3]));
897         $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4]));
898         $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5]));
899         $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6]));
900         $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7]));
901         $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8]));
903         $result = core_calendar_external::get_calendar_action_events_by_timesort(2, 7, $event3->id, 2);
904         $result = external_api::clean_returnvalue(
905             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
906             $result
907         );
908         $events = $result['events'];
910         $this->assertCount(2, $events);
911         $this->assertEquals('Event 4', $events[0]['name']);
912         $this->assertEquals('Event 5', $events[1]['name']);
913         $this->assertEquals($event4->id, $result['firstid']);
914         $this->assertEquals($event5->id, $result['lastid']);
916         $result = core_calendar_external::get_calendar_action_events_by_timesort(2, 7, $event5->id, 2);
917         $result = external_api::clean_returnvalue(
918             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
919             $result
920         );
921         $events = $result['events'];
923         $this->assertCount(2, $events);
924         $this->assertEquals('Event 6', $events[0]['name']);
925         $this->assertEquals('Event 7', $events[1]['name']);
926         $this->assertEquals($event6->id, $result['firstid']);
927         $this->assertEquals($event7->id, $result['lastid']);
929         $result = core_calendar_external::get_calendar_action_events_by_timesort(2, 7, $event7->id, 2);
930         $result = external_api::clean_returnvalue(
931             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
932             $result
933         );
935         $this->assertEmpty($result['events']);
936         $this->assertNull($result['firstid']);
937         $this->assertNull($result['lastid']);
938     }
940     /**
941      * Check that it is possible to restrict the calendar events to events where the user is not suspended in the course.
942      */
943     public function test_get_calendar_action_events_by_timesort_suspended_course() {
944         $this->resetAfterTest();
945         $user1 = $this->getDataGenerator()->create_user();
946         $user2 = $this->getDataGenerator()->create_user();
947         $course = $this->getDataGenerator()->create_course();
948         $this->setAdminUser();
949         $lesson = $this->getDataGenerator()->create_module('lesson', [
950                 'name' => 'Lesson 1',
951                 'course' => $course->id,
952                 'available' => time(),
953                 'deadline' => (time() + (60 * 60 * 24 * 5))
954             ]
955         );
956         $this->getDataGenerator()->enrol_user($user1->id, $course->id, null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
957         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
959         $this->setUser($user1);
960         $result = core_calendar_external::get_calendar_action_events_by_timesort(0, null, 0, 20, true);
961         $this->assertEmpty($result->events);
962         $this->setUser($user2);
963         $result = core_calendar_external::get_calendar_action_events_by_timesort(0, null, 0, 20, true);
964         $this->assertCount(1, $result->events);
965         $this->assertEquals('Lesson 1 closes', $result->events[0]->name);
966     }
968     /**
969      * Requesting calendar events from a given course and time should return all
970      * events with a sort time at or after the requested time. All events prior
971      * to that time should not be return.
972      *
973      * If there are no events on or after the given time then an empty result set should
974      * be returned.
975      */
976     public function test_get_calendar_action_events_by_course_after_time() {
977         $user = $this->getDataGenerator()->create_user();
978         $course1 = $this->getDataGenerator()->create_course();
979         $course2 = $this->getDataGenerator()->create_course();
980         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
981         $instance1 = $generator->create_instance(['course' => $course1->id]);
982         $instance2 = $generator->create_instance(['course' => $course2->id]);
983         $records = [];
985         $this->getDataGenerator()->enrol_user($user->id, $course1->id);
986         $this->getDataGenerator()->enrol_user($user->id, $course2->id);
987         $this->resetAfterTest(true);
988         $this->setUser($user);
990         for ($i = 1; $i < 19; $i++) {
991             $courseid = ($i < 9) ? $course1->id : $course2->id;
992             $instance = ($i < 9) ? $instance1->id : $instance2->id;
993             $records[] = $this->create_calendar_event(
994                 sprintf('Event %d', $i),
995                 $user->id,
996                 'user',
997                 0,
998                 1,
999                 [
1000                     'type' => CALENDAR_EVENT_TYPE_ACTION,
1001                     'courseid' => $courseid,
1002                     'timesort' => $i,
1003                     'modulename' => 'assign',
1004                     'instance' => $instance,
1005                 ]
1006             );
1007         }
1009         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 5);
1010         $result = external_api::clean_returnvalue(
1011             core_calendar_external::get_calendar_action_events_by_course_returns(),
1012             $result
1013         );
1014         $result = $result['events'];
1016         $this->assertCount(4, $result);
1017         $this->assertEquals('Event 5', $result[0]['name']);
1018         $this->assertEquals('Event 6', $result[1]['name']);
1019         $this->assertEquals('Event 7', $result[2]['name']);
1020         $this->assertEquals('Event 8', $result[3]['name']);
1022         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 9);
1023         $result = external_api::clean_returnvalue(
1024             core_calendar_external::get_calendar_action_events_by_course_returns(),
1025             $result
1026         );
1027         $result = $result['events'];
1029         $this->assertEmpty($result);
1030     }
1032     /**
1033      * Requesting calendar events for a course and before a given time should return
1034      * all events with a sort time at or before the requested time (inclusive). All
1035      * events after that time should not be returned.
1036      *
1037      * If there are no events before the given time then an empty result set should be
1038      * returned.
1039      */
1040     public function test_get_calendar_action_events_by_course_before_time() {
1041         $user = $this->getDataGenerator()->create_user();
1042         $course1 = $this->getDataGenerator()->create_course();
1043         $course2 = $this->getDataGenerator()->create_course();
1044         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1045         $instance1 = $generator->create_instance(['course' => $course1->id]);
1046         $instance2 = $generator->create_instance(['course' => $course2->id]);
1047         $records = [];
1049         $this->getDataGenerator()->enrol_user($user->id, $course1->id);
1050         $this->getDataGenerator()->enrol_user($user->id, $course2->id);
1051         $this->resetAfterTest(true);
1052         $this->setUser($user);
1054         for ($i = 1; $i < 19; $i++) {
1055             $courseid = ($i < 9) ? $course1->id : $course2->id;
1056             $instance = ($i < 9) ? $instance1->id : $instance2->id;
1057             $records[] = $this->create_calendar_event(
1058                 sprintf('Event %d', $i),
1059                 $user->id,
1060                 'user',
1061                 0,
1062                 1,
1063                 [
1064                     'type' => CALENDAR_EVENT_TYPE_ACTION,
1065                     'courseid' => $courseid,
1066                     'timesort' => $i + 1,
1067                     'modulename' => 'assign',
1068                     'instance' => $instance,
1069                 ]
1070             );
1071         }
1073         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, null, 5);
1074         $result = external_api::clean_returnvalue(
1075             core_calendar_external::get_calendar_action_events_by_course_returns(),
1076             $result
1077         );
1078         $result = $result['events'];
1080         $this->assertCount(4, $result);
1081         $this->assertEquals('Event 1', $result[0]['name']);
1082         $this->assertEquals('Event 2', $result[1]['name']);
1083         $this->assertEquals('Event 3', $result[2]['name']);
1084         $this->assertEquals('Event 4', $result[3]['name']);
1086         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, null, 1);
1087         $result = external_api::clean_returnvalue(
1088             core_calendar_external::get_calendar_action_events_by_course_returns(),
1089             $result
1090         );
1091         $result = $result['events'];
1093         $this->assertEmpty($result);
1094     }
1096     /**
1097      * Requesting calendar events for a course and within a given time range should
1098      * return all events with a sort time between the lower and upper time bound
1099      * (inclusive).
1100      *
1101      * If there are no events in the given time range then an empty result set should be
1102      * returned.
1103      */
1104     public function test_get_calendar_action_events_by_course_time_range() {
1105         $user = $this->getDataGenerator()->create_user();
1106         $course1 = $this->getDataGenerator()->create_course();
1107         $course2 = $this->getDataGenerator()->create_course();
1108         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1109         $instance1 = $generator->create_instance(['course' => $course1->id]);
1110         $instance2 = $generator->create_instance(['course' => $course2->id]);
1111         $records = [];
1113         $this->getDataGenerator()->enrol_user($user->id, $course1->id);
1114         $this->getDataGenerator()->enrol_user($user->id, $course2->id);
1115         $this->resetAfterTest(true);
1116         $this->setUser($user);
1118         for ($i = 1; $i < 19; $i++) {
1119             $courseid = ($i < 9) ? $course1->id : $course2->id;
1120             $instance = ($i < 9) ? $instance1->id : $instance2->id;
1121             $records[] = $this->create_calendar_event(
1122                 sprintf('Event %d', $i),
1123                 $user->id,
1124                 'user',
1125                 0,
1126                 1,
1127                 [
1128                     'type' => CALENDAR_EVENT_TYPE_ACTION,
1129                     'courseid' => $courseid,
1130                     'timesort' => $i,
1131                     'modulename' => 'assign',
1132                     'instance' => $instance,
1133                 ]
1134             );
1135         }
1137         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 3, 6);
1138         $result = external_api::clean_returnvalue(
1139             core_calendar_external::get_calendar_action_events_by_course_returns(),
1140             $result
1141         );
1142         $result = $result['events'];
1144         $this->assertCount(4, $result);
1145         $this->assertEquals('Event 3', $result[0]['name']);
1146         $this->assertEquals('Event 4', $result[1]['name']);
1147         $this->assertEquals('Event 5', $result[2]['name']);
1148         $this->assertEquals('Event 6', $result[3]['name']);
1150         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 10, 15);
1151         $result = external_api::clean_returnvalue(
1152             core_calendar_external::get_calendar_action_events_by_course_returns(),
1153             $result
1154         );
1155         $result = $result['events'];
1157         $this->assertEmpty($result);
1158     }
1160     /**
1161      * Requesting calendar events for a course and within a given time range and a limit
1162      * and offset should return the number of events up to the given limit value that have
1163      * a sort time between the lower and uppper time bound (inclusive) where the result
1164      * set is shifted by the offset value.
1165      *
1166      * If there are no events in the given time range then an empty result set should be
1167      * returned.
1168      */
1169     public function test_get_calendar_action_events_by_course_time_limit_offset() {
1170         $user = $this->getDataGenerator()->create_user();
1171         $course1 = $this->getDataGenerator()->create_course();
1172         $course2 = $this->getDataGenerator()->create_course();
1173         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1174         $instance1 = $generator->create_instance(['course' => $course1->id]);
1175         $instance2 = $generator->create_instance(['course' => $course2->id]);
1176         $records = [];
1178         $this->getDataGenerator()->enrol_user($user->id, $course1->id);
1179         $this->getDataGenerator()->enrol_user($user->id, $course2->id);
1180         $this->resetAfterTest(true);
1181         $this->setUser($user);
1183         for ($i = 1; $i < 19; $i++) {
1184             $courseid = ($i < 9) ? $course1->id : $course2->id;
1185             $instance = ($i < 9) ? $instance1->id : $instance2->id;
1186             $records[] = $this->create_calendar_event(
1187                 sprintf('Event %d', $i),
1188                 $user->id,
1189                 'user',
1190                 0,
1191                 1,
1192                 [
1193                     'type' => CALENDAR_EVENT_TYPE_ACTION,
1194                     'courseid' => $courseid,
1195                     'timesort' => $i,
1196                     'modulename' => 'assign',
1197                     'instance' => $instance,
1198                 ]
1199             );
1200         }
1202         $result = core_calendar_external::get_calendar_action_events_by_course(
1203             $course1->id, 2, 7, $records[2]->id, 2);
1204         $result = external_api::clean_returnvalue(
1205             core_calendar_external::get_calendar_action_events_by_course_returns(),
1206             $result
1207         );
1208         $result = $result['events'];
1210         $this->assertCount(2, $result);
1211         $this->assertEquals('Event 4', $result[0]['name']);
1212         $this->assertEquals('Event 5', $result[1]['name']);
1214         $result = core_calendar_external::get_calendar_action_events_by_course(
1215             $course1->id, 2, 7, $records[4]->id, 2);
1216         $result = external_api::clean_returnvalue(
1217             core_calendar_external::get_calendar_action_events_by_course_returns(),
1218             $result
1219         );
1220         $result = $result['events'];
1222         $this->assertCount(2, $result);
1223         $this->assertEquals('Event 6', $result[0]['name']);
1224         $this->assertEquals('Event 7', $result[1]['name']);
1226         $result = core_calendar_external::get_calendar_action_events_by_course(
1227             $course1->id, 2, 7, $records[6]->id, 2);
1228         $result = external_api::clean_returnvalue(
1229             core_calendar_external::get_calendar_action_events_by_course_returns(),
1230             $result
1231         );
1232         $result = $result['events'];
1234         $this->assertEmpty($result);
1235     }
1237     /**
1238      * Test that get_action_events_by_courses will return a list of events for each
1239      * course you provided as long as the user is enrolled in the course.
1240      */
1241     public function test_get_action_events_by_courses() {
1242         $user = $this->getDataGenerator()->create_user();
1243         $course1 = $this->getDataGenerator()->create_course();
1244         $course2 = $this->getDataGenerator()->create_course();
1245         $course3 = $this->getDataGenerator()->create_course();
1246         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1247         $instance1 = $generator->create_instance(['course' => $course1->id]);
1248         $instance2 = $generator->create_instance(['course' => $course2->id]);
1249         $instance3 = $generator->create_instance(['course' => $course3->id]);
1250         $records = [];
1251         $mapresult = function($result) {
1252             $groupedbycourse = [];
1253             foreach ($result['groupedbycourse'] as $group) {
1254                 $events = $group['events'];
1255                 $courseid = $group['courseid'];
1256                 $groupedbycourse[$courseid] = $events;
1257             }
1259             return $groupedbycourse;
1260         };
1262         $this->getDataGenerator()->enrol_user($user->id, $course1->id);
1263         $this->getDataGenerator()->enrol_user($user->id, $course2->id);
1264         $this->resetAfterTest(true);
1265         $this->setUser($user);
1267         for ($i = 1; $i < 10; $i++) {
1268             if ($i < 3) {
1269                 $courseid = $course1->id;
1270                 $instance = $instance1->id;
1271             } else if ($i < 6) {
1272                 $courseid = $course2->id;
1273                 $instance = $instance2->id;
1274             } else {
1275                 $courseid = $course3->id;
1276                 $instance = $instance3->id;
1277             }
1279             $records[] = $this->create_calendar_event(
1280                 sprintf('Event %d', $i),
1281                 $user->id,
1282                 'user',
1283                 0,
1284                 1,
1285                 [
1286                     'type' => CALENDAR_EVENT_TYPE_ACTION,
1287                     'courseid' => $courseid,
1288                     'timesort' => $i,
1289                     'modulename' => 'assign',
1290                     'instance' => $instance,
1291                 ]
1292             );
1293         }
1295         $result = core_calendar_external::get_calendar_action_events_by_courses([], 1);
1296         $result = external_api::clean_returnvalue(
1297             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1298             $result
1299         );
1300         $result = $result['groupedbycourse'];
1302         $this->assertEmpty($result);
1304         $result = core_calendar_external::get_calendar_action_events_by_courses([$course1->id], 3);
1305         $result = external_api::clean_returnvalue(
1306             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1307             $result
1308         );
1310         $groupedbycourse = $mapresult($result);
1312         $this->assertEmpty($groupedbycourse[$course1->id]);
1314         $result = core_calendar_external::get_calendar_action_events_by_courses([$course1->id], 1);
1315         $result = external_api::clean_returnvalue(
1316             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1317             $result
1318         );
1319         $groupedbycourse = $mapresult($result);
1321         $this->assertCount(2, $groupedbycourse[$course1->id]);
1322         $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']);
1323         $this->assertEquals('Event 2', $groupedbycourse[$course1->id][1]['name']);
1325         $result = core_calendar_external::get_calendar_action_events_by_courses(
1326             [$course1->id, $course2->id], 1);
1327         $result = external_api::clean_returnvalue(
1328             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1329             $result
1330         );
1331         $groupedbycourse = $mapresult($result);
1333         $this->assertCount(2, $groupedbycourse[$course1->id]);
1334         $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']);
1335         $this->assertEquals('Event 2', $groupedbycourse[$course1->id][1]['name']);
1336         $this->assertCount(3, $groupedbycourse[$course2->id]);
1337         $this->assertEquals('Event 3', $groupedbycourse[$course2->id][0]['name']);
1338         $this->assertEquals('Event 4', $groupedbycourse[$course2->id][1]['name']);
1339         $this->assertEquals('Event 5', $groupedbycourse[$course2->id][2]['name']);
1341         $result = core_calendar_external::get_calendar_action_events_by_courses(
1342             [$course1->id, $course2->id], 2, 4);
1343         $result = external_api::clean_returnvalue(
1344             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1345             $result
1346         );
1347         $groupedbycourse = $mapresult($result);
1349         $this->assertCount(2, $groupedbycourse);
1350         $this->assertCount(1, $groupedbycourse[$course1->id]);
1351         $this->assertEquals('Event 2', $groupedbycourse[$course1->id][0]['name']);
1352         $this->assertCount(2, $groupedbycourse[$course2->id]);
1353         $this->assertEquals('Event 3', $groupedbycourse[$course2->id][0]['name']);
1354         $this->assertEquals('Event 4', $groupedbycourse[$course2->id][1]['name']);
1356         $result = core_calendar_external::get_calendar_action_events_by_courses(
1357             [$course1->id, $course2->id], 1, null, 1);
1358         $result = external_api::clean_returnvalue(
1359             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1360             $result
1361         );
1362         $groupedbycourse = $mapresult($result);
1364         $this->assertCount(2, $groupedbycourse);
1365         $this->assertCount(1, $groupedbycourse[$course1->id]);
1366         $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']);
1367         $this->assertCount(1, $groupedbycourse[$course2->id]);
1368         $this->assertEquals('Event 3', $groupedbycourse[$course2->id][0]['name']);
1369     }
1371     /**
1372      * Test for deleting module events.
1373      */
1374     public function test_delete_calendar_events_for_modules() {
1375         $this->resetAfterTest();
1376         $this->setAdminUser();
1377         $course = $this->getDataGenerator()->create_course();
1378         $nexttime = time() + DAYSECS;
1379         $this->getDataGenerator()->create_module('assign', ['course' => $course->id, 'duedate' => $nexttime]);
1380         $events = calendar_get_events(time(), $nexttime, true, true, true);
1381         $this->assertCount(1, $events);
1382         $params = [];
1383         foreach ($events as $event) {
1384             $params[] = [
1385                 'eventid' => $event->id,
1386                 'repeat' => false
1387             ];
1388         }
1390         $this->expectException('moodle_exception');
1391         core_calendar_external::delete_calendar_events($params);
1392     }
1394     /**
1395      * Updating the event start day should change the date value but leave
1396      * the time of day unchanged.
1397      */
1398     public function test_update_event_start_day() {
1399         $generator = $this->getDataGenerator();
1400         $user = $generator->create_user();
1401         $roleid = $generator->create_role();
1402         $context = \context_system::instance();
1403         $originalstarttime = new DateTimeImmutable('2017-01-1T15:00:00+08:00');
1404         $newstartdate = new DateTimeImmutable('2018-02-2T10:00:00+08:00');
1405         $expected = new DateTimeImmutable('2018-02-2T15:00:00+08:00');
1407         $generator->role_assign($roleid, $user->id, $context->id);
1408         assign_capability('moodle/calendar:manageownentries', CAP_ALLOW, $roleid, $context, true);
1410         $this->setUser($user);
1411         $this->resetAfterTest(true);
1413         $event = $this->create_calendar_event(
1414             'Test event',
1415             $user->id,
1416             'user',
1417             0,
1418             null,
1419             [
1420                 'courseid' => 0,
1421                 'timestart' => $originalstarttime->getTimestamp()
1422             ]
1423         );
1425         $result = core_calendar_external::update_event_start_day($event->id, $newstartdate->getTimestamp());
1426         $result = external_api::clean_returnvalue(
1427             core_calendar_external::update_event_start_day_returns(),
1428             $result
1429         );
1431         $this->assertEquals($expected->getTimestamp(), $result['event']['timestart']);
1432     }
1434     /**
1435      * A user should not be able to edit an event that they don't have
1436      * capabilities for.
1437      */
1438     public function test_update_event_start_day_no_permission() {
1439         $generator = $this->getDataGenerator();
1440         $user = $generator->create_user();
1441         $roleid = $generator->create_role();
1442         $context = \context_system::instance();
1443         $originalstarttime = new DateTimeImmutable('2017-01-1T15:00:00+08:00');
1444         $newstartdate = new DateTimeImmutable('2018-02-2T10:00:00+08:00');
1445         $expected = new DateTimeImmutable('2018-02-2T15:00:00+08:00');
1447         $generator->role_assign($roleid, $user->id, $context->id);
1448         assign_capability('moodle/calendar:manageownentries', CAP_ALLOW, $roleid, $context, true);
1450         $this->setUser($user);
1451         $this->resetAfterTest(true);
1453         $event = $this->create_calendar_event(
1454             'Test event',
1455             $user->id,
1456             'user',
1457             0,
1458             null,
1459             [
1460                 'courseid' => 0,
1461                 'timestart' => $originalstarttime->getTimestamp()
1462             ]
1463         );
1465         assign_capability('moodle/calendar:manageownentries', CAP_PROHIBIT, $roleid, $context, true);
1466         $this->expectException('moodle_exception');
1467         $result = core_calendar_external::update_event_start_day($event->id, $newstartdate->getTimestamp());
1468         $result = external_api::clean_returnvalue(
1469             core_calendar_external::update_event_start_day_returns(),
1470             $result
1471         );
1472     }
1474     /**
1475      * A user should not be able to update a module event.
1476      */
1477     public function test_update_event_start_day_module_event() {
1478         $generator = $this->getDataGenerator();
1479         $user = $generator->create_user();
1480         $course = $generator->create_course();
1481         $plugingenerator = $generator->get_plugin_generator('mod_assign');
1482         $moduleinstance = $plugingenerator->create_instance(['course' => $course->id]);
1483         $roleid = $generator->create_role();
1484         $context = \context_course::instance($course->id);
1485         $originalstarttime = new DateTimeImmutable('2017-01-1T15:00:00+08:00');
1486         $newstartdate = new DateTimeImmutable('2018-02-2T10:00:00+08:00');
1487         $expected = new DateTimeImmutable('2018-02-2T15:00:00+08:00');
1489         $generator->role_assign($roleid, $user->id, $context->id);
1490         $generator->enrol_user($user->id, $course->id);
1492         $this->setUser($user);
1493         $this->resetAfterTest(true);
1495         $event = $this->create_calendar_event(
1496             'Test event',
1497             $user->id,
1498             'user',
1499             0,
1500             null,
1501             [
1502                 'modulename' => 'assign',
1503                 'instance' => $moduleinstance->id,
1504                 'courseid' => $course->id,
1505                 'timestart' => $originalstarttime->getTimestamp()
1506             ]
1507         );
1509         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
1510         $this->expectException('moodle_exception');
1511         $result = core_calendar_external::update_event_start_day($event->id, $newstartdate->getTimestamp());
1512         $result = external_api::clean_returnvalue(
1513             core_calendar_external::update_event_start_day_returns(),
1514             $result
1515         );
1516     }
1518     /**
1519      * Submit a request where the time duration until is earlier than the time
1520      * start in order to get a validation error from the server.
1521      */
1522     public function test_submit_create_update_form_validation_error() {
1523         $user = $this->getDataGenerator()->create_user();
1524         $timestart = new DateTime();
1525         $interval = new DateInterval("P1D"); // One day.
1526         $timedurationuntil = new DateTime();
1527         $timedurationuntil->sub($interval);
1528         $formdata = [
1529             'id' => 0,
1530             'userid' => $user->id,
1531             'modulename' => '',
1532             'instance' => 0,
1533             'visible' => 1,
1534             'name' => 'Test',
1535             'timestart' => [
1536                 'day' => $timestart->format('j'),
1537                 'month' => $timestart->format('n'),
1538                 'year' => $timestart->format('Y'),
1539                 'hour' => $timestart->format('G'),
1540                 'minute' => 0,
1541             ],
1542             'eventtype' => 'user',
1543             'description' => [
1544                 'text' => '',
1545                 'format' => 1,
1546             ],
1547             'location' => 'Test',
1548             'duration' => 1,
1549             'timedurationuntil' => [
1550                 'day' => $timedurationuntil->format('j'),
1551                 'month' => $timedurationuntil->format('n'),
1552                 'year' => $timedurationuntil->format('Y'),
1553                 'hour' => $timedurationuntil->format('G'),
1554                 'minute' => 0,
1555             ]
1556         ];
1558         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1560         $querystring = http_build_query($formdata, '', '&amp;');
1562         $this->resetAfterTest(true);
1563         $this->setUser($user);
1565         $result = external_api::clean_returnvalue(
1566             core_calendar_external::submit_create_update_form_returns(),
1567             core_calendar_external::submit_create_update_form($querystring)
1568         );
1570         $this->assertTrue($result['validationerror']);
1571     }
1573     /**
1574      * A user with the moodle/calendar:manageownentries capability at the
1575      * system context should be able to create a user event.
1576      */
1577     public function test_submit_create_update_form_create_user_event() {
1578         $generator = $this->getDataGenerator();
1579         $user = $generator->create_user();
1580         $roleid = $generator->create_role();
1581         $context = \context_system::instance();
1582         $timestart = new DateTime();
1583         $interval = new DateInterval("P1D"); // One day.
1584         $timedurationuntil = new DateTime();
1585         $timedurationuntil->add($interval);
1586         $formdata = [
1587             'id' => 0,
1588             'userid' => $user->id,
1589             'modulename' => '',
1590             'instance' => 0,
1591             'visible' => 1,
1592             'name' => 'Test',
1593             'timestart' => [
1594                 'day' => $timestart->format('j'),
1595                 'month' => $timestart->format('n'),
1596                 'year' => $timestart->format('Y'),
1597                 'hour' => $timestart->format('G'),
1598                 'minute' => 0,
1599             ],
1600             'eventtype' => 'user',
1601             'description' => [
1602                 'text' => '',
1603                 'format' => 1,
1604                 'itemid' => 0
1605             ],
1606             'location' => 'Test',
1607             'duration' => 1,
1608             'timedurationuntil' => [
1609                 'day' => $timedurationuntil->format('j'),
1610                 'month' => $timedurationuntil->format('n'),
1611                 'year' => $timedurationuntil->format('Y'),
1612                 'hour' => $timedurationuntil->format('G'),
1613                 'minute' => 0,
1614             ]
1615         ];
1617         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1618         $querystring = http_build_query($formdata, '', '&');
1620         $generator->role_assign($roleid, $user->id, $context->id);
1621         assign_capability('moodle/calendar:manageownentries', CAP_ALLOW, $roleid, $context, true);
1623         $user->ignoresesskey = true;
1624         $this->resetAfterTest(true);
1625         $this->setUser($user);
1627         $result = external_api::clean_returnvalue(
1628             core_calendar_external::submit_create_update_form_returns(),
1629             core_calendar_external::submit_create_update_form($querystring)
1630         );
1632         $event = $result['event'];
1633         $this->assertEquals($user->id, $event['userid']);
1634         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
1635         $this->assertEquals($formdata['name'], $event['name']);
1636     }
1638     /**
1639      * A user without the moodle/calendar:manageownentries capability at the
1640      * system context should not be able to create a user event.
1641      */
1642     public function test_submit_create_update_form_create_user_event_no_permission() {
1643         $generator = $this->getDataGenerator();
1644         $user = $generator->create_user();
1645         $roleid = $generator->create_role();
1646         $context = \context_system::instance();
1647         $timestart = new DateTime();
1648         $interval = new DateInterval("P1D"); // One day.
1649         $timedurationuntil = new DateTime();
1650         $timedurationuntil->add($interval);
1651         $formdata = [
1652             'id' => 0,
1653             'userid' => $user->id,
1654             'modulename' => '',
1655             'instance' => 0,
1656             'visible' => 1,
1657             'name' => 'Test',
1658             'timestart' => [
1659                 'day' => $timestart->format('j'),
1660                 'month' => $timestart->format('n'),
1661                 'year' => $timestart->format('Y'),
1662                 'hour' => $timestart->format('G'),
1663                 'minute' => 0,
1664             ],
1665             'eventtype' => 'user',
1666             'description' => [
1667                 'text' => '',
1668                 'format' => 1,
1669             ],
1670             'location' => 'Test',
1671             'duration' => 1,
1672             'timedurationuntil' => [
1673                 'day' => $timedurationuntil->format('j'),
1674                 'month' => $timedurationuntil->format('n'),
1675                 'year' => $timedurationuntil->format('Y'),
1676                 'hour' => $timedurationuntil->format('G'),
1677                 'minute' => 0,
1678             ]
1679         ];
1681         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1682         $querystring = http_build_query($formdata, '', '&');
1684         $generator->role_assign($roleid, $user->id, $context->id);
1685         assign_capability('moodle/calendar:manageownentries', CAP_PROHIBIT, $roleid, $context, true);
1687         $user->ignoresesskey = true;
1688         $this->resetAfterTest(true);
1689         $this->setUser($user);
1691         $this->expectException('moodle_exception');
1693         external_api::clean_returnvalue(
1694             core_calendar_external::submit_create_update_form_returns(),
1695             core_calendar_external::submit_create_update_form($querystring)
1696         );
1697     }
1699     /**
1700      * A user with the moodle/calendar:manageentries capability at the
1701      * site course context should be able to create a site event.
1702      */
1703     public function test_submit_create_update_form_create_site_event() {
1704         $generator = $this->getDataGenerator();
1705         $user = $generator->create_user();
1706         $context = context_system::instance();
1707         $roleid = $generator->create_role();
1708         $timestart = new DateTime();
1709         $interval = new DateInterval("P1D"); // One day.
1710         $timedurationuntil = new DateTime();
1711         $timedurationuntil->add($interval);
1712         $formdata = [
1713             'id' => 0,
1714             'userid' => $user->id,
1715             'modulename' => '',
1716             'instance' => 0,
1717             'visible' => 1,
1718             'name' => 'Test',
1719             'timestart' => [
1720                 'day' => $timestart->format('j'),
1721                 'month' => $timestart->format('n'),
1722                 'year' => $timestart->format('Y'),
1723                 'hour' => $timestart->format('G'),
1724                 'minute' => 0,
1725             ],
1726             'eventtype' => 'site',
1727             'description' => [
1728                 'text' => '',
1729                 'format' => 1,
1730                 'itemid' => 0
1731             ],
1732             'location' => 'Test',
1733             'duration' => 1,
1734             'timedurationuntil' => [
1735                 'day' => $timedurationuntil->format('j'),
1736                 'month' => $timedurationuntil->format('n'),
1737                 'year' => $timedurationuntil->format('Y'),
1738                 'hour' => $timedurationuntil->format('G'),
1739                 'minute' => 0,
1740             ]
1741         ];
1743         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1744         $querystring = http_build_query($formdata, '', '&');
1746         $generator->role_assign($roleid, $user->id, $context->id);
1748         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
1750         $user->ignoresesskey = true;
1751         $this->resetAfterTest(true);
1752         $this->setUser($user);
1754         $result = external_api::clean_returnvalue(
1755             core_calendar_external::submit_create_update_form_returns(),
1756             core_calendar_external::submit_create_update_form($querystring)
1757         );
1759         $event = $result['event'];
1760         $this->assertEquals($user->id, $event['userid']);
1761         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
1762         $this->assertEquals($formdata['name'], $event['name']);
1763     }
1765     /**
1766      * A user without the moodle/calendar:manageentries capability at the
1767      * site course context should not be able to create a site event.
1768      */
1769     public function test_submit_create_update_form_create_site_event_no_permission() {
1770         $generator = $this->getDataGenerator();
1771         $user = $generator->create_user();
1772         $context = context_course::instance(SITEID);
1773         $roleid = $generator->create_role();
1774         $timestart = new DateTime();
1775         $interval = new DateInterval("P1D"); // One day.
1776         $timedurationuntil = new DateTime();
1777         $timedurationuntil->add($interval);
1778         $formdata = [
1779             'id' => 0,
1780             'userid' => $user->id,
1781             'modulename' => '',
1782             'instance' => 0,
1783             'visible' => 1,
1784             'name' => 'Test',
1785             'timestart' => [
1786                 'day' => $timestart->format('j'),
1787                 'month' => $timestart->format('n'),
1788                 'year' => $timestart->format('Y'),
1789                 'hour' => $timestart->format('G'),
1790                 'minute' => 0,
1791             ],
1792             'eventtype' => 'site',
1793             'description' => [
1794                 'text' => '',
1795                 'format' => 1,
1796             ],
1797             'location' => 'Test',
1798             'duration' => 1,
1799             'timedurationuntil' => [
1800                 'day' => $timedurationuntil->format('j'),
1801                 'month' => $timedurationuntil->format('n'),
1802                 'year' => $timedurationuntil->format('Y'),
1803                 'hour' => $timedurationuntil->format('G'),
1804                 'minute' => 0,
1805             ]
1806         ];
1808         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1809         $querystring = http_build_query($formdata, '', '&');
1811         $generator->role_assign($roleid, $user->id, $context->id);
1813         assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
1815         $user->ignoresesskey = true;
1816         $this->resetAfterTest(true);
1817         $this->setUser($user);
1819         $result = external_api::clean_returnvalue(
1820             core_calendar_external::submit_create_update_form_returns(),
1821             core_calendar_external::submit_create_update_form($querystring)
1822         );
1824         $this->assertTrue($result['validationerror']);
1825     }
1827     /**
1828      * A user that has the moodle/calendar:manageentries in a course that they
1829      * are enrolled in should be able to create a course event in that course.
1830      */
1831     public function test_submit_create_update_form_create_course_event() {
1832         $generator = $this->getDataGenerator();
1833         $user = $generator->create_user();
1834         $course = $generator->create_course();
1835         $context = context_course::instance($course->id);
1836         $roleid = $generator->create_role();
1837         $timestart = new DateTime();
1838         $interval = new DateInterval("P1D"); // One day.
1839         $timedurationuntil = new DateTime();
1840         $timedurationuntil->add($interval);
1841         $formdata = [
1842             'id' => 0,
1843             'userid' => $user->id,
1844             'modulename' => '',
1845             'instance' => 0,
1846             'visible' => 1,
1847             'name' => 'Test',
1848             'timestart' => [
1849                 'day' => $timestart->format('j'),
1850                 'month' => $timestart->format('n'),
1851                 'year' => $timestart->format('Y'),
1852                 'hour' => $timestart->format('G'),
1853                 'minute' => 0,
1854             ],
1855             'eventtype' => 'course',
1856             'courseid' => $course->id,
1857             'description' => [
1858                 'text' => '',
1859                 'format' => 1,
1860                 'itemid' => 0,
1861             ],
1862             'location' => 'Test',
1863             'duration' => 1,
1864             'timedurationuntil' => [
1865                 'day' => $timedurationuntil->format('j'),
1866                 'month' => $timedurationuntil->format('n'),
1867                 'year' => $timedurationuntil->format('Y'),
1868                 'hour' => $timedurationuntil->format('G'),
1869                 'minute' => 0,
1870             ]
1871         ];
1873         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1874         $querystring = http_build_query($formdata, '', '&');
1876         $generator->enrol_user($user->id, $course->id, 'student');
1877         $generator->role_assign($roleid, $user->id, $context->id);
1879         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
1881         $user->ignoresesskey = true;
1882         $this->resetAfterTest(true);
1883         $this->setUser($user);
1885         $result = external_api::clean_returnvalue(
1886             core_calendar_external::submit_create_update_form_returns(),
1887             core_calendar_external::submit_create_update_form($querystring)
1888         );
1890         $event = $result['event'];
1891         $this->assertEquals($user->id, $event['userid']);
1892         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
1893         $this->assertEquals($formdata['name'], $event['name']);
1894         $this->assertEquals($formdata['courseid'], $event['course']['id']);
1895     }
1897     /**
1898      * A user without the moodle/calendar:manageentries capability in a course
1899      * that they are enrolled in should not be able to create a course event in that course.
1900      */
1901     public function test_submit_create_update_form_create_course_event_no_permission() {
1902         $generator = $this->getDataGenerator();
1903         $user = $generator->create_user();
1904         $course = $generator->create_course();
1905         $context = context_course::instance($course->id);
1906         $roleid = $generator->create_role();
1907         $timestart = new DateTime();
1908         $interval = new DateInterval("P1D"); // One day.
1909         $timedurationuntil = new DateTime();
1910         $timedurationuntil->add($interval);
1911         $formdata = [
1912             'id' => 0,
1913             'userid' => $user->id,
1914             'modulename' => '',
1915             'instance' => 0,
1916             'visible' => 1,
1917             'name' => 'Test',
1918             'timestart' => [
1919                 'day' => $timestart->format('j'),
1920                 'month' => $timestart->format('n'),
1921                 'year' => $timestart->format('Y'),
1922                 'hour' => $timestart->format('G'),
1923                 'minute' => 0,
1924             ],
1925             'eventtype' => 'course',
1926             'courseid' => $course->id,
1927             'description' => [
1928                 'text' => '',
1929                 'format' => 1,
1930             ],
1931             'location' => 'Test',
1932             'duration' => 1,
1933             'timedurationuntil' => [
1934                 'day' => $timedurationuntil->format('j'),
1935                 'month' => $timedurationuntil->format('n'),
1936                 'year' => $timedurationuntil->format('Y'),
1937                 'hour' => $timedurationuntil->format('G'),
1938                 'minute' => 0,
1939             ]
1940         ];
1942         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1943         $querystring = http_build_query($formdata, '', '&');
1945         $generator->enrol_user($user->id, $course->id, 'student');
1946         $generator->role_assign($roleid, $user->id, $context->id);
1948         assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
1950         $user->ignoresesskey = true;
1951         $this->resetAfterTest(true);
1952         $this->setUser($user);
1954         $result = external_api::clean_returnvalue(
1955             core_calendar_external::submit_create_update_form_returns(),
1956             core_calendar_external::submit_create_update_form($querystring)
1957         );
1959         $this->assertTrue($result['validationerror']);
1960     }
1962     /**
1963      * A user should not be able to create an event for a course that they are
1964      * not enrolled in.
1965      */
1966     public function test_submit_create_update_form_create_course_event_not_enrolled() {
1967         $generator = $this->getDataGenerator();
1968         $user = $generator->create_user();
1969         $course = $generator->create_course();
1970         $course2 = $generator->create_course();
1971         $context = context_course::instance($course->id);
1972         $roleid = $generator->create_role();
1973         $timestart = new DateTime();
1974         $interval = new DateInterval("P1D"); // One day.
1975         $timedurationuntil = new DateTime();
1976         $timedurationuntil->add($interval);
1977         $formdata = [
1978             'id' => 0,
1979             'userid' => $user->id,
1980             'modulename' => '',
1981             'instance' => 0,
1982             'visible' => 1,
1983             'name' => 'Test',
1984             'timestart' => [
1985                 'day' => $timestart->format('j'),
1986                 'month' => $timestart->format('n'),
1987                 'year' => $timestart->format('Y'),
1988                 'hour' => $timestart->format('G'),
1989                 'minute' => 0,
1990             ],
1991             'eventtype' => 'course',
1992             'courseid' => $course2->id, // Not enrolled.
1993             'description' => [
1994                 'text' => '',
1995                 'format' => 1,
1996             ],
1997             'location' => 'Test',
1998             'duration' => 1,
1999             'timedurationuntil' => [
2000                 'day' => $timedurationuntil->format('j'),
2001                 'month' => $timedurationuntil->format('n'),
2002                 'year' => $timedurationuntil->format('Y'),
2003                 'hour' => $timedurationuntil->format('G'),
2004                 'minute' => 0,
2005             ]
2006         ];
2008         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
2009         $querystring = http_build_query($formdata, '', '&');
2011         $generator->enrol_user($user->id, $course->id, 'student');
2012         $generator->role_assign($roleid, $user->id, $context->id);
2014         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
2016         $user->ignoresesskey = true;
2017         $this->resetAfterTest(true);
2018         $this->setUser($user);
2020         $result = external_api::clean_returnvalue(
2021             core_calendar_external::submit_create_update_form_returns(),
2022             core_calendar_external::submit_create_update_form($querystring)
2023         );
2025         $this->assertTrue($result['validationerror']);
2026     }
2028     /**
2029      * A user should be able to create an event for a group that they are a member of in
2030      * a course in which they are enrolled and have the moodle/calendar:manageentries capability.
2031      */
2032     public function test_submit_create_update_form_create_group_event_group_member_manage_course() {
2033         $generator = $this->getDataGenerator();
2034         $user = $generator->create_user();
2035         $course = $generator->create_course();
2036         $group = $generator->create_group(array('courseid' => $course->id));
2037         $context = context_course::instance($course->id);
2038         $roleid = $generator->create_role();
2039         $timestart = new DateTime();
2040         $interval = new DateInterval("P1D"); // One day.
2041         $timedurationuntil = new DateTime();
2042         $timedurationuntil->add($interval);
2043         $formdata = [
2044             'id' => 0,
2045             'userid' => $user->id,
2046             'modulename' => '',
2047             'instance' => 0,
2048             'visible' => 1,
2049             'name' => 'Test',
2050             'timestart' => [
2051                 'day' => $timestart->format('j'),
2052                 'month' => $timestart->format('n'),
2053                 'year' => $timestart->format('Y'),
2054                 'hour' => $timestart->format('G'),
2055                 'minute' => 0,
2056             ],
2057             'eventtype' => 'group',
2058             'groupid' => $group->id,
2059             'groupcourseid' => $course->id,
2060             'description' => [
2061                 'text' => '',
2062                 'format' => 1,
2063                 'itemid' => 0
2064             ],
2065             'location' => 'Test',
2066             'duration' => 1,
2067             'timedurationuntil' => [
2068                 'day' => $timedurationuntil->format('j'),
2069                 'month' => $timedurationuntil->format('n'),
2070                 'year' => $timedurationuntil->format('Y'),
2071                 'hour' => $timedurationuntil->format('G'),
2072                 'minute' => 0,
2073             ]
2074         ];
2076         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
2077         $querystring = http_build_query($formdata, '', '&');
2079         $generator->enrol_user($user->id, $course->id, 'student');
2080         $generator->role_assign($roleid, $user->id, $context->id);
2081         $generator->create_group_member(['groupid' => $group->id, 'userid' => $user->id]);
2083         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
2085         $user->ignoresesskey = true;
2086         $this->resetAfterTest(true);
2087         $this->setUser($user);
2089         $result = external_api::clean_returnvalue(
2090             core_calendar_external::submit_create_update_form_returns(),
2091             core_calendar_external::submit_create_update_form($querystring)
2092         );
2094         $event = $result['event'];
2095         $this->assertEquals($user->id, $event['userid']);
2096         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
2097         $this->assertEquals($formdata['name'], $event['name']);
2098         $this->assertEquals($group->id, $event['groupid']);
2099     }
2101     /**
2102      * A user should be able to create an event for a group that they are a member of in
2103      * a course in which they are enrolled and have the moodle/calendar:managegroupentries capability.
2104      */
2105     public function test_submit_create_update_form_create_group_event_group_member_manage_group_entries() {
2106         $generator = $this->getDataGenerator();
2107         $user = $generator->create_user();
2108         $course = $generator->create_course();
2109         $group = $generator->create_group(array('courseid' => $course->id));
2110         $context = context_course::instance($course->id);
2111         $roleid = $generator->create_role();
2112         $timestart = new DateTime();
2113         $interval = new DateInterval("P1D"); // One day.
2114         $timedurationuntil = new DateTime();
2115         $timedurationuntil->add($interval);
2116         $formdata = [
2117             'id' => 0,
2118             'userid' => $user->id,
2119             'modulename' => '',
2120             'instance' => 0,
2121             'visible' => 1,
2122             'name' => 'Test',
2123             'timestart' => [
2124                 'day' => $timestart->format('j'),
2125                 'month' => $timestart->format('n'),
2126                 'year' => $timestart->format('Y'),
2127                 'hour' => $timestart->format('G'),
2128                 'minute' => 0,
2129             ],
2130             'eventtype' => 'group',
2131             'groupid' => $group->id,
2132             'groupcourseid' => $course->id,
2133             'description' => [
2134                 'text' => '',
2135                 'format' => 1,
2136                 'itemid' => 0
2137             ],
2138             'location' => 'Test',
2139             'duration' => 1,
2140             'timedurationuntil' => [
2141                 'day' => $timedurationuntil->format('j'),
2142                 'month' => $timedurationuntil->format('n'),
2143                 'year' => $timedurationuntil->format('Y'),
2144                 'hour' => $timedurationuntil->format('G'),
2145                 'minute' => 0,
2146             ]
2147         ];
2149         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
2150         $querystring = http_build_query($formdata, '', '&');
2152         $generator->enrol_user($user->id, $course->id, 'student');
2153         $generator->role_assign($roleid, $user->id, $context->id);
2154         $generator->create_group_member(['groupid' => $group->id, 'userid' => $user->id]);
2156         assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
2157         assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true);
2159         $user->ignoresesskey = true;
2160         $this->resetAfterTest(true);
2161         $this->setUser($user);
2163         $result = external_api::clean_returnvalue(
2164             core_calendar_external::submit_create_update_form_returns(),
2165             core_calendar_external::submit_create_update_form($querystring)
2166         );
2168         $event = $result['event'];
2169         $this->assertEquals($user->id, $event['userid']);
2170         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
2171         $this->assertEquals($formdata['name'], $event['name']);
2172         $this->assertEquals($group->id, $event['groupid']);
2173     }
2175     /**
2176      * A user should be able to create an event for any group in a course in which
2177      * they are enrolled and have the moodle/site:accessallgroups capability.
2178      */
2179     public function test_submit_create_update_form_create_group_event_access_all_groups() {
2180         $generator = $this->getDataGenerator();
2181         $user = $generator->create_user();
2182         $course = $generator->create_course();
2183         $group = $generator->create_group(array('courseid' => $course->id));
2184         $context = context_course::instance($course->id);
2185         $roleid = $generator->create_role();
2186         $timestart = new DateTime();
2187         $interval = new DateInterval("P1D"); // One day.
2188         $timedurationuntil = new DateTime();
2189         $timedurationuntil->add($interval);
2190         $formdata = [
2191             'id' => 0,
2192             'userid' => $user->id,
2193             'modulename' => '',
2194             'instance' => 0,
2195             'visible' => 1,
2196             'name' => 'Test',
2197             'timestart' => [
2198                 'day' => $timestart->format('j'),
2199                 'month' => $timestart->format('n'),
2200                 'year' => $timestart->format('Y'),
2201                 'hour' => $timestart->format('G'),
2202                 'minute' => 0,
2203             ],
2204             'eventtype' => 'group',
2205             'groupid' => $group->id,
2206             'groupcourseid' => $course->id,
2207             'description' => [
2208                 'text' => '',
2209                 'format' => 1,
2210                 'itemid' => 0
2211             ],
2212             'location' => 'Test',
2213             'duration' => 1,
2214             'timedurationuntil' => [
2215                 'day' => $timedurationuntil->format('j'),
2216                 'month' => $timedurationuntil->format('n'),
2217                 'year' => $timedurationuntil->format('Y'),
2218                 'hour' => $timedurationuntil->format('G'),
2219                 'minute' => 0,
2220             ]
2221         ];
2223         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
2224         $querystring = http_build_query($formdata, '', '&');
2226         $generator->enrol_user($user->id, $course->id, 'student');
2227         $generator->role_assign($roleid, $user->id, $context->id);
2229         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
2230         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context, true);
2232         $user->ignoresesskey = true;
2233         $this->resetAfterTest(true);
2234         $this->setUser($user);
2236         $result = external_api::clean_returnvalue(
2237             core_calendar_external::submit_create_update_form_returns(),
2238             core_calendar_external::submit_create_update_form($querystring)
2239         );
2241         $event = $result['event'];
2242         $this->assertEquals($user->id, $event['userid']);
2243         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
2244         $this->assertEquals($formdata['name'], $event['name']);
2245         $this->assertEquals($group->id, $event['groupid']);
2246     }
2248     /**
2249      * A user should not be able to create an event for any group that they are not a
2250      * member of in a course in which they are enrolled but don't have the
2251      * moodle/site:accessallgroups capability.
2252      */
2253     public function test_submit_create_update_form_create_group_event_non_member_no_permission() {
2254         $generator = $this->getDataGenerator();
2255         $user = $generator->create_user();
2256         $course = $generator->create_course();
2257         $group = $generator->create_group(array('courseid' => $course->id));
2258         $context = context_course::instance($course->id);
2259         $roleid = $generator->create_role();
2260         $timestart = new DateTime();
2261         $interval = new DateInterval("P1D"); // One day.
2262         $timedurationuntil = new DateTime();
2263         $timedurationuntil->add($interval);
2264         $formdata = [
2265             'id' => 0,
2266             'userid' => $user->id,
2267             'modulename' => '',
2268             'instance' => 0,
2269             'visible' => 1,
2270             'name' => 'Test',
2271             'timestart' => [
2272                 'day' => $timestart->format('j'),
2273                 'month' => $timestart->format('n'),
2274                 'year' => $timestart->format('Y'),
2275                 'hour' => $timestart->format('G'),
2276                 'minute' => 0,
2277             ],
2278             'eventtype' => 'group',
2279             'groupid' => $group->id,
2280             'groupcourseid' => $course->id,
2281             'description' => [
2282                 'text' => '',
2283                 'format' => 1,
2284             ],
2285             'location' => 'Test',
2286             'duration' => 1,
2287             'timedurationuntil' => [
2288                 'day' => $timedurationuntil->format('j'),
2289                 'month' => $timedurationuntil->format('n'),
2290                 'year' => $timedurationuntil->format('Y'),
2291                 'hour' => $timedurationuntil->format('G'),
2292                 'minute' => 0,
2293             ]
2294         ];
2296         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
2297         $querystring = http_build_query($formdata, '', '&');
2299         $generator->enrol_user($user->id, $course->id, 'student');
2300         $generator->role_assign($roleid, $user->id, $context->id);
2302         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
2303         assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $roleid, $context, true);
2305         $user->ignoresesskey = true;
2306         $this->resetAfterTest(true);
2307         $this->setUser($user);
2309         $result = external_api::clean_returnvalue(
2310             core_calendar_external::submit_create_update_form_returns(),
2311             core_calendar_external::submit_create_update_form($querystring)
2312         );
2314         $this->assertTrue($result['validationerror']);
2315     }
2317     /**
2318      * A user should not be able load the calendar monthly view for a course they cannot access.
2319      */
2320     public function test_get_calendar_monthly_view_no_course_permission() {
2321         global $USER;
2322         $this->resetAfterTest(true);
2323         $this->setAdminUser();
2325         $generator = $this->getDataGenerator();
2326         $user1 = $generator->create_user();
2327         $user2 = $generator->create_user();
2328         $course = $generator->create_course();
2329         $generator->enrol_user($user1->id, $course->id, 'student');
2330         $name = 'Course Event (course' . $course->id . ')';
2331         $record = new stdClass();
2332         $record->courseid = $course->id;
2333         $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record);
2335         $timestart = new DateTime();
2336         // Admin can load the course.
2337         $data = external_api::clean_returnvalue(
2338             core_calendar_external::get_calendar_monthly_view_returns(),
2339             core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
2340                                                               $course->id, null, false, true)
2341         );
2342         $this->assertEquals($data['courseid'], $course->id);
2343         // User enrolled in the course can load the course calendar.
2344         $this->setUser($user1);
2345         $data = external_api::clean_returnvalue(
2346             core_calendar_external::get_calendar_monthly_view_returns(),
2347             core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
2348                                                               $course->id, null, false, true)
2349         );
2350         $this->assertEquals($data['courseid'], $course->id);
2351         // User not enrolled in the course cannot load the course calendar.
2352         $this->setUser($user2);
2353         $this->expectException('require_login_exception');
2354         $data = external_api::clean_returnvalue(
2355             core_calendar_external::get_calendar_monthly_view_returns(),
2356             core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
2357                                                               $course->id, null, false, false)
2358         );
2359     }
2361     /**
2362      * A user should not be able load the calendar day view for a course they cannot access.
2363      */
2364     public function test_get_calendar_day_view_no_course_permission() {
2365         global $USER;
2366         $this->resetAfterTest(true);
2367         $this->setAdminUser();
2369         $generator = $this->getDataGenerator();
2370         $user1 = $generator->create_user();
2371         $user2 = $generator->create_user();
2372         $course = $generator->create_course();
2373         $generator->enrol_user($user1->id, $course->id, 'student');
2374         $name = 'Course Event (course' . $course->id . ')';
2375         $record = new stdClass();
2376         $record->courseid = $course->id;
2377         $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record);
2379         $timestart = new DateTime();
2380         // Admin can load the course.
2381         $data = external_api::clean_returnvalue(
2382             core_calendar_external::get_calendar_day_view_returns(),
2383             core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'),
2384                                                           $timestart->format('j'), $course->id, null)
2385         );
2386         $this->assertEquals($data['courseid'], $course->id);
2387         // User enrolled in the course can load the course calendar.
2388         $this->setUser($user1);
2389         $data = external_api::clean_returnvalue(
2390             core_calendar_external::get_calendar_day_view_returns(),
2391             core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'),
2392                                                           $timestart->format('j'), $course->id, null)
2393         );
2394         $this->assertEquals($data['courseid'], $course->id);
2395         // User not enrolled in the course cannot load the course calendar.
2396         $this->setUser($user2);
2397         $this->expectException('require_login_exception');
2398         $data = external_api::clean_returnvalue(
2399             core_calendar_external::get_calendar_day_view_returns(),
2400             core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'),
2401                                                           $timestart->format('j'), $course->id, null)
2402         );
2403     }
2405     /**
2406      * A user should not be able load the calendar upcoming view for a course they cannot access.
2407      */
2408     public function test_get_calendar_upcoming_view_no_course_permission() {
2409         global $USER;
2410         $this->resetAfterTest(true);
2411         $this->setAdminUser();
2413         $generator = $this->getDataGenerator();
2414         $user1 = $generator->create_user();
2415         $user2 = $generator->create_user();
2416         $course = $generator->create_course();
2417         $generator->enrol_user($user1->id, $course->id, 'student');
2418         $name = 'Course Event (course' . $course->id . ')';
2419         $record = new stdClass();
2420         $record->courseid = $course->id;
2421         $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record);
2423         // Admin can load the course.
2424         $data = external_api::clean_returnvalue(
2425             core_calendar_external::get_calendar_upcoming_view_returns(),
2426             core_calendar_external::get_calendar_upcoming_view($course->id, null)
2427         );
2428         $this->assertEquals($data['courseid'], $course->id);
2429         // User enrolled in the course can load the course calendar.
2430         $this->setUser($user1);
2431         $data = external_api::clean_returnvalue(
2432             core_calendar_external::get_calendar_upcoming_view_returns(),
2433             core_calendar_external::get_calendar_upcoming_view($course->id, null)
2434         );
2435         $this->assertEquals($data['courseid'], $course->id);
2436         // User not enrolled in the course cannot load the course calendar.
2437         $this->setUser($user2);
2438         $this->expectException('require_login_exception');
2439         $data = external_api::clean_returnvalue(
2440             core_calendar_external::get_calendar_upcoming_view_returns(),
2441             core_calendar_external::get_calendar_upcoming_view($course->id, null)
2442         );
2443     }
2445     /**
2446      * A user should not be able load the calendar event for a course they cannot access.
2447      */
2448     public function test_get_calendar_event_by_id_no_course_permission() {
2449         global $USER;
2450         $this->resetAfterTest(true);
2451         $this->setAdminUser();
2453         $generator = $this->getDataGenerator();
2454         $user1 = $generator->create_user();
2455         $user2 = $generator->create_user();
2456         $course = $generator->create_course();
2457         $generator->enrol_user($user1->id, $course->id, 'student');
2458         $name = 'Course Event (course' . $course->id . ')';
2459         $record = new stdClass();
2460         $record->courseid = $course->id;
2461         $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record);
2463         // Admin can load the course event.
2464         $data = external_api::clean_returnvalue(
2465             core_calendar_external::get_calendar_event_by_id_returns(),
2466             core_calendar_external::get_calendar_event_by_id($courseevent->id)
2467         );
2468         $this->assertEquals($data['event']['id'], $courseevent->id);
2469         // User enrolled in the course can load the course event.
2470         $this->setUser($user1);
2471         $data = external_api::clean_returnvalue(
2472             core_calendar_external::get_calendar_event_by_id_returns(),
2473             core_calendar_external::get_calendar_event_by_id($courseevent->id)
2474         );
2475         $this->assertEquals($data['event']['id'], $courseevent->id);
2476         // User not enrolled in the course cannot load the course event.
2477         $this->setUser($user2);
2478         $this->expectException('required_capability_exception');
2479         $data = external_api::clean_returnvalue(
2480             core_calendar_external::get_calendar_event_by_id_returns(),
2481             core_calendar_external::get_calendar_event_by_id($courseevent->id)
2482         );
2483     }
2485     /**
2486      * A user should not be able load the calendar events for a category they cannot see.
2487      */
2488     public function test_get_calendar_events_hidden_category() {
2489         global $USER;
2490         $this->resetAfterTest(true);
2491         $this->setAdminUser();
2493         $generator = $this->getDataGenerator();
2494         $user1 = $generator->create_user();
2495         $category = $generator->create_category(['visible' => 0]);
2496         $name = 'Category Event (category: ' . $category->id . ')';
2497         $record = new stdClass();
2498         $record->categoryid = $category->id;
2499         $categoryevent = $this->create_calendar_event($name, $USER->id, 'category', 0, time(), $record);
2501         $events = [
2502             'eventids' => [$categoryevent->id]
2503         ];
2504         $options = [];
2505         // Admin can load the category event.
2506         $data = external_api::clean_returnvalue(
2507             core_calendar_external::get_calendar_events_returns(),
2508             core_calendar_external::get_calendar_events($events, $options)
2509         );
2510         $this->assertEquals($data['events'][0]['id'], $categoryevent->id);
2511         // User with no special permission to see hidden categories will not see the event.
2512         $this->setUser($user1);
2513         $data = external_api::clean_returnvalue(
2514             core_calendar_external::get_calendar_events_returns(),
2515             core_calendar_external::get_calendar_events($events, $options)
2516         );
2517         $this->assertCount(0, $data['events']);
2518         $this->assertEquals('nopermissions', $data['warnings'][0]['warningcode']);
2519     }