Merge branch 'MDL-60181-33' of git://github.com/mihailges/moodle into MOODLE_33_STABLE
[moodle.git] / calendar / externallib.php
blob2aab02c55f223d7f1e5273f442cfd8ce3d66c31b
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.
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/>.
18 /**
19 * External calendar API
21 * @package core_calendar
22 * @category external
23 * @copyright 2012 Ankit Agarwal
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 * @since Moodle 2.5
28 defined('MOODLE_INTERNAL') || die;
30 require_once("$CFG->libdir/externallib.php");
32 use \core_calendar\local\api as local_api;
33 use \core_calendar\external\events_exporter;
34 use \core_calendar\external\events_grouped_by_course_exporter;
35 use \core_calendar\external\events_related_objects_cache;
37 /**
38 * Calendar external functions
40 * @package core_calendar
41 * @category external
42 * @copyright 2012 Ankit Agarwal
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44 * @since Moodle 2.5
46 class core_calendar_external extends external_api {
49 /**
50 * Returns description of method parameters
52 * @return external_function_parameters
53 * @since Moodle 2.5
55 public static function delete_calendar_events_parameters() {
56 return new external_function_parameters(
57 array('events' => new external_multiple_structure(
58 new external_single_structure(
59 array(
60 'eventid' => new external_value(PARAM_INT, 'Event ID', VALUE_REQUIRED, '', NULL_NOT_ALLOWED),
61 'repeat' => new external_value(PARAM_BOOL, 'Delete comeplete series if repeated event')
62 ), 'List of events to delete'
69 /**
70 * Delete Calendar events
72 * @param array $eventids A list of event ids with repeat flag to delete
73 * @return null
74 * @since Moodle 2.5
76 public static function delete_calendar_events($events) {
77 global $CFG, $DB;
78 require_once($CFG->dirroot."/calendar/lib.php");
80 // Parameter validation.
81 $params = self::validate_parameters(self:: delete_calendar_events_parameters(), array('events' => $events));
83 $transaction = $DB->start_delegated_transaction();
85 foreach ($params['events'] as $event) {
86 $eventobj = calendar_event::load($event['eventid']);
88 // Let's check if the user is allowed to delete an event.
89 if (!empty($eventobj->modulename) || !calendar_edit_event_allowed($eventobj)) {
90 throw new moodle_exception("nopermissions", 'error', '',
91 get_string('deleteevent', 'calendar'));
93 // Time to do the magic.
94 $eventobj->delete($event['repeat']);
97 // Everything done smoothly, let's commit.
98 $transaction->allow_commit();
100 return null;
104 * Returns description of method result value
106 * @return external_description
107 * @since Moodle 2.5
109 public static function delete_calendar_events_returns() {
110 return null;
114 * Returns description of method parameters
116 * @return external_function_parameters
117 * @since Moodle 2.5
119 public static function get_calendar_events_parameters() {
120 return new external_function_parameters(
121 array('events' => new external_single_structure(
122 array(
123 'eventids' => new external_multiple_structure(
124 new external_value(PARAM_INT, 'event ids')
125 , 'List of event ids',
126 VALUE_DEFAULT, array(), NULL_ALLOWED
128 'courseids' => new external_multiple_structure(
129 new external_value(PARAM_INT, 'course ids')
130 , 'List of course ids for which events will be returned',
131 VALUE_DEFAULT, array(), NULL_ALLOWED
133 'groupids' => new external_multiple_structure(
134 new external_value(PARAM_INT, 'group ids')
135 , 'List of group ids for which events should be returned',
136 VALUE_DEFAULT, array(), NULL_ALLOWED
138 ), 'Event details', VALUE_DEFAULT, array()),
139 'options' => new external_single_structure(
140 array(
141 'userevents' => new external_value(PARAM_BOOL,
142 "Set to true to return current user's user events",
143 VALUE_DEFAULT, true, NULL_ALLOWED),
144 'siteevents' => new external_value(PARAM_BOOL,
145 "Set to true to return global events",
146 VALUE_DEFAULT, true, NULL_ALLOWED),
147 'timestart' => new external_value(PARAM_INT,
148 "Time from which events should be returned",
149 VALUE_DEFAULT, 0, NULL_ALLOWED),
150 'timeend' => new external_value(PARAM_INT,
151 "Time to which the events should be returned. We treat 0 and null as no end",
152 VALUE_DEFAULT, 0, NULL_ALLOWED),
153 'ignorehidden' => new external_value(PARAM_BOOL,
154 "Ignore hidden events or not",
155 VALUE_DEFAULT, true, NULL_ALLOWED),
157 ), 'Options', VALUE_DEFAULT, array())
163 * Get Calendar events
165 * @param array $events A list of events
166 * @param array $options various options
167 * @return array Array of event details
168 * @since Moodle 2.5
170 public static function get_calendar_events($events = array(), $options = array()) {
171 global $SITE, $DB, $USER, $CFG;
172 require_once($CFG->dirroot."/calendar/lib.php");
174 // Parameter validation.
175 $params = self::validate_parameters(self::get_calendar_events_parameters(), array('events' => $events, 'options' => $options));
176 $funcparam = array('courses' => array(), 'groups' => array());
177 $hassystemcap = has_capability('moodle/calendar:manageentries', context_system::instance());
178 $warnings = array();
180 // Let us findout courses that we can return events from.
181 if (!$hassystemcap) {
182 $courses = enrol_get_my_courses('id');
183 $courses = array_keys($courses);
184 foreach ($params['events']['courseids'] as $id) {
185 try {
186 $context = context_course::instance($id);
187 self::validate_context($context);
188 $funcparam['courses'][] = $id;
189 } catch (Exception $e) {
190 $warnings[] = array(
191 'item' => 'course',
192 'itemid' => $id,
193 'warningcode' => 'nopermissions',
194 'message' => 'No access rights in course context '.$e->getMessage().$e->getTraceAsString()
198 } else {
199 $courses = $params['events']['courseids'];
200 $funcparam['courses'] = $courses;
203 // Let us findout groups that we can return events from.
204 if (!$hassystemcap) {
205 $groups = groups_get_my_groups();
206 $groups = array_keys($groups);
207 foreach ($params['events']['groupids'] as $id) {
208 if (in_array($id, $groups)) {
209 $funcparam['groups'][] = $id;
210 } else {
211 $warnings[] = array('item' => $id, 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to access this group');
214 } else {
215 $groups = $params['events']['groupids'];
216 $funcparam['groups'] = $groups;
219 // Do we need user events?
220 if (!empty($params['options']['userevents'])) {
221 $funcparam['users'] = array($USER->id);
222 } else {
223 $funcparam['users'] = false;
226 // Do we need site events?
227 if (!empty($params['options']['siteevents'])) {
228 $funcparam['courses'][] = $SITE->id;
231 // We treat 0 and null as no end.
232 if (empty($params['options']['timeend'])) {
233 $params['options']['timeend'] = PHP_INT_MAX;
236 // Event list does not check visibility and permissions, we'll check that later.
237 $eventlist = calendar_get_legacy_events($params['options']['timestart'], $params['options']['timeend'],
238 $funcparam['users'], $funcparam['groups'], $funcparam['courses'], true, $params['options']['ignorehidden']);
240 // WS expects arrays.
241 $events = array();
243 // We need to get events asked for eventids.
244 if ($eventsbyid = calendar_get_events_by_id($params['events']['eventids'])) {
245 $eventlist += $eventsbyid;
248 foreach ($eventlist as $eventid => $eventobj) {
249 $event = (array) $eventobj;
250 // Description formatting.
251 $calendareventobj = new calendar_event($event);
252 list($event['description'], $event['format']) = $calendareventobj->format_external_text();
254 if ($hassystemcap) {
255 // User can see everything, no further check is needed.
256 $events[$eventid] = $event;
257 } else if (!empty($eventobj->modulename)) {
258 $courseid = $eventobj->courseid;
259 if (!$courseid) {
260 if (!$calendareventobj->context || !($context = $calendareventobj->context->get_course_context(false))) {
261 continue;
263 $courseid = $context->instanceid;
265 $instances = get_fast_modinfo($courseid)->get_instances_of($eventobj->modulename);
266 if (!empty($instances[$eventobj->instance]->uservisible)) {
267 $events[$eventid] = $event;
269 } else {
270 // Can the user actually see this event?
271 $eventobj = calendar_event::load($eventobj);
272 if (($eventobj->courseid == $SITE->id) ||
273 (!empty($eventobj->groupid) && in_array($eventobj->groupid, $groups)) ||
274 (!empty($eventobj->courseid) && in_array($eventobj->courseid, $courses)) ||
275 ($USER->id == $eventobj->userid) ||
276 (calendar_edit_event_allowed($eventid))) {
277 $events[$eventid] = $event;
278 } else {
279 $warnings[] = array('item' => $eventid, 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to view this event');
283 return array('events' => $events, 'warnings' => $warnings);
287 * Returns description of method result value
289 * @return external_description
290 * @since Moodle 2.5
292 public static function get_calendar_events_returns() {
293 return new external_single_structure(array(
294 'events' => new external_multiple_structure( new external_single_structure(
295 array(
296 'id' => new external_value(PARAM_INT, 'event id'),
297 'name' => new external_value(PARAM_TEXT, 'event name'),
298 'description' => new external_value(PARAM_RAW, 'Description', VALUE_OPTIONAL, null, NULL_ALLOWED),
299 'format' => new external_format_value('description'),
300 'courseid' => new external_value(PARAM_INT, 'course id'),
301 'groupid' => new external_value(PARAM_INT, 'group id'),
302 'userid' => new external_value(PARAM_INT, 'user id'),
303 'repeatid' => new external_value(PARAM_INT, 'repeat id'),
304 'modulename' => new external_value(PARAM_TEXT, 'module name', VALUE_OPTIONAL, null, NULL_ALLOWED),
305 'instance' => new external_value(PARAM_INT, 'instance id'),
306 'eventtype' => new external_value(PARAM_TEXT, 'Event type'),
307 'timestart' => new external_value(PARAM_INT, 'timestart'),
308 'timeduration' => new external_value(PARAM_INT, 'time duration'),
309 'visible' => new external_value(PARAM_INT, 'visible'),
310 'uuid' => new external_value(PARAM_TEXT, 'unique id of ical events', VALUE_OPTIONAL, null, NULL_NOT_ALLOWED),
311 'sequence' => new external_value(PARAM_INT, 'sequence'),
312 'timemodified' => new external_value(PARAM_INT, 'time modified'),
313 'subscriptionid' => new external_value(PARAM_INT, 'Subscription id', VALUE_OPTIONAL, null, NULL_ALLOWED),
314 ), 'event')
316 'warnings' => new external_warnings()
322 * Returns description of method parameters.
324 * @since Moodle 3.3
325 * @return external_function_parameters
327 public static function get_calendar_action_events_by_timesort_parameters() {
328 return new external_function_parameters(
329 array(
330 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, 0),
331 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null),
332 'aftereventid' => new external_value(PARAM_INT, 'The last seen event id', VALUE_DEFAULT, 0),
333 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 20)
339 * Get calendar action events based on the timesort value.
341 * @since Moodle 3.3
342 * @param null|int $timesortfrom Events after this time (inclusive)
343 * @param null|int $timesortto Events before this time (inclusive)
344 * @param null|int $aftereventid Get events with ids greater than this one
345 * @param int $limitnum Limit the number of results to this value
346 * @return array
348 public static function get_calendar_action_events_by_timesort($timesortfrom = 0, $timesortto = null,
349 $aftereventid = 0, $limitnum = 20) {
350 global $CFG, $PAGE, $USER;
352 require_once($CFG->dirroot . '/calendar/lib.php');
354 $user = null;
355 $params = self::validate_parameters(
356 self::get_calendar_action_events_by_timesort_parameters(),
358 'timesortfrom' => $timesortfrom,
359 'timesortto' => $timesortto,
360 'aftereventid' => $aftereventid,
361 'limitnum' => $limitnum,
364 $context = \context_user::instance($USER->id);
365 self::validate_context($context);
367 if (empty($params['aftereventid'])) {
368 $params['aftereventid'] = null;
371 $renderer = $PAGE->get_renderer('core_calendar');
372 $events = local_api::get_action_events_by_timesort(
373 $params['timesortfrom'],
374 $params['timesortto'],
375 $params['aftereventid'],
376 $params['limitnum']
379 $exportercache = new events_related_objects_cache($events);
380 $exporter = new events_exporter($events, ['cache' => $exportercache]);
382 return $exporter->export($renderer);
386 * Returns description of method result value.
388 * @since Moodle 3.3
389 * @return external_description
391 public static function get_calendar_action_events_by_timesort_returns() {
392 return events_exporter::get_read_structure();
396 * Returns description of method parameters.
398 * @return external_function_parameters
400 public static function get_calendar_action_events_by_course_parameters() {
401 return new external_function_parameters(
402 array(
403 'courseid' => new external_value(PARAM_INT, 'Course id'),
404 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, null),
405 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null),
406 'aftereventid' => new external_value(PARAM_INT, 'The last seen event id', VALUE_DEFAULT, 0),
407 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 20)
413 * Get calendar action events for the given course.
415 * @since Moodle 3.3
416 * @param int $courseid Only events in this course
417 * @param null|int $timesortfrom Events after this time (inclusive)
418 * @param null|int $timesortto Events before this time (inclusive)
419 * @param null|int $aftereventid Get events with ids greater than this one
420 * @param int $limitnum Limit the number of results to this value
421 * @return array
423 public static function get_calendar_action_events_by_course(
424 $courseid, $timesortfrom = null, $timesortto = null, $aftereventid = 0, $limitnum = 20) {
426 global $CFG, $PAGE, $USER;
428 require_once($CFG->dirroot . '/calendar/lib.php');
430 $user = null;
431 $params = self::validate_parameters(
432 self::get_calendar_action_events_by_course_parameters(),
434 'courseid' => $courseid,
435 'timesortfrom' => $timesortfrom,
436 'timesortto' => $timesortto,
437 'aftereventid' => $aftereventid,
438 'limitnum' => $limitnum,
441 $context = \context_user::instance($USER->id);
442 self::validate_context($context);
444 if (empty($params['aftereventid'])) {
445 $params['aftereventid'] = null;
448 $courses = enrol_get_my_courses('*', 'visible DESC,sortorder ASC', 0, [$courseid]);
449 $courses = array_values($courses);
451 if (empty($courses)) {
452 return [];
455 $course = $courses[0];
456 $renderer = $PAGE->get_renderer('core_calendar');
457 $events = local_api::get_action_events_by_course(
458 $course,
459 $params['timesortfrom'],
460 $params['timesortto'],
461 $params['aftereventid'],
462 $params['limitnum']
465 $exportercache = new events_related_objects_cache($events, $courses);
466 $exporter = new events_exporter($events, ['cache' => $exportercache]);
468 return $exporter->export($renderer);
472 * Returns description of method result value.
474 * @return external_description
476 public static function get_calendar_action_events_by_course_returns() {
477 return events_exporter::get_read_structure();
481 * Returns description of method parameters.
483 * @return external_function_parameters
485 public static function get_calendar_action_events_by_courses_parameters() {
486 return new external_function_parameters(
487 array(
488 'courseids' => new external_multiple_structure(
489 new external_value(PARAM_INT, 'Course id')
491 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, null),
492 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null),
493 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 10)
499 * Get calendar action events for a given list of courses.
501 * @since Moodle 3.3
502 * @param array $courseids Only include events for these courses
503 * @param null|int $timesortfrom Events after this time (inclusive)
504 * @param null|int $timesortto Events before this time (inclusive)
505 * @param int $limitnum Limit the number of results per course to this value
506 * @return array
508 public static function get_calendar_action_events_by_courses(
509 array $courseids, $timesortfrom = null, $timesortto = null, $limitnum = 10) {
511 global $CFG, $PAGE, $USER;
513 require_once($CFG->dirroot . '/calendar/lib.php');
515 $user = null;
516 $params = self::validate_parameters(
517 self::get_calendar_action_events_by_courses_parameters(),
519 'courseids' => $courseids,
520 'timesortfrom' => $timesortfrom,
521 'timesortto' => $timesortto,
522 'limitnum' => $limitnum,
525 $context = \context_user::instance($USER->id);
526 self::validate_context($context);
528 if (empty($params['courseids'])) {
529 return ['groupedbycourse' => []];
532 $renderer = $PAGE->get_renderer('core_calendar');
533 $courses = enrol_get_my_courses('*', 'visible DESC,sortorder ASC', 0, $params['courseids']);
534 $courses = array_values($courses);
536 if (empty($courses)) {
537 return ['groupedbycourse' => []];
540 $events = local_api::get_action_events_by_courses(
541 $courses,
542 $params['timesortfrom'],
543 $params['timesortto'],
544 $params['limitnum']
547 if (empty($events)) {
548 return ['groupedbycourse' => []];
551 $exportercache = new events_related_objects_cache($events, $courses);
552 $exporter = new events_grouped_by_course_exporter($events, ['cache' => $exportercache]);
554 return $exporter->export($renderer);
558 * Returns description of method result value.
560 * @return external_description
562 public static function get_calendar_action_events_by_courses_returns() {
563 return events_grouped_by_course_exporter::get_read_structure();
567 * Returns description of method parameters.
569 * @return external_function_parameters.
570 * @since Moodle 2.5
572 public static function create_calendar_events_parameters() {
573 // Userid is always current user, so no need to get it from client.
574 // Module based calendar events are not allowed here. Hence no need of instance and modulename.
575 // subscription id and uuid is not allowed as this is not an ical api.
576 return new external_function_parameters(
577 array('events' => new external_multiple_structure(
578 new external_single_structure(
579 array(
580 'name' => new external_value(PARAM_TEXT, 'event name', VALUE_REQUIRED, '', NULL_NOT_ALLOWED),
581 'description' => new external_value(PARAM_RAW, 'Description', VALUE_DEFAULT, null, NULL_ALLOWED),
582 'format' => new external_format_value('description', VALUE_DEFAULT),
583 'courseid' => new external_value(PARAM_INT, 'course id', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED),
584 'groupid' => new external_value(PARAM_INT, 'group id', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED),
585 'repeats' => new external_value(PARAM_INT, 'number of repeats', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED),
586 'eventtype' => new external_value(PARAM_TEXT, 'Event type', VALUE_DEFAULT, 'user', NULL_NOT_ALLOWED),
587 'timestart' => new external_value(PARAM_INT, 'timestart', VALUE_DEFAULT, time(), NULL_NOT_ALLOWED),
588 'timeduration' => new external_value(PARAM_INT, 'time duration', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED),
589 'visible' => new external_value(PARAM_INT, 'visible', VALUE_DEFAULT, 1, NULL_NOT_ALLOWED),
590 'sequence' => new external_value(PARAM_INT, 'sequence', VALUE_DEFAULT, 1, NULL_NOT_ALLOWED),
591 ), 'event')
598 * Delete Calendar events.
600 * @param array $events A list of events to create.
601 * @return array array of events created.
602 * @since Moodle 2.5
603 * @throws moodle_exception if user doesnt have the permission to create events.
605 public static function create_calendar_events($events) {
606 global $CFG, $DB, $USER;
607 require_once($CFG->dirroot."/calendar/lib.php");
609 // Parameter validation.
610 $params = self::validate_parameters(self::create_calendar_events_parameters(), array('events' => $events));
612 $transaction = $DB->start_delegated_transaction();
613 $return = array();
614 $warnings = array();
616 foreach ($params['events'] as $event) {
618 // Let us set some defaults.
619 $event['userid'] = $USER->id;
620 $event['modulename'] = '';
621 $event['instance'] = 0;
622 $event['subscriptionid'] = null;
623 $event['uuid']= '';
624 $event['format'] = external_validate_format($event['format']);
625 if ($event['repeats'] > 0) {
626 $event['repeat'] = 1;
627 } else {
628 $event['repeat'] = 0;
631 $eventobj = new calendar_event($event);
633 // Let's check if the user is allowed to delete an event.
634 if (!calendar_add_event_allowed($eventobj)) {
635 $warnings [] = array('item' => $event['name'], 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to create this event');
636 continue;
638 // Let's create the event.
639 $var = $eventobj->create($event);
640 $var = (array)$var->properties();
641 if ($event['repeat']) {
642 $children = $DB->get_records('event', array('repeatid' => $var['id']));
643 foreach ($children as $child) {
644 $return[] = (array) $child;
646 } else {
647 $return[] = $var;
651 // Everything done smoothly, let's commit.
652 $transaction->allow_commit();
653 return array('events' => $return, 'warnings' => $warnings);
657 * Returns description of method result value.
659 * @return external_description.
660 * @since Moodle 2.5
662 public static function create_calendar_events_returns() {
663 return new external_single_structure(
664 array(
665 'events' => new external_multiple_structure( new external_single_structure(
666 array(
667 'id' => new external_value(PARAM_INT, 'event id'),
668 'name' => new external_value(PARAM_TEXT, 'event name'),
669 'description' => new external_value(PARAM_RAW, 'Description', VALUE_OPTIONAL),
670 'format' => new external_format_value('description'),
671 'courseid' => new external_value(PARAM_INT, 'course id'),
672 'groupid' => new external_value(PARAM_INT, 'group id'),
673 'userid' => new external_value(PARAM_INT, 'user id'),
674 'repeatid' => new external_value(PARAM_INT, 'repeat id', VALUE_OPTIONAL),
675 'modulename' => new external_value(PARAM_TEXT, 'module name', VALUE_OPTIONAL),
676 'instance' => new external_value(PARAM_INT, 'instance id'),
677 'eventtype' => new external_value(PARAM_TEXT, 'Event type'),
678 'timestart' => new external_value(PARAM_INT, 'timestart'),
679 'timeduration' => new external_value(PARAM_INT, 'time duration'),
680 'visible' => new external_value(PARAM_INT, 'visible'),
681 'uuid' => new external_value(PARAM_TEXT, 'unique id of ical events', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
682 'sequence' => new external_value(PARAM_INT, 'sequence'),
683 'timemodified' => new external_value(PARAM_INT, 'time modified'),
684 'subscriptionid' => new external_value(PARAM_INT, 'Subscription id', VALUE_OPTIONAL),
685 ), 'event')
687 'warnings' => new external_warnings()