MDL-64641 calendar: New WS core_calendar_get_allowed_event_types
[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']);
683         // Requesting action events on behalf of another user.
684         $this->setAdminUser();
685         $result = core_calendar_external::get_calendar_action_events_by_timesort(5, null, 0, 20, false, $user->id);
686         $result = external_api::clean_returnvalue(
687             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
688             $result
689         );
690         $events = $result['events'];
692         $this->assertCount(4, $events);
693         $this->assertEquals('Event 5', $events[0]['name']);
694         $this->assertEquals('Event 6', $events[1]['name']);
695         $this->assertEquals('Event 7', $events[2]['name']);
696         $this->assertEquals('Event 8', $events[3]['name']);
697         $this->assertEquals($event5->id, $result['firstid']);
698         $this->assertEquals($event8->id, $result['lastid']);
699     }
701     /**
702      * Requesting calendar events before a given time should return all events with a sort
703      * time at or before the requested time (inclusive). All events after that time
704      * should not be returned.
705      *
706      * If there are no events before the given time then an empty result set should be
707      * returned.
708      */
709     public function test_get_calendar_action_events_by_timesort_before_time() {
710         $user = $this->getDataGenerator()->create_user();
711         $course = $this->getDataGenerator()->create_course();
712         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
713         $moduleinstance = $generator->create_instance(['course' => $course->id]);
715         $this->getDataGenerator()->enrol_user($user->id, $course->id);
716         $this->resetAfterTest(true);
717         $this->setUser($user);
719         $params = [
720             'type' => CALENDAR_EVENT_TYPE_ACTION,
721             'modulename' => 'assign',
722             'instance' => $moduleinstance->id,
723             'courseid' => $course->id,
724         ];
726         $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2]));
727         $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3]));
728         $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4]));
729         $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5]));
730         $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6]));
731         $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7]));
732         $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8]));
733         $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 9]));
735         $result = core_calendar_external::get_calendar_action_events_by_timesort(null, 5);
736         $result = external_api::clean_returnvalue(
737             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
738             $result
739         );
740         $events = $result['events'];
742         $this->assertCount(4, $events);
743         $this->assertEquals('Event 1', $events[0]['name']);
744         $this->assertEquals('Event 2', $events[1]['name']);
745         $this->assertEquals('Event 3', $events[2]['name']);
746         $this->assertEquals('Event 4', $events[3]['name']);
747         $this->assertEquals($event1->id, $result['firstid']);
748         $this->assertEquals($event4->id, $result['lastid']);
750         $result = core_calendar_external::get_calendar_action_events_by_timesort(null, 1);
751         $result = external_api::clean_returnvalue(
752             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
753             $result
754         );
756         $this->assertEmpty($result['events']);
757         $this->assertNull($result['firstid']);
758         $this->assertNull($result['lastid']);
760         // Requesting action events on behalf of another user.
761         $this->setAdminUser();
763         $result = core_calendar_external::get_calendar_action_events_by_timesort(null, 5, 0, 20, false, $user->id);
764         $result = external_api::clean_returnvalue(
765             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
766             $result
767         );
768         $events = $result['events'];
770         $this->assertCount(4, $events);
771         $this->assertEquals('Event 1', $events[0]['name']);
772         $this->assertEquals('Event 2', $events[1]['name']);
773         $this->assertEquals('Event 3', $events[2]['name']);
774         $this->assertEquals('Event 4', $events[3]['name']);
775         $this->assertEquals($event1->id, $result['firstid']);
776         $this->assertEquals($event4->id, $result['lastid']);
777     }
779     /**
780      * Test retrieving event that was overridden for a user
781      */
782     public function test_get_calendar_events_override() {
783         $user = $this->getDataGenerator()->create_user();
784         $user2 = $this->getDataGenerator()->create_user();
785         $teacher = $this->getDataGenerator()->create_user();
786         $anotheruser = $this->getDataGenerator()->create_user();
787         $course = $this->getDataGenerator()->create_course();
788         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
789         $moduleinstance = $generator->create_instance(['course' => $course->id]);
791         $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
792         $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
793         $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
794         $this->resetAfterTest(true);
795         $this->setAdminUser();
797         $params = [
798             'type' => CALENDAR_EVENT_TYPE_ACTION,
799             'modulename' => 'assign',
800             'instance' => $moduleinstance->id,
801         ];
803         $now = time();
804         // Create two events - one for everybody in the course and one only for the first student.
805         $event1 = $this->create_calendar_event('Base event', 0, 'due', 0, $now + DAYSECS, $params + ['courseid' => $course->id]);
806         $event2 = $this->create_calendar_event('User event', $user->id, 'due', 0, $now + 2*DAYSECS, $params + ['courseid' => 0]);
808         // Retrieve course events for the second student - only one "Base event" is returned.
809         $this->setUser($user2);
810         $paramevents = array('courseids' => array($course->id));
811         $options = array ('siteevents' => true, 'userevents' => true);
812         $events = core_calendar_external::get_calendar_events($paramevents, $options);
813         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
814         $this->assertEquals(1, count($events['events']));
815         $this->assertEquals(0, count($events['warnings']));
816         $this->assertEquals('Base event', $events['events'][0]['name']);
818         // Retrieve events for the first student - both events are returned.
819         $this->setUser($user);
820         $events = core_calendar_external::get_calendar_events($paramevents, $options);
821         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
822         $this->assertEquals(2, count($events['events']));
823         $this->assertEquals(0, count($events['warnings']));
824         $this->assertEquals('Base event', $events['events'][0]['name']);
825         $this->assertEquals('User event', $events['events'][1]['name']);
827         // Retrieve events by id as a teacher, 'User event' should be returned since teacher has access to this course.
828         $this->setUser($teacher);
829         $paramevents = ['eventids' => [$event2->id]];
830         $events = core_calendar_external::get_calendar_events($paramevents, $options);
831         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
832         $this->assertEquals(1, count($events['events']));
833         $this->assertEquals(0, count($events['warnings']));
834         $this->assertEquals('User event', $events['events'][0]['name']);
836         // Retrieve events by id as another user, nothing should be returned.
837         $this->setUser($anotheruser);
838         $paramevents = ['eventids' => [$event2->id, $event1->id]];
839         $events = core_calendar_external::get_calendar_events($paramevents, $options);
840         $events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
841         $this->assertEquals(0, count($events['events']));
842         $this->assertEquals(0, count($events['warnings']));
843     }
845     /**
846      * Requesting calendar events within a given time range should return all events with
847      * a sort time between the lower and upper time bound (inclusive).
848      *
849      * If there are no events in the given time range then an empty result set should be
850      * returned.
851      */
852     public function test_get_calendar_action_events_by_timesort_time_range() {
853         $user = $this->getDataGenerator()->create_user();
854         $course = $this->getDataGenerator()->create_course();
855         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
856         $moduleinstance = $generator->create_instance(['course' => $course->id]);
858         $this->getDataGenerator()->enrol_user($user->id, $course->id);
859         $this->resetAfterTest(true);
860         $this->setUser($user);
862         $params = [
863             'type' => CALENDAR_EVENT_TYPE_ACTION,
864             'modulename' => 'assign',
865             'instance' => $moduleinstance->id,
866             'courseid' => $course->id,
867         ];
869         $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 1]));
870         $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2]));
871         $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3]));
872         $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4]));
873         $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5]));
874         $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6]));
875         $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7]));
876         $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8]));
878         $result = core_calendar_external::get_calendar_action_events_by_timesort(3, 6);
879         $result = external_api::clean_returnvalue(
880             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
881             $result
882         );
883         $events = $result['events'];
885         $this->assertCount(4, $events);
886         $this->assertEquals('Event 3', $events[0]['name']);
887         $this->assertEquals('Event 4', $events[1]['name']);
888         $this->assertEquals('Event 5', $events[2]['name']);
889         $this->assertEquals('Event 6', $events[3]['name']);
890         $this->assertEquals($event3->id, $result['firstid']);
891         $this->assertEquals($event6->id, $result['lastid']);
893         $result = core_calendar_external::get_calendar_action_events_by_timesort(10, 15);
894         $result = external_api::clean_returnvalue(
895             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
896             $result
897         );
899         $this->assertEmpty($result['events']);
900         $this->assertNull($result['firstid']);
901         $this->assertNull($result['lastid']);
902     }
904     /**
905      * Requesting calendar events within a given time range and a limit and offset should return
906      * the number of events up to the given limit value that have a sort time between the lower
907      * and uppper time bound (inclusive) where the result set is shifted by the offset value.
908      *
909      * If there are no events in the given time range then an empty result set should be
910      * returned.
911      */
912     public function test_get_calendar_action_events_by_timesort_time_limit_offset() {
913         $user = $this->getDataGenerator()->create_user();
914         $course = $this->getDataGenerator()->create_course();
915         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
916         $moduleinstance = $generator->create_instance(['course' => $course->id]);
918         $this->getDataGenerator()->enrol_user($user->id, $course->id);
919         $this->resetAfterTest(true);
920         $this->setUser($user);
922         $params = [
923             'type' => CALENDAR_EVENT_TYPE_ACTION,
924             'modulename' => 'assign',
925             'instance' => $moduleinstance->id,
926             'courseid' => $course->id,
927         ];
929         $event1 = $this->create_calendar_event('Event 1', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 1]));
930         $event2 = $this->create_calendar_event('Event 2', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 2]));
931         $event3 = $this->create_calendar_event('Event 3', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 3]));
932         $event4 = $this->create_calendar_event('Event 4', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 4]));
933         $event5 = $this->create_calendar_event('Event 5', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 5]));
934         $event6 = $this->create_calendar_event('Event 6', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 6]));
935         $event7 = $this->create_calendar_event('Event 7', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 7]));
936         $event8 = $this->create_calendar_event('Event 8', $user->id, 'user', 0, 1, array_merge($params, ['timesort' => 8]));
938         $result = core_calendar_external::get_calendar_action_events_by_timesort(2, 7, $event3->id, 2);
939         $result = external_api::clean_returnvalue(
940             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
941             $result
942         );
943         $events = $result['events'];
945         $this->assertCount(2, $events);
946         $this->assertEquals('Event 4', $events[0]['name']);
947         $this->assertEquals('Event 5', $events[1]['name']);
948         $this->assertEquals($event4->id, $result['firstid']);
949         $this->assertEquals($event5->id, $result['lastid']);
951         $result = core_calendar_external::get_calendar_action_events_by_timesort(2, 7, $event5->id, 2);
952         $result = external_api::clean_returnvalue(
953             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
954             $result
955         );
956         $events = $result['events'];
958         $this->assertCount(2, $events);
959         $this->assertEquals('Event 6', $events[0]['name']);
960         $this->assertEquals('Event 7', $events[1]['name']);
961         $this->assertEquals($event6->id, $result['firstid']);
962         $this->assertEquals($event7->id, $result['lastid']);
964         $result = core_calendar_external::get_calendar_action_events_by_timesort(2, 7, $event7->id, 2);
965         $result = external_api::clean_returnvalue(
966             core_calendar_external::get_calendar_action_events_by_timesort_returns(),
967             $result
968         );
970         $this->assertEmpty($result['events']);
971         $this->assertNull($result['firstid']);
972         $this->assertNull($result['lastid']);
973     }
975     /**
976      * Check that it is possible to restrict the calendar events to events where the user is not suspended in the course.
977      */
978     public function test_get_calendar_action_events_by_timesort_suspended_course() {
979         $this->resetAfterTest();
980         $user1 = $this->getDataGenerator()->create_user();
981         $user2 = $this->getDataGenerator()->create_user();
982         $course = $this->getDataGenerator()->create_course();
983         $this->setAdminUser();
984         $lesson = $this->getDataGenerator()->create_module('lesson', [
985                 'name' => 'Lesson 1',
986                 'course' => $course->id,
987                 'available' => time(),
988                 'deadline' => (time() + (60 * 60 * 24 * 5))
989             ]
990         );
991         $this->getDataGenerator()->enrol_user($user1->id, $course->id, null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
992         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
994         $this->setUser($user1);
995         $result = core_calendar_external::get_calendar_action_events_by_timesort(0, null, 0, 20, true);
996         $this->assertEmpty($result->events);
997         $this->setUser($user2);
998         $result = core_calendar_external::get_calendar_action_events_by_timesort(0, null, 0, 20, true);
999         $this->assertCount(1, $result->events);
1000         $this->assertEquals('Lesson 1 closes', $result->events[0]->name);
1001     }
1003     /**
1004      * Requesting calendar events from a given course and time should return all
1005      * events with a sort time at or after the requested time. All events prior
1006      * to that time should not be return.
1007      *
1008      * If there are no events on or after the given time then an empty result set should
1009      * be returned.
1010      */
1011     public function test_get_calendar_action_events_by_course_after_time() {
1012         $user = $this->getDataGenerator()->create_user();
1013         $course1 = $this->getDataGenerator()->create_course();
1014         $course2 = $this->getDataGenerator()->create_course();
1015         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1016         $instance1 = $generator->create_instance(['course' => $course1->id]);
1017         $instance2 = $generator->create_instance(['course' => $course2->id]);
1018         $records = [];
1020         $this->getDataGenerator()->enrol_user($user->id, $course1->id);
1021         $this->getDataGenerator()->enrol_user($user->id, $course2->id);
1022         $this->resetAfterTest(true);
1023         $this->setUser($user);
1025         for ($i = 1; $i < 19; $i++) {
1026             $courseid = ($i < 9) ? $course1->id : $course2->id;
1027             $instance = ($i < 9) ? $instance1->id : $instance2->id;
1028             $records[] = $this->create_calendar_event(
1029                 sprintf('Event %d', $i),
1030                 $user->id,
1031                 'user',
1032                 0,
1033                 1,
1034                 [
1035                     'type' => CALENDAR_EVENT_TYPE_ACTION,
1036                     'courseid' => $courseid,
1037                     'timesort' => $i,
1038                     'modulename' => 'assign',
1039                     'instance' => $instance,
1040                 ]
1041             );
1042         }
1044         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 5);
1045         $result = external_api::clean_returnvalue(
1046             core_calendar_external::get_calendar_action_events_by_course_returns(),
1047             $result
1048         );
1049         $result = $result['events'];
1051         $this->assertCount(4, $result);
1052         $this->assertEquals('Event 5', $result[0]['name']);
1053         $this->assertEquals('Event 6', $result[1]['name']);
1054         $this->assertEquals('Event 7', $result[2]['name']);
1055         $this->assertEquals('Event 8', $result[3]['name']);
1057         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 9);
1058         $result = external_api::clean_returnvalue(
1059             core_calendar_external::get_calendar_action_events_by_course_returns(),
1060             $result
1061         );
1062         $result = $result['events'];
1064         $this->assertEmpty($result);
1065     }
1067     /**
1068      * Requesting calendar events for a course and before a given time should return
1069      * all events with a sort time at or before the requested time (inclusive). All
1070      * events after that time should not be returned.
1071      *
1072      * If there are no events before the given time then an empty result set should be
1073      * returned.
1074      */
1075     public function test_get_calendar_action_events_by_course_before_time() {
1076         $user = $this->getDataGenerator()->create_user();
1077         $course1 = $this->getDataGenerator()->create_course();
1078         $course2 = $this->getDataGenerator()->create_course();
1079         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1080         $instance1 = $generator->create_instance(['course' => $course1->id]);
1081         $instance2 = $generator->create_instance(['course' => $course2->id]);
1082         $records = [];
1084         $this->getDataGenerator()->enrol_user($user->id, $course1->id);
1085         $this->getDataGenerator()->enrol_user($user->id, $course2->id);
1086         $this->resetAfterTest(true);
1087         $this->setUser($user);
1089         for ($i = 1; $i < 19; $i++) {
1090             $courseid = ($i < 9) ? $course1->id : $course2->id;
1091             $instance = ($i < 9) ? $instance1->id : $instance2->id;
1092             $records[] = $this->create_calendar_event(
1093                 sprintf('Event %d', $i),
1094                 $user->id,
1095                 'user',
1096                 0,
1097                 1,
1098                 [
1099                     'type' => CALENDAR_EVENT_TYPE_ACTION,
1100                     'courseid' => $courseid,
1101                     'timesort' => $i + 1,
1102                     'modulename' => 'assign',
1103                     'instance' => $instance,
1104                 ]
1105             );
1106         }
1108         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, null, 5);
1109         $result = external_api::clean_returnvalue(
1110             core_calendar_external::get_calendar_action_events_by_course_returns(),
1111             $result
1112         );
1113         $result = $result['events'];
1115         $this->assertCount(4, $result);
1116         $this->assertEquals('Event 1', $result[0]['name']);
1117         $this->assertEquals('Event 2', $result[1]['name']);
1118         $this->assertEquals('Event 3', $result[2]['name']);
1119         $this->assertEquals('Event 4', $result[3]['name']);
1121         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, null, 1);
1122         $result = external_api::clean_returnvalue(
1123             core_calendar_external::get_calendar_action_events_by_course_returns(),
1124             $result
1125         );
1126         $result = $result['events'];
1128         $this->assertEmpty($result);
1129     }
1131     /**
1132      * Requesting calendar events for a course and within a given time range should
1133      * return all events with a sort time between the lower and upper time bound
1134      * (inclusive).
1135      *
1136      * If there are no events in the given time range then an empty result set should be
1137      * returned.
1138      */
1139     public function test_get_calendar_action_events_by_course_time_range() {
1140         $user = $this->getDataGenerator()->create_user();
1141         $course1 = $this->getDataGenerator()->create_course();
1142         $course2 = $this->getDataGenerator()->create_course();
1143         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1144         $instance1 = $generator->create_instance(['course' => $course1->id]);
1145         $instance2 = $generator->create_instance(['course' => $course2->id]);
1146         $records = [];
1148         $this->getDataGenerator()->enrol_user($user->id, $course1->id);
1149         $this->getDataGenerator()->enrol_user($user->id, $course2->id);
1150         $this->resetAfterTest(true);
1151         $this->setUser($user);
1153         for ($i = 1; $i < 19; $i++) {
1154             $courseid = ($i < 9) ? $course1->id : $course2->id;
1155             $instance = ($i < 9) ? $instance1->id : $instance2->id;
1156             $records[] = $this->create_calendar_event(
1157                 sprintf('Event %d', $i),
1158                 $user->id,
1159                 'user',
1160                 0,
1161                 1,
1162                 [
1163                     'type' => CALENDAR_EVENT_TYPE_ACTION,
1164                     'courseid' => $courseid,
1165                     'timesort' => $i,
1166                     'modulename' => 'assign',
1167                     'instance' => $instance,
1168                 ]
1169             );
1170         }
1172         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 3, 6);
1173         $result = external_api::clean_returnvalue(
1174             core_calendar_external::get_calendar_action_events_by_course_returns(),
1175             $result
1176         );
1177         $result = $result['events'];
1179         $this->assertCount(4, $result);
1180         $this->assertEquals('Event 3', $result[0]['name']);
1181         $this->assertEquals('Event 4', $result[1]['name']);
1182         $this->assertEquals('Event 5', $result[2]['name']);
1183         $this->assertEquals('Event 6', $result[3]['name']);
1185         $result = core_calendar_external::get_calendar_action_events_by_course($course1->id, 10, 15);
1186         $result = external_api::clean_returnvalue(
1187             core_calendar_external::get_calendar_action_events_by_course_returns(),
1188             $result
1189         );
1190         $result = $result['events'];
1192         $this->assertEmpty($result);
1193     }
1195     /**
1196      * Requesting calendar events for a course and within a given time range and a limit
1197      * and offset should return the number of events up to the given limit value that have
1198      * a sort time between the lower and uppper time bound (inclusive) where the result
1199      * set is shifted by the offset value.
1200      *
1201      * If there are no events in the given time range then an empty result set should be
1202      * returned.
1203      */
1204     public function test_get_calendar_action_events_by_course_time_limit_offset() {
1205         $user = $this->getDataGenerator()->create_user();
1206         $course1 = $this->getDataGenerator()->create_course();
1207         $course2 = $this->getDataGenerator()->create_course();
1208         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1209         $instance1 = $generator->create_instance(['course' => $course1->id]);
1210         $instance2 = $generator->create_instance(['course' => $course2->id]);
1211         $records = [];
1213         $this->getDataGenerator()->enrol_user($user->id, $course1->id);
1214         $this->getDataGenerator()->enrol_user($user->id, $course2->id);
1215         $this->resetAfterTest(true);
1216         $this->setUser($user);
1218         for ($i = 1; $i < 19; $i++) {
1219             $courseid = ($i < 9) ? $course1->id : $course2->id;
1220             $instance = ($i < 9) ? $instance1->id : $instance2->id;
1221             $records[] = $this->create_calendar_event(
1222                 sprintf('Event %d', $i),
1223                 $user->id,
1224                 'user',
1225                 0,
1226                 1,
1227                 [
1228                     'type' => CALENDAR_EVENT_TYPE_ACTION,
1229                     'courseid' => $courseid,
1230                     'timesort' => $i,
1231                     'modulename' => 'assign',
1232                     'instance' => $instance,
1233                 ]
1234             );
1235         }
1237         $result = core_calendar_external::get_calendar_action_events_by_course(
1238             $course1->id, 2, 7, $records[2]->id, 2);
1239         $result = external_api::clean_returnvalue(
1240             core_calendar_external::get_calendar_action_events_by_course_returns(),
1241             $result
1242         );
1243         $result = $result['events'];
1245         $this->assertCount(2, $result);
1246         $this->assertEquals('Event 4', $result[0]['name']);
1247         $this->assertEquals('Event 5', $result[1]['name']);
1249         $result = core_calendar_external::get_calendar_action_events_by_course(
1250             $course1->id, 2, 7, $records[4]->id, 2);
1251         $result = external_api::clean_returnvalue(
1252             core_calendar_external::get_calendar_action_events_by_course_returns(),
1253             $result
1254         );
1255         $result = $result['events'];
1257         $this->assertCount(2, $result);
1258         $this->assertEquals('Event 6', $result[0]['name']);
1259         $this->assertEquals('Event 7', $result[1]['name']);
1261         $result = core_calendar_external::get_calendar_action_events_by_course(
1262             $course1->id, 2, 7, $records[6]->id, 2);
1263         $result = external_api::clean_returnvalue(
1264             core_calendar_external::get_calendar_action_events_by_course_returns(),
1265             $result
1266         );
1267         $result = $result['events'];
1269         $this->assertEmpty($result);
1270     }
1272     /**
1273      * Test that get_action_events_by_courses will return a list of events for each
1274      * course you provided as long as the user is enrolled in the course.
1275      */
1276     public function test_get_action_events_by_courses() {
1277         $user = $this->getDataGenerator()->create_user();
1278         $course1 = $this->getDataGenerator()->create_course();
1279         $course2 = $this->getDataGenerator()->create_course();
1280         $course3 = $this->getDataGenerator()->create_course();
1281         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1282         $instance1 = $generator->create_instance(['course' => $course1->id]);
1283         $instance2 = $generator->create_instance(['course' => $course2->id]);
1284         $instance3 = $generator->create_instance(['course' => $course3->id]);
1285         $records = [];
1286         $mapresult = function($result) {
1287             $groupedbycourse = [];
1288             foreach ($result['groupedbycourse'] as $group) {
1289                 $events = $group['events'];
1290                 $courseid = $group['courseid'];
1291                 $groupedbycourse[$courseid] = $events;
1292             }
1294             return $groupedbycourse;
1295         };
1297         $this->getDataGenerator()->enrol_user($user->id, $course1->id);
1298         $this->getDataGenerator()->enrol_user($user->id, $course2->id);
1299         $this->resetAfterTest(true);
1300         $this->setUser($user);
1302         for ($i = 1; $i < 10; $i++) {
1303             if ($i < 3) {
1304                 $courseid = $course1->id;
1305                 $instance = $instance1->id;
1306             } else if ($i < 6) {
1307                 $courseid = $course2->id;
1308                 $instance = $instance2->id;
1309             } else {
1310                 $courseid = $course3->id;
1311                 $instance = $instance3->id;
1312             }
1314             $records[] = $this->create_calendar_event(
1315                 sprintf('Event %d', $i),
1316                 $user->id,
1317                 'user',
1318                 0,
1319                 1,
1320                 [
1321                     'type' => CALENDAR_EVENT_TYPE_ACTION,
1322                     'courseid' => $courseid,
1323                     'timesort' => $i,
1324                     'modulename' => 'assign',
1325                     'instance' => $instance,
1326                 ]
1327             );
1328         }
1330         $result = core_calendar_external::get_calendar_action_events_by_courses([], 1);
1331         $result = external_api::clean_returnvalue(
1332             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1333             $result
1334         );
1335         $result = $result['groupedbycourse'];
1337         $this->assertEmpty($result);
1339         $result = core_calendar_external::get_calendar_action_events_by_courses([$course1->id], 3);
1340         $result = external_api::clean_returnvalue(
1341             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1342             $result
1343         );
1345         $groupedbycourse = $mapresult($result);
1347         $this->assertEmpty($groupedbycourse[$course1->id]);
1349         $result = core_calendar_external::get_calendar_action_events_by_courses([$course1->id], 1);
1350         $result = external_api::clean_returnvalue(
1351             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1352             $result
1353         );
1354         $groupedbycourse = $mapresult($result);
1356         $this->assertCount(2, $groupedbycourse[$course1->id]);
1357         $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']);
1358         $this->assertEquals('Event 2', $groupedbycourse[$course1->id][1]['name']);
1360         $result = core_calendar_external::get_calendar_action_events_by_courses(
1361             [$course1->id, $course2->id], 1);
1362         $result = external_api::clean_returnvalue(
1363             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1364             $result
1365         );
1366         $groupedbycourse = $mapresult($result);
1368         $this->assertCount(2, $groupedbycourse[$course1->id]);
1369         $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']);
1370         $this->assertEquals('Event 2', $groupedbycourse[$course1->id][1]['name']);
1371         $this->assertCount(3, $groupedbycourse[$course2->id]);
1372         $this->assertEquals('Event 3', $groupedbycourse[$course2->id][0]['name']);
1373         $this->assertEquals('Event 4', $groupedbycourse[$course2->id][1]['name']);
1374         $this->assertEquals('Event 5', $groupedbycourse[$course2->id][2]['name']);
1376         $result = core_calendar_external::get_calendar_action_events_by_courses(
1377             [$course1->id, $course2->id], 2, 4);
1378         $result = external_api::clean_returnvalue(
1379             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1380             $result
1381         );
1382         $groupedbycourse = $mapresult($result);
1384         $this->assertCount(2, $groupedbycourse);
1385         $this->assertCount(1, $groupedbycourse[$course1->id]);
1386         $this->assertEquals('Event 2', $groupedbycourse[$course1->id][0]['name']);
1387         $this->assertCount(2, $groupedbycourse[$course2->id]);
1388         $this->assertEquals('Event 3', $groupedbycourse[$course2->id][0]['name']);
1389         $this->assertEquals('Event 4', $groupedbycourse[$course2->id][1]['name']);
1391         $result = core_calendar_external::get_calendar_action_events_by_courses(
1392             [$course1->id, $course2->id], 1, null, 1);
1393         $result = external_api::clean_returnvalue(
1394             core_calendar_external::get_calendar_action_events_by_courses_returns(),
1395             $result
1396         );
1397         $groupedbycourse = $mapresult($result);
1399         $this->assertCount(2, $groupedbycourse);
1400         $this->assertCount(1, $groupedbycourse[$course1->id]);
1401         $this->assertEquals('Event 1', $groupedbycourse[$course1->id][0]['name']);
1402         $this->assertCount(1, $groupedbycourse[$course2->id]);
1403         $this->assertEquals('Event 3', $groupedbycourse[$course2->id][0]['name']);
1404     }
1406     /**
1407      * Test for deleting module events.
1408      */
1409     public function test_delete_calendar_events_for_modules() {
1410         $this->resetAfterTest();
1411         $this->setAdminUser();
1412         $course = $this->getDataGenerator()->create_course();
1413         $nexttime = time() + DAYSECS;
1414         $this->getDataGenerator()->create_module('assign', ['course' => $course->id, 'duedate' => $nexttime]);
1415         $events = calendar_get_events(time(), $nexttime, true, true, true);
1416         $this->assertCount(1, $events);
1417         $params = [];
1418         foreach ($events as $event) {
1419             $params[] = [
1420                 'eventid' => $event->id,
1421                 'repeat' => false
1422             ];
1423         }
1425         $this->expectException('moodle_exception');
1426         core_calendar_external::delete_calendar_events($params);
1427     }
1429     /**
1430      * Updating the event start day should change the date value but leave
1431      * the time of day unchanged.
1432      */
1433     public function test_update_event_start_day() {
1434         $generator = $this->getDataGenerator();
1435         $user = $generator->create_user();
1436         $roleid = $generator->create_role();
1437         $context = \context_system::instance();
1438         $originalstarttime = new DateTimeImmutable('2017-01-1T15:00:00+08:00');
1439         $newstartdate = new DateTimeImmutable('2018-02-2T10:00:00+08:00');
1440         $expected = new DateTimeImmutable('2018-02-2T15:00:00+08:00');
1442         $generator->role_assign($roleid, $user->id, $context->id);
1443         assign_capability('moodle/calendar:manageownentries', CAP_ALLOW, $roleid, $context, true);
1445         $this->setUser($user);
1446         $this->resetAfterTest(true);
1448         $event = $this->create_calendar_event(
1449             'Test event',
1450             $user->id,
1451             'user',
1452             0,
1453             null,
1454             [
1455                 'courseid' => 0,
1456                 'timestart' => $originalstarttime->getTimestamp()
1457             ]
1458         );
1460         $result = core_calendar_external::update_event_start_day($event->id, $newstartdate->getTimestamp());
1461         $result = external_api::clean_returnvalue(
1462             core_calendar_external::update_event_start_day_returns(),
1463             $result
1464         );
1466         $this->assertEquals($expected->getTimestamp(), $result['event']['timestart']);
1467     }
1469     /**
1470      * A user should not be able to edit an event that they don't have
1471      * capabilities for.
1472      */
1473     public function test_update_event_start_day_no_permission() {
1474         $generator = $this->getDataGenerator();
1475         $user = $generator->create_user();
1476         $roleid = $generator->create_role();
1477         $context = \context_system::instance();
1478         $originalstarttime = new DateTimeImmutable('2017-01-1T15:00:00+08:00');
1479         $newstartdate = new DateTimeImmutable('2018-02-2T10:00:00+08:00');
1480         $expected = new DateTimeImmutable('2018-02-2T15:00:00+08:00');
1482         $generator->role_assign($roleid, $user->id, $context->id);
1483         assign_capability('moodle/calendar:manageownentries', CAP_ALLOW, $roleid, $context, true);
1485         $this->setUser($user);
1486         $this->resetAfterTest(true);
1488         $event = $this->create_calendar_event(
1489             'Test event',
1490             $user->id,
1491             'user',
1492             0,
1493             null,
1494             [
1495                 'courseid' => 0,
1496                 'timestart' => $originalstarttime->getTimestamp()
1497             ]
1498         );
1500         assign_capability('moodle/calendar:manageownentries', CAP_PROHIBIT, $roleid, $context, true);
1501         $this->expectException('moodle_exception');
1502         $result = core_calendar_external::update_event_start_day($event->id, $newstartdate->getTimestamp());
1503         $result = external_api::clean_returnvalue(
1504             core_calendar_external::update_event_start_day_returns(),
1505             $result
1506         );
1507     }
1509     /**
1510      * A user should not be able to update a module event.
1511      */
1512     public function test_update_event_start_day_module_event() {
1513         $generator = $this->getDataGenerator();
1514         $user = $generator->create_user();
1515         $course = $generator->create_course();
1516         $plugingenerator = $generator->get_plugin_generator('mod_assign');
1517         $moduleinstance = $plugingenerator->create_instance(['course' => $course->id]);
1518         $roleid = $generator->create_role();
1519         $context = \context_course::instance($course->id);
1520         $originalstarttime = new DateTimeImmutable('2017-01-1T15:00:00+08:00');
1521         $newstartdate = new DateTimeImmutable('2018-02-2T10:00:00+08:00');
1522         $expected = new DateTimeImmutable('2018-02-2T15:00:00+08:00');
1524         $generator->role_assign($roleid, $user->id, $context->id);
1525         $generator->enrol_user($user->id, $course->id);
1527         $this->setUser($user);
1528         $this->resetAfterTest(true);
1530         $event = $this->create_calendar_event(
1531             'Test event',
1532             $user->id,
1533             'user',
1534             0,
1535             null,
1536             [
1537                 'modulename' => 'assign',
1538                 'instance' => $moduleinstance->id,
1539                 'courseid' => $course->id,
1540                 'timestart' => $originalstarttime->getTimestamp()
1541             ]
1542         );
1544         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
1545         $this->expectException('moodle_exception');
1546         $result = core_calendar_external::update_event_start_day($event->id, $newstartdate->getTimestamp());
1547         $result = external_api::clean_returnvalue(
1548             core_calendar_external::update_event_start_day_returns(),
1549             $result
1550         );
1551     }
1553     /**
1554      * Submit a request where the time duration until is earlier than the time
1555      * start in order to get a validation error from the server.
1556      */
1557     public function test_submit_create_update_form_validation_error() {
1558         $user = $this->getDataGenerator()->create_user();
1559         $timestart = new DateTime();
1560         $interval = new DateInterval("P1D"); // One day.
1561         $timedurationuntil = new DateTime();
1562         $timedurationuntil->sub($interval);
1563         $formdata = [
1564             'id' => 0,
1565             'userid' => $user->id,
1566             'modulename' => '',
1567             'instance' => 0,
1568             'visible' => 1,
1569             'name' => 'Test',
1570             'timestart' => [
1571                 'day' => $timestart->format('j'),
1572                 'month' => $timestart->format('n'),
1573                 'year' => $timestart->format('Y'),
1574                 'hour' => $timestart->format('G'),
1575                 'minute' => 0,
1576             ],
1577             'eventtype' => 'user',
1578             'description' => [
1579                 'text' => '',
1580                 'format' => 1,
1581             ],
1582             'location' => 'Test',
1583             'duration' => 1,
1584             'timedurationuntil' => [
1585                 'day' => $timedurationuntil->format('j'),
1586                 'month' => $timedurationuntil->format('n'),
1587                 'year' => $timedurationuntil->format('Y'),
1588                 'hour' => $timedurationuntil->format('G'),
1589                 'minute' => 0,
1590             ]
1591         ];
1593         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1595         $querystring = http_build_query($formdata, '', '&amp;');
1597         $this->resetAfterTest(true);
1598         $this->setUser($user);
1600         $result = external_api::clean_returnvalue(
1601             core_calendar_external::submit_create_update_form_returns(),
1602             core_calendar_external::submit_create_update_form($querystring)
1603         );
1605         $this->assertTrue($result['validationerror']);
1606     }
1608     /**
1609      * A user with the moodle/calendar:manageownentries capability at the
1610      * system context should be able to create a user event.
1611      */
1612     public function test_submit_create_update_form_create_user_event() {
1613         $generator = $this->getDataGenerator();
1614         $user = $generator->create_user();
1615         $roleid = $generator->create_role();
1616         $context = \context_system::instance();
1617         $timestart = new DateTime();
1618         $interval = new DateInterval("P1D"); // One day.
1619         $timedurationuntil = new DateTime();
1620         $timedurationuntil->add($interval);
1621         $formdata = [
1622             'id' => 0,
1623             'userid' => $user->id,
1624             'modulename' => '',
1625             'instance' => 0,
1626             'visible' => 1,
1627             'name' => 'Test',
1628             'timestart' => [
1629                 'day' => $timestart->format('j'),
1630                 'month' => $timestart->format('n'),
1631                 'year' => $timestart->format('Y'),
1632                 'hour' => $timestart->format('G'),
1633                 'minute' => 0,
1634             ],
1635             'eventtype' => 'user',
1636             'description' => [
1637                 'text' => '',
1638                 'format' => 1,
1639                 'itemid' => 0
1640             ],
1641             'location' => 'Test',
1642             'duration' => 1,
1643             'timedurationuntil' => [
1644                 'day' => $timedurationuntil->format('j'),
1645                 'month' => $timedurationuntil->format('n'),
1646                 'year' => $timedurationuntil->format('Y'),
1647                 'hour' => $timedurationuntil->format('G'),
1648                 'minute' => 0,
1649             ]
1650         ];
1652         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1653         $querystring = http_build_query($formdata, '', '&');
1655         $generator->role_assign($roleid, $user->id, $context->id);
1656         assign_capability('moodle/calendar:manageownentries', CAP_ALLOW, $roleid, $context, true);
1658         $user->ignoresesskey = true;
1659         $this->resetAfterTest(true);
1660         $this->setUser($user);
1662         $result = external_api::clean_returnvalue(
1663             core_calendar_external::submit_create_update_form_returns(),
1664             core_calendar_external::submit_create_update_form($querystring)
1665         );
1667         $event = $result['event'];
1668         $this->assertEquals($user->id, $event['userid']);
1669         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
1670         $this->assertEquals($formdata['name'], $event['name']);
1671     }
1673     /**
1674      * A user without the moodle/calendar:manageownentries capability at the
1675      * system context should not be able to create a user event.
1676      */
1677     public function test_submit_create_update_form_create_user_event_no_permission() {
1678         $generator = $this->getDataGenerator();
1679         $user = $generator->create_user();
1680         $roleid = $generator->create_role();
1681         $context = \context_system::instance();
1682         $timestart = new DateTime();
1683         $interval = new DateInterval("P1D"); // One day.
1684         $timedurationuntil = new DateTime();
1685         $timedurationuntil->add($interval);
1686         $formdata = [
1687             'id' => 0,
1688             'userid' => $user->id,
1689             'modulename' => '',
1690             'instance' => 0,
1691             'visible' => 1,
1692             'name' => 'Test',
1693             'timestart' => [
1694                 'day' => $timestart->format('j'),
1695                 'month' => $timestart->format('n'),
1696                 'year' => $timestart->format('Y'),
1697                 'hour' => $timestart->format('G'),
1698                 'minute' => 0,
1699             ],
1700             'eventtype' => 'user',
1701             'description' => [
1702                 'text' => '',
1703                 'format' => 1,
1704             ],
1705             'location' => 'Test',
1706             'duration' => 1,
1707             'timedurationuntil' => [
1708                 'day' => $timedurationuntil->format('j'),
1709                 'month' => $timedurationuntil->format('n'),
1710                 'year' => $timedurationuntil->format('Y'),
1711                 'hour' => $timedurationuntil->format('G'),
1712                 'minute' => 0,
1713             ]
1714         ];
1716         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1717         $querystring = http_build_query($formdata, '', '&');
1719         $generator->role_assign($roleid, $user->id, $context->id);
1720         assign_capability('moodle/calendar:manageownentries', CAP_PROHIBIT, $roleid, $context, true);
1722         $user->ignoresesskey = true;
1723         $this->resetAfterTest(true);
1724         $this->setUser($user);
1726         $this->expectException('moodle_exception');
1728         external_api::clean_returnvalue(
1729             core_calendar_external::submit_create_update_form_returns(),
1730             core_calendar_external::submit_create_update_form($querystring)
1731         );
1732     }
1734     /**
1735      * A user with the moodle/calendar:manageentries capability at the
1736      * site course context should be able to create a site event.
1737      */
1738     public function test_submit_create_update_form_create_site_event() {
1739         $generator = $this->getDataGenerator();
1740         $user = $generator->create_user();
1741         $context = context_system::instance();
1742         $roleid = $generator->create_role();
1743         $timestart = new DateTime();
1744         $interval = new DateInterval("P1D"); // One day.
1745         $timedurationuntil = new DateTime();
1746         $timedurationuntil->add($interval);
1747         $formdata = [
1748             'id' => 0,
1749             'userid' => $user->id,
1750             'modulename' => '',
1751             'instance' => 0,
1752             'visible' => 1,
1753             'name' => 'Test',
1754             'timestart' => [
1755                 'day' => $timestart->format('j'),
1756                 'month' => $timestart->format('n'),
1757                 'year' => $timestart->format('Y'),
1758                 'hour' => $timestart->format('G'),
1759                 'minute' => 0,
1760             ],
1761             'eventtype' => 'site',
1762             'description' => [
1763                 'text' => '',
1764                 'format' => 1,
1765                 'itemid' => 0
1766             ],
1767             'location' => 'Test',
1768             'duration' => 1,
1769             'timedurationuntil' => [
1770                 'day' => $timedurationuntil->format('j'),
1771                 'month' => $timedurationuntil->format('n'),
1772                 'year' => $timedurationuntil->format('Y'),
1773                 'hour' => $timedurationuntil->format('G'),
1774                 'minute' => 0,
1775             ]
1776         ];
1778         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1779         $querystring = http_build_query($formdata, '', '&');
1781         $generator->role_assign($roleid, $user->id, $context->id);
1783         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
1785         $user->ignoresesskey = true;
1786         $this->resetAfterTest(true);
1787         $this->setUser($user);
1789         $result = external_api::clean_returnvalue(
1790             core_calendar_external::submit_create_update_form_returns(),
1791             core_calendar_external::submit_create_update_form($querystring)
1792         );
1794         $event = $result['event'];
1795         $this->assertEquals($user->id, $event['userid']);
1796         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
1797         $this->assertEquals($formdata['name'], $event['name']);
1798     }
1800     /**
1801      * A user without the moodle/calendar:manageentries capability at the
1802      * site course context should not be able to create a site event.
1803      */
1804     public function test_submit_create_update_form_create_site_event_no_permission() {
1805         $generator = $this->getDataGenerator();
1806         $user = $generator->create_user();
1807         $context = context_course::instance(SITEID);
1808         $roleid = $generator->create_role();
1809         $timestart = new DateTime();
1810         $interval = new DateInterval("P1D"); // One day.
1811         $timedurationuntil = new DateTime();
1812         $timedurationuntil->add($interval);
1813         $formdata = [
1814             'id' => 0,
1815             'userid' => $user->id,
1816             'modulename' => '',
1817             'instance' => 0,
1818             'visible' => 1,
1819             'name' => 'Test',
1820             'timestart' => [
1821                 'day' => $timestart->format('j'),
1822                 'month' => $timestart->format('n'),
1823                 'year' => $timestart->format('Y'),
1824                 'hour' => $timestart->format('G'),
1825                 'minute' => 0,
1826             ],
1827             'eventtype' => 'site',
1828             'description' => [
1829                 'text' => '',
1830                 'format' => 1,
1831             ],
1832             'location' => 'Test',
1833             'duration' => 1,
1834             'timedurationuntil' => [
1835                 'day' => $timedurationuntil->format('j'),
1836                 'month' => $timedurationuntil->format('n'),
1837                 'year' => $timedurationuntil->format('Y'),
1838                 'hour' => $timedurationuntil->format('G'),
1839                 'minute' => 0,
1840             ]
1841         ];
1843         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1844         $querystring = http_build_query($formdata, '', '&');
1846         $generator->role_assign($roleid, $user->id, $context->id);
1848         assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
1850         $user->ignoresesskey = true;
1851         $this->resetAfterTest(true);
1852         $this->setUser($user);
1854         $result = external_api::clean_returnvalue(
1855             core_calendar_external::submit_create_update_form_returns(),
1856             core_calendar_external::submit_create_update_form($querystring)
1857         );
1859         $this->assertTrue($result['validationerror']);
1860     }
1862     /**
1863      * A user that has the moodle/calendar:manageentries in a course that they
1864      * are enrolled in should be able to create a course event in that course.
1865      */
1866     public function test_submit_create_update_form_create_course_event() {
1867         $generator = $this->getDataGenerator();
1868         $user = $generator->create_user();
1869         $course = $generator->create_course();
1870         $context = context_course::instance($course->id);
1871         $roleid = $generator->create_role();
1872         $timestart = new DateTime();
1873         $interval = new DateInterval("P1D"); // One day.
1874         $timedurationuntil = new DateTime();
1875         $timedurationuntil->add($interval);
1876         $formdata = [
1877             'id' => 0,
1878             'userid' => $user->id,
1879             'modulename' => '',
1880             'instance' => 0,
1881             'visible' => 1,
1882             'name' => 'Test',
1883             'timestart' => [
1884                 'day' => $timestart->format('j'),
1885                 'month' => $timestart->format('n'),
1886                 'year' => $timestart->format('Y'),
1887                 'hour' => $timestart->format('G'),
1888                 'minute' => 0,
1889             ],
1890             'eventtype' => 'course',
1891             'courseid' => $course->id,
1892             'description' => [
1893                 'text' => '',
1894                 'format' => 1,
1895                 'itemid' => 0,
1896             ],
1897             'location' => 'Test',
1898             'duration' => 1,
1899             'timedurationuntil' => [
1900                 'day' => $timedurationuntil->format('j'),
1901                 'month' => $timedurationuntil->format('n'),
1902                 'year' => $timedurationuntil->format('Y'),
1903                 'hour' => $timedurationuntil->format('G'),
1904                 'minute' => 0,
1905             ]
1906         ];
1908         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1909         $querystring = http_build_query($formdata, '', '&');
1911         $generator->enrol_user($user->id, $course->id, 'student');
1912         $generator->role_assign($roleid, $user->id, $context->id);
1914         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
1916         $user->ignoresesskey = true;
1917         $this->resetAfterTest(true);
1918         $this->setUser($user);
1920         $result = external_api::clean_returnvalue(
1921             core_calendar_external::submit_create_update_form_returns(),
1922             core_calendar_external::submit_create_update_form($querystring)
1923         );
1925         $event = $result['event'];
1926         $this->assertEquals($user->id, $event['userid']);
1927         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
1928         $this->assertEquals($formdata['name'], $event['name']);
1929         $this->assertEquals($formdata['courseid'], $event['course']['id']);
1930     }
1932     /**
1933      * A user without the moodle/calendar:manageentries capability in a course
1934      * that they are enrolled in should not be able to create a course event in that course.
1935      */
1936     public function test_submit_create_update_form_create_course_event_no_permission() {
1937         $generator = $this->getDataGenerator();
1938         $user = $generator->create_user();
1939         $course = $generator->create_course();
1940         $context = context_course::instance($course->id);
1941         $roleid = $generator->create_role();
1942         $timestart = new DateTime();
1943         $interval = new DateInterval("P1D"); // One day.
1944         $timedurationuntil = new DateTime();
1945         $timedurationuntil->add($interval);
1946         $formdata = [
1947             'id' => 0,
1948             'userid' => $user->id,
1949             'modulename' => '',
1950             'instance' => 0,
1951             'visible' => 1,
1952             'name' => 'Test',
1953             'timestart' => [
1954                 'day' => $timestart->format('j'),
1955                 'month' => $timestart->format('n'),
1956                 'year' => $timestart->format('Y'),
1957                 'hour' => $timestart->format('G'),
1958                 'minute' => 0,
1959             ],
1960             'eventtype' => 'course',
1961             'courseid' => $course->id,
1962             'description' => [
1963                 'text' => '',
1964                 'format' => 1,
1965             ],
1966             'location' => 'Test',
1967             'duration' => 1,
1968             'timedurationuntil' => [
1969                 'day' => $timedurationuntil->format('j'),
1970                 'month' => $timedurationuntil->format('n'),
1971                 'year' => $timedurationuntil->format('Y'),
1972                 'hour' => $timedurationuntil->format('G'),
1973                 'minute' => 0,
1974             ]
1975         ];
1977         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
1978         $querystring = http_build_query($formdata, '', '&');
1980         $generator->enrol_user($user->id, $course->id, 'student');
1981         $generator->role_assign($roleid, $user->id, $context->id);
1983         assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
1985         $user->ignoresesskey = true;
1986         $this->resetAfterTest(true);
1987         $this->setUser($user);
1989         $result = external_api::clean_returnvalue(
1990             core_calendar_external::submit_create_update_form_returns(),
1991             core_calendar_external::submit_create_update_form($querystring)
1992         );
1994         $this->assertTrue($result['validationerror']);
1995     }
1997     /**
1998      * A user should not be able to create an event for a course that they are
1999      * not enrolled in.
2000      */
2001     public function test_submit_create_update_form_create_course_event_not_enrolled() {
2002         $generator = $this->getDataGenerator();
2003         $user = $generator->create_user();
2004         $course = $generator->create_course();
2005         $course2 = $generator->create_course();
2006         $context = context_course::instance($course->id);
2007         $roleid = $generator->create_role();
2008         $timestart = new DateTime();
2009         $interval = new DateInterval("P1D"); // One day.
2010         $timedurationuntil = new DateTime();
2011         $timedurationuntil->add($interval);
2012         $formdata = [
2013             'id' => 0,
2014             'userid' => $user->id,
2015             'modulename' => '',
2016             'instance' => 0,
2017             'visible' => 1,
2018             'name' => 'Test',
2019             'timestart' => [
2020                 'day' => $timestart->format('j'),
2021                 'month' => $timestart->format('n'),
2022                 'year' => $timestart->format('Y'),
2023                 'hour' => $timestart->format('G'),
2024                 'minute' => 0,
2025             ],
2026             'eventtype' => 'course',
2027             'courseid' => $course2->id, // Not enrolled.
2028             'description' => [
2029                 'text' => '',
2030                 'format' => 1,
2031             ],
2032             'location' => 'Test',
2033             'duration' => 1,
2034             'timedurationuntil' => [
2035                 'day' => $timedurationuntil->format('j'),
2036                 'month' => $timedurationuntil->format('n'),
2037                 'year' => $timedurationuntil->format('Y'),
2038                 'hour' => $timedurationuntil->format('G'),
2039                 'minute' => 0,
2040             ]
2041         ];
2043         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
2044         $querystring = http_build_query($formdata, '', '&');
2046         $generator->enrol_user($user->id, $course->id, 'student');
2047         $generator->role_assign($roleid, $user->id, $context->id);
2049         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
2051         $user->ignoresesskey = true;
2052         $this->resetAfterTest(true);
2053         $this->setUser($user);
2055         $result = external_api::clean_returnvalue(
2056             core_calendar_external::submit_create_update_form_returns(),
2057             core_calendar_external::submit_create_update_form($querystring)
2058         );
2060         $this->assertTrue($result['validationerror']);
2061     }
2063     /**
2064      * A user should be able to create an event for a group that they are a member of in
2065      * a course in which they are enrolled and have the moodle/calendar:manageentries capability.
2066      */
2067     public function test_submit_create_update_form_create_group_event_group_member_manage_course() {
2068         $generator = $this->getDataGenerator();
2069         $user = $generator->create_user();
2070         $course = $generator->create_course();
2071         $group = $generator->create_group(array('courseid' => $course->id));
2072         $context = context_course::instance($course->id);
2073         $roleid = $generator->create_role();
2074         $timestart = new DateTime();
2075         $interval = new DateInterval("P1D"); // One day.
2076         $timedurationuntil = new DateTime();
2077         $timedurationuntil->add($interval);
2078         $formdata = [
2079             'id' => 0,
2080             'userid' => $user->id,
2081             'modulename' => '',
2082             'instance' => 0,
2083             'visible' => 1,
2084             'name' => 'Test',
2085             'timestart' => [
2086                 'day' => $timestart->format('j'),
2087                 'month' => $timestart->format('n'),
2088                 'year' => $timestart->format('Y'),
2089                 'hour' => $timestart->format('G'),
2090                 'minute' => 0,
2091             ],
2092             'eventtype' => 'group',
2093             'groupid' => $group->id,
2094             'groupcourseid' => $course->id,
2095             'description' => [
2096                 'text' => '',
2097                 'format' => 1,
2098                 'itemid' => 0
2099             ],
2100             'location' => 'Test',
2101             'duration' => 1,
2102             'timedurationuntil' => [
2103                 'day' => $timedurationuntil->format('j'),
2104                 'month' => $timedurationuntil->format('n'),
2105                 'year' => $timedurationuntil->format('Y'),
2106                 'hour' => $timedurationuntil->format('G'),
2107                 'minute' => 0,
2108             ]
2109         ];
2111         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
2112         $querystring = http_build_query($formdata, '', '&');
2114         $generator->enrol_user($user->id, $course->id, 'student');
2115         $generator->role_assign($roleid, $user->id, $context->id);
2116         $generator->create_group_member(['groupid' => $group->id, 'userid' => $user->id]);
2118         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
2120         $user->ignoresesskey = true;
2121         $this->resetAfterTest(true);
2122         $this->setUser($user);
2124         $result = external_api::clean_returnvalue(
2125             core_calendar_external::submit_create_update_form_returns(),
2126             core_calendar_external::submit_create_update_form($querystring)
2127         );
2129         $event = $result['event'];
2130         $this->assertEquals($user->id, $event['userid']);
2131         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
2132         $this->assertEquals($formdata['name'], $event['name']);
2133         $this->assertEquals($group->id, $event['groupid']);
2134     }
2136     /**
2137      * A user should be able to create an event for a group that they are a member of in
2138      * a course in which they are enrolled and have the moodle/calendar:managegroupentries capability.
2139      */
2140     public function test_submit_create_update_form_create_group_event_group_member_manage_group_entries() {
2141         $generator = $this->getDataGenerator();
2142         $user = $generator->create_user();
2143         $course = $generator->create_course();
2144         $group = $generator->create_group(array('courseid' => $course->id));
2145         $context = context_course::instance($course->id);
2146         $roleid = $generator->create_role();
2147         $timestart = new DateTime();
2148         $interval = new DateInterval("P1D"); // One day.
2149         $timedurationuntil = new DateTime();
2150         $timedurationuntil->add($interval);
2151         $formdata = [
2152             'id' => 0,
2153             'userid' => $user->id,
2154             'modulename' => '',
2155             'instance' => 0,
2156             'visible' => 1,
2157             'name' => 'Test',
2158             'timestart' => [
2159                 'day' => $timestart->format('j'),
2160                 'month' => $timestart->format('n'),
2161                 'year' => $timestart->format('Y'),
2162                 'hour' => $timestart->format('G'),
2163                 'minute' => 0,
2164             ],
2165             'eventtype' => 'group',
2166             'groupid' => $group->id,
2167             'groupcourseid' => $course->id,
2168             'description' => [
2169                 'text' => '',
2170                 'format' => 1,
2171                 'itemid' => 0
2172             ],
2173             'location' => 'Test',
2174             'duration' => 1,
2175             'timedurationuntil' => [
2176                 'day' => $timedurationuntil->format('j'),
2177                 'month' => $timedurationuntil->format('n'),
2178                 'year' => $timedurationuntil->format('Y'),
2179                 'hour' => $timedurationuntil->format('G'),
2180                 'minute' => 0,
2181             ]
2182         ];
2184         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
2185         $querystring = http_build_query($formdata, '', '&');
2187         $generator->enrol_user($user->id, $course->id, 'student');
2188         $generator->role_assign($roleid, $user->id, $context->id);
2189         $generator->create_group_member(['groupid' => $group->id, 'userid' => $user->id]);
2191         assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
2192         assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true);
2194         $user->ignoresesskey = true;
2195         $this->resetAfterTest(true);
2196         $this->setUser($user);
2198         $result = external_api::clean_returnvalue(
2199             core_calendar_external::submit_create_update_form_returns(),
2200             core_calendar_external::submit_create_update_form($querystring)
2201         );
2203         $event = $result['event'];
2204         $this->assertEquals($user->id, $event['userid']);
2205         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
2206         $this->assertEquals($formdata['name'], $event['name']);
2207         $this->assertEquals($group->id, $event['groupid']);
2208     }
2210     /**
2211      * A user should be able to create an event for any group in a course in which
2212      * they are enrolled and have the moodle/site:accessallgroups capability.
2213      */
2214     public function test_submit_create_update_form_create_group_event_access_all_groups() {
2215         $generator = $this->getDataGenerator();
2216         $user = $generator->create_user();
2217         $course = $generator->create_course();
2218         $group = $generator->create_group(array('courseid' => $course->id));
2219         $context = context_course::instance($course->id);
2220         $roleid = $generator->create_role();
2221         $timestart = new DateTime();
2222         $interval = new DateInterval("P1D"); // One day.
2223         $timedurationuntil = new DateTime();
2224         $timedurationuntil->add($interval);
2225         $formdata = [
2226             'id' => 0,
2227             'userid' => $user->id,
2228             'modulename' => '',
2229             'instance' => 0,
2230             'visible' => 1,
2231             'name' => 'Test',
2232             'timestart' => [
2233                 'day' => $timestart->format('j'),
2234                 'month' => $timestart->format('n'),
2235                 'year' => $timestart->format('Y'),
2236                 'hour' => $timestart->format('G'),
2237                 'minute' => 0,
2238             ],
2239             'eventtype' => 'group',
2240             'groupid' => $group->id,
2241             'groupcourseid' => $course->id,
2242             'description' => [
2243                 'text' => '',
2244                 'format' => 1,
2245                 'itemid' => 0
2246             ],
2247             'location' => 'Test',
2248             'duration' => 1,
2249             'timedurationuntil' => [
2250                 'day' => $timedurationuntil->format('j'),
2251                 'month' => $timedurationuntil->format('n'),
2252                 'year' => $timedurationuntil->format('Y'),
2253                 'hour' => $timedurationuntil->format('G'),
2254                 'minute' => 0,
2255             ]
2256         ];
2258         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
2259         $querystring = http_build_query($formdata, '', '&');
2261         $generator->enrol_user($user->id, $course->id, 'student');
2262         $generator->role_assign($roleid, $user->id, $context->id);
2264         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
2265         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context, true);
2267         $user->ignoresesskey = true;
2268         $this->resetAfterTest(true);
2269         $this->setUser($user);
2271         $result = external_api::clean_returnvalue(
2272             core_calendar_external::submit_create_update_form_returns(),
2273             core_calendar_external::submit_create_update_form($querystring)
2274         );
2276         $event = $result['event'];
2277         $this->assertEquals($user->id, $event['userid']);
2278         $this->assertEquals($formdata['eventtype'], $event['eventtype']);
2279         $this->assertEquals($formdata['name'], $event['name']);
2280         $this->assertEquals($group->id, $event['groupid']);
2281     }
2283     /**
2284      * A user should not be able to create an event for any group that they are not a
2285      * member of in a course in which they are enrolled but don't have the
2286      * moodle/site:accessallgroups capability.
2287      */
2288     public function test_submit_create_update_form_create_group_event_non_member_no_permission() {
2289         $generator = $this->getDataGenerator();
2290         $user = $generator->create_user();
2291         $course = $generator->create_course();
2292         $group = $generator->create_group(array('courseid' => $course->id));
2293         $context = context_course::instance($course->id);
2294         $roleid = $generator->create_role();
2295         $timestart = new DateTime();
2296         $interval = new DateInterval("P1D"); // One day.
2297         $timedurationuntil = new DateTime();
2298         $timedurationuntil->add($interval);
2299         $formdata = [
2300             'id' => 0,
2301             'userid' => $user->id,
2302             'modulename' => '',
2303             'instance' => 0,
2304             'visible' => 1,
2305             'name' => 'Test',
2306             'timestart' => [
2307                 'day' => $timestart->format('j'),
2308                 'month' => $timestart->format('n'),
2309                 'year' => $timestart->format('Y'),
2310                 'hour' => $timestart->format('G'),
2311                 'minute' => 0,
2312             ],
2313             'eventtype' => 'group',
2314             'groupid' => $group->id,
2315             'groupcourseid' => $course->id,
2316             'description' => [
2317                 'text' => '',
2318                 'format' => 1,
2319             ],
2320             'location' => 'Test',
2321             'duration' => 1,
2322             'timedurationuntil' => [
2323                 'day' => $timedurationuntil->format('j'),
2324                 'month' => $timedurationuntil->format('n'),
2325                 'year' => $timedurationuntil->format('Y'),
2326                 'hour' => $timedurationuntil->format('G'),
2327                 'minute' => 0,
2328             ]
2329         ];
2331         $formdata = \core_calendar\local\event\forms\create::mock_generate_submit_keys($formdata);
2332         $querystring = http_build_query($formdata, '', '&');
2334         $generator->enrol_user($user->id, $course->id, 'student');
2335         $generator->role_assign($roleid, $user->id, $context->id);
2337         assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true);
2338         assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $roleid, $context, true);
2340         $user->ignoresesskey = true;
2341         $this->resetAfterTest(true);
2342         $this->setUser($user);
2344         $result = external_api::clean_returnvalue(
2345             core_calendar_external::submit_create_update_form_returns(),
2346             core_calendar_external::submit_create_update_form($querystring)
2347         );
2349         $this->assertTrue($result['validationerror']);
2350     }
2352     /**
2353      * A user should not be able load the calendar monthly view for a course they cannot access.
2354      */
2355     public function test_get_calendar_monthly_view_no_course_permission() {
2356         global $USER;
2357         $this->resetAfterTest(true);
2358         $this->setAdminUser();
2360         $generator = $this->getDataGenerator();
2361         $user1 = $generator->create_user();
2362         $user2 = $generator->create_user();
2363         $course = $generator->create_course();
2364         $generator->enrol_user($user1->id, $course->id, 'student');
2365         $name = 'Course Event (course' . $course->id . ')';
2366         $record = new stdClass();
2367         $record->courseid = $course->id;
2368         $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record);
2370         $timestart = new DateTime();
2371         // Admin can load the course.
2372         $data = external_api::clean_returnvalue(
2373             core_calendar_external::get_calendar_monthly_view_returns(),
2374             core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
2375                                                               $course->id, null, false, true)
2376         );
2377         $this->assertEquals($data['courseid'], $course->id);
2378         // User enrolled in the course can load the course calendar.
2379         $this->setUser($user1);
2380         $data = external_api::clean_returnvalue(
2381             core_calendar_external::get_calendar_monthly_view_returns(),
2382             core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
2383                                                               $course->id, null, false, true)
2384         );
2385         $this->assertEquals($data['courseid'], $course->id);
2386         // User not enrolled in the course cannot load the course calendar.
2387         $this->setUser($user2);
2388         $this->expectException('require_login_exception');
2389         $data = external_api::clean_returnvalue(
2390             core_calendar_external::get_calendar_monthly_view_returns(),
2391             core_calendar_external::get_calendar_monthly_view($timestart->format('Y'), $timestart->format('n'),
2392                                                               $course->id, null, false, false)
2393         );
2394     }
2396     /**
2397      * A user should not be able load the calendar day view for a course they cannot access.
2398      */
2399     public function test_get_calendar_day_view_no_course_permission() {
2400         global $USER;
2401         $this->resetAfterTest(true);
2402         $this->setAdminUser();
2404         $generator = $this->getDataGenerator();
2405         $user1 = $generator->create_user();
2406         $user2 = $generator->create_user();
2407         $course = $generator->create_course();
2408         $generator->enrol_user($user1->id, $course->id, 'student');
2409         $name = 'Course Event (course' . $course->id . ')';
2410         $record = new stdClass();
2411         $record->courseid = $course->id;
2412         $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record);
2414         $timestart = new DateTime();
2415         // Admin can load the course.
2416         $data = external_api::clean_returnvalue(
2417             core_calendar_external::get_calendar_day_view_returns(),
2418             core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'),
2419                                                           $timestart->format('j'), $course->id, null)
2420         );
2421         $this->assertEquals($data['courseid'], $course->id);
2422         // User enrolled in the course can load the course calendar.
2423         $this->setUser($user1);
2424         $data = external_api::clean_returnvalue(
2425             core_calendar_external::get_calendar_day_view_returns(),
2426             core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'),
2427                                                           $timestart->format('j'), $course->id, null)
2428         );
2429         $this->assertEquals($data['courseid'], $course->id);
2430         // User not enrolled in the course cannot load the course calendar.
2431         $this->setUser($user2);
2432         $this->expectException('require_login_exception');
2433         $data = external_api::clean_returnvalue(
2434             core_calendar_external::get_calendar_day_view_returns(),
2435             core_calendar_external::get_calendar_day_view($timestart->format('Y'), $timestart->format('n'),
2436                                                           $timestart->format('j'), $course->id, null)
2437         );
2438     }
2440     /**
2441      * A user should not be able load the calendar upcoming view for a course they cannot access.
2442      */
2443     public function test_get_calendar_upcoming_view_no_course_permission() {
2444         global $USER;
2445         $this->resetAfterTest(true);
2446         $this->setAdminUser();
2448         $generator = $this->getDataGenerator();
2449         $user1 = $generator->create_user();
2450         $user2 = $generator->create_user();
2451         $course = $generator->create_course();
2452         $generator->enrol_user($user1->id, $course->id, 'student');
2453         $name = 'Course Event (course' . $course->id . ')';
2454         $record = new stdClass();
2455         $record->courseid = $course->id;
2456         $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record);
2458         // Admin can load the course.
2459         $data = external_api::clean_returnvalue(
2460             core_calendar_external::get_calendar_upcoming_view_returns(),
2461             core_calendar_external::get_calendar_upcoming_view($course->id, null)
2462         );
2463         $this->assertEquals($data['courseid'], $course->id);
2464         // User enrolled in the course can load the course calendar.
2465         $this->setUser($user1);
2466         $data = external_api::clean_returnvalue(
2467             core_calendar_external::get_calendar_upcoming_view_returns(),
2468             core_calendar_external::get_calendar_upcoming_view($course->id, null)
2469         );
2470         $this->assertEquals($data['courseid'], $course->id);
2471         // User not enrolled in the course cannot load the course calendar.
2472         $this->setUser($user2);
2473         $this->expectException('require_login_exception');
2474         $data = external_api::clean_returnvalue(
2475             core_calendar_external::get_calendar_upcoming_view_returns(),
2476             core_calendar_external::get_calendar_upcoming_view($course->id, null)
2477         );
2478     }
2480     /**
2481      * A user should not be able load the calendar event for a course they cannot access.
2482      */
2483     public function test_get_calendar_event_by_id_no_course_permission() {
2484         global $USER;
2485         $this->resetAfterTest(true);
2486         $this->setAdminUser();
2488         $generator = $this->getDataGenerator();
2489         $user1 = $generator->create_user();
2490         $user2 = $generator->create_user();
2491         $course = $generator->create_course();
2492         $generator->enrol_user($user1->id, $course->id, 'student');
2493         $name = 'Course Event (course' . $course->id . ')';
2494         $record = new stdClass();
2495         $record->courseid = $course->id;
2496         $courseevent = $this->create_calendar_event($name, $USER->id, 'course', 0, time(), $record);
2498         // Admin can load the course event.
2499         $data = external_api::clean_returnvalue(
2500             core_calendar_external::get_calendar_event_by_id_returns(),
2501             core_calendar_external::get_calendar_event_by_id($courseevent->id)
2502         );
2503         $this->assertEquals($data['event']['id'], $courseevent->id);
2504         // User enrolled in the course can load the course event.
2505         $this->setUser($user1);
2506         $data = external_api::clean_returnvalue(
2507             core_calendar_external::get_calendar_event_by_id_returns(),
2508             core_calendar_external::get_calendar_event_by_id($courseevent->id)
2509         );
2510         $this->assertEquals($data['event']['id'], $courseevent->id);
2511         // User not enrolled in the course cannot load the course event.
2512         $this->setUser($user2);
2513         $this->expectException('required_capability_exception');
2514         $data = external_api::clean_returnvalue(
2515             core_calendar_external::get_calendar_event_by_id_returns(),
2516             core_calendar_external::get_calendar_event_by_id($courseevent->id)
2517         );
2518     }
2520     /**
2521      * A user should not be able load the calendar events for a category they cannot see.
2522      */
2523     public function test_get_calendar_events_hidden_category() {
2524         global $USER;
2525         $this->resetAfterTest(true);
2526         $this->setAdminUser();
2528         $generator = $this->getDataGenerator();
2529         $user1 = $generator->create_user();
2530         $category = $generator->create_category(['visible' => 0]);
2531         $name = 'Category Event (category: ' . $category->id . ')';
2532         $record = new stdClass();
2533         $record->categoryid = $category->id;
2534         $categoryevent = $this->create_calendar_event($name, $USER->id, 'category', 0, time(), $record);
2536         $events = [
2537             'eventids' => [$categoryevent->id]
2538         ];
2539         $options = [];
2540         // Admin can load the category event.
2541         $data = external_api::clean_returnvalue(
2542             core_calendar_external::get_calendar_events_returns(),
2543             core_calendar_external::get_calendar_events($events, $options)
2544         );
2545         $this->assertEquals($data['events'][0]['id'], $categoryevent->id);
2546         // User with no special permission to see hidden categories will not see the event.
2547         $this->setUser($user1);
2548         $data = external_api::clean_returnvalue(
2549             core_calendar_external::get_calendar_events_returns(),
2550             core_calendar_external::get_calendar_events($events, $options)
2551         );
2552         $this->assertCount(0, $data['events']);
2553         $this->assertEquals('nopermissions', $data['warnings'][0]['warningcode']);
2554     }
2556     /**
2557      * Test get_calendar_access_information for admins.
2558      */
2559     public function test_get_calendar_access_information_for_admins() {
2560         global $CFG;
2561         $this->resetAfterTest(true);
2562         $this->setAdminUser();
2564         $CFG->calendar_adminseesall = 1;
2566         $data = external_api::clean_returnvalue(
2567             core_calendar_external::get_calendar_access_information_returns(),
2568             core_calendar_external::get_calendar_access_information()
2569         );
2570         $this->assertTrue($data['canmanageownentries']);
2571         $this->assertTrue($data['canmanagegroupentries']);
2572         $this->assertTrue($data['canmanageentries']);
2573     }
2575     /**
2576      * Test get_calendar_access_information for authenticated users.
2577      */
2578     public function test_get_calendar_access_information_for_authenticated_users() {
2579         $this->resetAfterTest(true);
2580         $this->setUser($this->getDataGenerator()->create_user());
2582         $data = external_api::clean_returnvalue(
2583             core_calendar_external::get_calendar_access_information_returns(),
2584             core_calendar_external::get_calendar_access_information()
2585         );
2586         $this->assertTrue($data['canmanageownentries']);
2587         $this->assertFalse($data['canmanagegroupentries']);
2588         $this->assertFalse($data['canmanageentries']);
2589     }
2591     /**
2592      * Test get_calendar_access_information for student users.
2593      */
2594     public function test_get_calendar_access_information_for_student_users() {
2595         global $DB;
2596         $this->resetAfterTest(true);
2598         $user = $this->getDataGenerator()->create_user();
2599         $course = $this->getDataGenerator()->create_course();
2600         $role = $DB->get_record('role', array('shortname' => 'student'));
2601         $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
2603         $this->setUser($user);
2605         $data = external_api::clean_returnvalue(
2606             core_calendar_external::get_calendar_access_information_returns(),
2607             core_calendar_external::get_calendar_access_information($course->id)
2608         );
2609         $this->assertTrue($data['canmanageownentries']);
2610         $this->assertFalse($data['canmanagegroupentries']);
2611         $this->assertFalse($data['canmanageentries']);
2612     }
2614     /**
2615      * Test get_calendar_access_information for teacher users.
2616      */
2617     public function test_get_calendar_access_information_for_teacher_users() {
2618         global $DB;
2619         $this->resetAfterTest(true);
2621         $user = $this->getDataGenerator()->create_user();
2622         $course = $this->getDataGenerator()->create_course(['groupmode' => 1]);
2623         $role = $DB->get_record('role', array('shortname' => 'editingteacher'));
2624         $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
2625         $this->getDataGenerator()->create_group(['courseid' => $course->id]);
2627         $this->setUser($user);
2629         $data = external_api::clean_returnvalue(
2630             core_calendar_external::get_calendar_access_information_returns(),
2631             core_calendar_external::get_calendar_access_information($course->id)
2632         );
2633         $this->assertTrue($data['canmanageownentries']);
2634         $this->assertTrue($data['canmanagegroupentries']);
2635         $this->assertTrue($data['canmanageentries']);
2636     }
2638     /**
2639      * Test get_allowed_event_types for admins.
2640      */
2641     public function test_get_allowed_event_types_for_admins() {
2642         global $CFG;
2643         $this->resetAfterTest(true);
2644         $this->setAdminUser();
2645         $CFG->calendar_adminseesall = 1;
2646         $data = external_api::clean_returnvalue(
2647             core_calendar_external::get_allowed_event_types_returns(),
2648             core_calendar_external::get_allowed_event_types()
2649         );
2650         $this->assertEquals(['user', 'site', 'course', 'category'], $data['allowedeventtypes']);
2651     }
2652     /**
2653      * Test get_allowed_event_types for authenticated users.
2654      */
2655     public function test_get_allowed_event_types_for_authenticated_users() {
2656         $this->resetAfterTest(true);
2657         $this->setUser($this->getDataGenerator()->create_user());
2658         $data = external_api::clean_returnvalue(
2659             core_calendar_external::get_allowed_event_types_returns(),
2660             core_calendar_external::get_allowed_event_types()
2661         );
2662         $this->assertEquals(['user'], $data['allowedeventtypes']);
2663     }
2664     /**
2665      * Test get_allowed_event_types for student users.
2666      */
2667     public function test_get_allowed_event_types_for_student_users() {
2668         global $DB;
2669         $this->resetAfterTest(true);
2670         $user = $this->getDataGenerator()->create_user();
2671         $course = $this->getDataGenerator()->create_course();
2672         $role = $DB->get_record('role', array('shortname' => 'student'));
2673         $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
2674         $this->setUser($user);
2675         $data = external_api::clean_returnvalue(
2676             core_calendar_external::get_allowed_event_types_returns(),
2677             core_calendar_external::get_allowed_event_types($course->id)
2678         );
2679         $this->assertEquals(['user'], $data['allowedeventtypes']);
2680     }
2681     /**
2682      * Test get_allowed_event_types for teacher users.
2683      */
2684     public function test_get_allowed_event_types_for_teacher_users() {
2685         global $DB;
2686         $this->resetAfterTest(true);
2687         $user = $this->getDataGenerator()->create_user();
2688         $course = $this->getDataGenerator()->create_course(['groupmode' => 1]);
2689         $role = $DB->get_record('role', array('shortname' => 'editingteacher'));
2690         $this->getDataGenerator()->enrol_user($user->id, $course->id, $role->id);
2691         $this->getDataGenerator()->create_group(['courseid' => $course->id]);
2692         $this->setUser($user);
2693         $data = external_api::clean_returnvalue(
2694             core_calendar_external::get_allowed_event_types_returns(),
2695             core_calendar_external::get_allowed_event_types($course->id)
2696         );
2697         $this->assertEquals(['user', 'course', 'group'], $data['allowedeventtypes']);
2698     }