MDL-57503 calendar: external function get action events by course
[moodle.git] / calendar / externallib.php
CommitLineData
01bea07d
AA
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17
18/**
19 * External calendar API
20 *
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
26 */
27
28defined('MOODLE_INTERNAL') || die;
29
30require_once("$CFG->libdir/externallib.php");
31
c0f877fa
MN
32use \core_calendar\local\api as local_api;
33use \core_calendar\external\events_exporter;
60774b28 34use \core_calendar\external\events_grouped_by_course_exporter;
c0f877fa
MN
35use \core_calendar\external\events_related_objects_cache;
36
01bea07d
AA
37/**
38 * Calendar external functions
39 *
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
45 */
46class core_calendar_external extends external_api {
47
48
49 /**
50 * Returns description of method parameters
51 *
52 * @return external_function_parameters
53 * @since Moodle 2.5
54 */
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'
63 )
64 )
65 )
66 );
67 }
68
69 /**
70 * Delete Calendar events
71 *
72 * @param array $eventids A list of event ids with repeat flag to delete
73 * @return null
74 * @since Moodle 2.5
75 */
76 public static function delete_calendar_events($events) {
77 global $CFG, $DB;
78 require_once($CFG->dirroot."/calendar/lib.php");
79
80 // Parameter validation.
81 $params = self::validate_parameters(self:: delete_calendar_events_parameters(), array('events' => $events));
82
83 $transaction = $DB->start_delegated_transaction();
84
85 foreach ($params['events'] as $event) {
e057f279 86 $eventobj = \core_calendar\event::load($event['eventid']);
01bea07d
AA
87
88 // Let's check if the user is allowed to delete an event.
12cbce0a 89 if (!\core_calendar\api::can_edit_event($eventobj)) {
01bea07d
AA
90 throw new moodle_exception("nopermissions");
91 }
92 // Time to do the magic.
93 $eventobj->delete($event['repeat']);
94 }
95
96 // Everything done smoothly, let's commit.
97 $transaction->allow_commit();
98
99 return null;
100 }
101
102 /**
103 * Returns description of method result value
104 *
105 * @return external_description
106 * @since Moodle 2.5
107 */
108 public static function delete_calendar_events_returns() {
109 return null;
110 }
475896bd
AA
111
112 /**
113 * Returns description of method parameters
114 *
115 * @return external_function_parameters
116 * @since Moodle 2.5
117 */
118 public static function get_calendar_events_parameters() {
119 return new external_function_parameters(
120 array('events' => new external_single_structure(
121 array(
122 'eventids' => new external_multiple_structure(
123 new external_value(PARAM_INT, 'event ids')
124 , 'List of event ids',
125 VALUE_DEFAULT, array(), NULL_ALLOWED
126 ),
127 'courseids' => new external_multiple_structure(
128 new external_value(PARAM_INT, 'course ids')
129 , 'List of course ids for which events will be returned',
130 VALUE_DEFAULT, array(), NULL_ALLOWED
131 ),
132 'groupids' => new external_multiple_structure(
133 new external_value(PARAM_INT, 'group ids')
134 , 'List of group ids for which events should be returned',
135 VALUE_DEFAULT, array(), NULL_ALLOWED
136 )
137 ), 'Event details', VALUE_DEFAULT, array()),
138 'options' => new external_single_structure(
139 array(
140 'userevents' => new external_value(PARAM_BOOL,
141 "Set to true to return current user's user events",
142 VALUE_DEFAULT, true, NULL_ALLOWED),
143 'siteevents' => new external_value(PARAM_BOOL,
144 "Set to true to return global events",
145 VALUE_DEFAULT, true, NULL_ALLOWED),
146 'timestart' => new external_value(PARAM_INT,
147 "Time from which events should be returned",
148 VALUE_DEFAULT, 0, NULL_ALLOWED),
149 'timeend' => new external_value(PARAM_INT,
e07e04c1
DM
150 "Time to which the events should be returned. We treat 0 and null as no end",
151 VALUE_DEFAULT, 0, NULL_ALLOWED),
475896bd
AA
152 'ignorehidden' => new external_value(PARAM_BOOL,
153 "Ignore hidden events or not",
154 VALUE_DEFAULT, true, NULL_ALLOWED),
155
156 ), 'Options', VALUE_DEFAULT, array())
157 )
158 );
159 }
160
161 /**
162 * Get Calendar events
475896bd
AA
163 *
164 * @param array $events A list of events
e5adc5a1 165 * @param array $options various options
475896bd
AA
166 * @return array Array of event details
167 * @since Moodle 2.5
168 */
169 public static function get_calendar_events($events = array(), $options = array()) {
170 global $SITE, $DB, $USER, $CFG;
171 require_once($CFG->dirroot."/calendar/lib.php");
172
173 // Parameter validation.
e6a1f8c1
AA
174 $params = self::validate_parameters(self::get_calendar_events_parameters(), array('events' => $events, 'options' => $options));
175 $funcparam = array('courses' => array(), 'groups' => array());
475896bd 176 $hassystemcap = has_capability('moodle/calendar:manageentries', context_system::instance());
e6a1f8c1 177 $warnings = array();
475896bd
AA
178
179 // Let us findout courses that we can return events from.
180 if (!$hassystemcap) {
f11fdf9c
NM
181 $courses = enrol_get_my_courses('id');
182 $courses = array_keys($courses);
e6a1f8c1 183 foreach ($params['events']['courseids'] as $id) {
76aea854
SL
184 try {
185 $context = context_course::instance($id);
186 self::validate_context($context);
e6a1f8c1 187 $funcparam['courses'][] = $id;
76aea854
SL
188 } catch (Exception $e) {
189 $warnings[] = array(
190 'item' => 'course',
191 'itemid' => $id,
192 'warningcode' => 'nopermissions',
193 'message' => 'No access rights in course context '.$e->getMessage().$e->getTraceAsString()
194 );
e6a1f8c1
AA
195 }
196 }
475896bd
AA
197 } else {
198 $courses = $params['events']['courseids'];
199 $funcparam['courses'] = $courses;
200 }
201
202 // Let us findout groups that we can return events from.
203 if (!$hassystemcap) {
204 $groups = groups_get_my_groups();
205 $groups = array_keys($groups);
e6a1f8c1
AA
206 foreach ($params['events']['groupids'] as $id) {
207 if (in_array($id, $groups)) {
208 $funcparam['groups'][] = $id;
209 } else {
38e4fa58 210 $warnings[] = array('item' => $id, 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to access this group');
e6a1f8c1
AA
211 }
212 }
475896bd
AA
213 } else {
214 $groups = $params['events']['groupids'];
215 $funcparam['groups'] = $groups;
216 }
217
475896bd
AA
218 // Do we need user events?
219 if (!empty($params['options']['userevents'])) {
220 $funcparam['users'] = array($USER->id);
221 } else {
222 $funcparam['users'] = false;
223 }
224
225 // Do we need site events?
226 if (!empty($params['options']['siteevents'])) {
227 $funcparam['courses'][] = $SITE->id;
228 }
229
e07e04c1
DM
230 // We treat 0 and null as no end.
231 if (empty($params['options']['timeend'])) {
232 $params['options']['timeend'] = PHP_INT_MAX;
233 }
234
39b85137 235 // Event list does not check visibility and permissions, we'll check that later.
12cbce0a
MN
236 $eventlist = \core_calendar\api::get_events($params['options']['timestart'], $params['options']['timeend'],
237 $funcparam['users'], $funcparam['groups'], $funcparam['courses'], true, $params['options']['ignorehidden']);
39b85137 238
7c30224a
AA
239 // WS expects arrays.
240 $events = array();
475896bd
AA
241
242 // We need to get events asked for eventids.
12cbce0a 243 if ($eventsbyid = \core_calendar\api::get_events_by_id($params['events']['eventids'])) {
39b85137
JL
244 $eventlist += $eventsbyid;
245 }
246
247 foreach ($eventlist as $eventid => $eventobj) {
7c30224a 248 $event = (array) $eventobj;
871988b0 249 // Description formatting.
e057f279 250 $calendareventobj = new \core_calendar\event($event);
871988b0 251 list($event['description'], $event['format']) = $calendareventobj->format_external_text();
39b85137 252
475896bd
AA
253 if ($hassystemcap) {
254 // User can see everything, no further check is needed.
7c30224a
AA
255 $events[$eventid] = $event;
256 } else if (!empty($eventobj->modulename)) {
257 $cm = get_coursemodule_from_instance($eventobj->modulename, $eventobj->instance);
8270f0d0 258 if (\core_availability\info_module::is_user_visible($cm, 0, false)) {
7c30224a 259 $events[$eventid] = $event;
475896bd
AA
260 }
261 } else {
262 // Can the user actually see this event?
e057f279 263 $eventobj = \core_calendar\event::load($eventobj);
e6a1f8c1
AA
264 if (($eventobj->courseid == $SITE->id) ||
265 (!empty($eventobj->groupid) && in_array($eventobj->groupid, $groups)) ||
266 (!empty($eventobj->courseid) && in_array($eventobj->courseid, $courses)) ||
267 ($USER->id == $eventobj->userid) ||
12cbce0a 268 (\core_calendar\api::can_edit_event($eventid))) {
7c30224a 269 $events[$eventid] = $event;
e6a1f8c1 270 } else {
38e4fa58 271 $warnings[] = array('item' => $eventid, 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to view this event');
475896bd
AA
272 }
273 }
274 }
e6a1f8c1 275 return array('events' => $events, 'warnings' => $warnings);
475896bd
AA
276 }
277
278 /**
279 * Returns description of method result value
280 *
281 * @return external_description
282 * @since Moodle 2.5
283 */
284 public static function get_calendar_events_returns() {
e6a1f8c1
AA
285 return new external_single_structure(array(
286 'events' => new external_multiple_structure( new external_single_structure(
475896bd
AA
287 array(
288 'id' => new external_value(PARAM_INT, 'event id'),
289 'name' => new external_value(PARAM_TEXT, 'event name'),
e6a1f8c1 290 'description' => new external_value(PARAM_RAW, 'Description', VALUE_OPTIONAL, null, NULL_ALLOWED),
475896bd
AA
291 'format' => new external_format_value('description'),
292 'courseid' => new external_value(PARAM_INT, 'course id'),
293 'groupid' => new external_value(PARAM_INT, 'group id'),
294 'userid' => new external_value(PARAM_INT, 'user id'),
295 'repeatid' => new external_value(PARAM_INT, 'repeat id'),
e6a1f8c1 296 'modulename' => new external_value(PARAM_TEXT, 'module name', VALUE_OPTIONAL, null, NULL_ALLOWED),
475896bd
AA
297 'instance' => new external_value(PARAM_INT, 'instance id'),
298 'eventtype' => new external_value(PARAM_TEXT, 'Event type'),
299 'timestart' => new external_value(PARAM_INT, 'timestart'),
300 'timeduration' => new external_value(PARAM_INT, 'time duration'),
301 'visible' => new external_value(PARAM_INT, 'visible'),
e6a1f8c1 302 'uuid' => new external_value(PARAM_TEXT, 'unique id of ical events', VALUE_OPTIONAL, null, NULL_NOT_ALLOWED),
475896bd
AA
303 'sequence' => new external_value(PARAM_INT, 'sequence'),
304 'timemodified' => new external_value(PARAM_INT, 'time modified'),
e6a1f8c1
AA
305 'subscriptionid' => new external_value(PARAM_INT, 'Subscription id', VALUE_OPTIONAL, null, NULL_ALLOWED),
306 ), 'event')
307 ),
308 'warnings' => new external_warnings()
475896bd
AA
309 )
310 );
311 }
494a6389 312
c0f877fa
MN
313 /**
314 * Returns description of method parameters.
315 *
316 * @since Moodle 3.3
317 * @return external_function_parameters
318 */
319 public static function get_calendar_action_events_by_timesort_parameters() {
320 return new external_function_parameters(
321 array(
322 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, 0),
323 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null),
324 'aftereventid' => new external_value(PARAM_INT, 'The last seen event id', VALUE_DEFAULT, 0),
325 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 20)
326 )
327 );
328 }
329
330 /**
331 * Get calendar action events based on the timesort value.
332 *
333 * @since Moodle 3.3
334 * @param null|int $timesortfrom Events after this time (inclusive)
335 * @param null|int $timesortto Events before this time (inclusive)
336 * @param null|int $aftereventid Get events with ids greater than this one
337 * @param int $limitnum Limit the number of results to this value
338 * @return array
339 */
340 public static function get_calendar_action_events_by_timesort($timesortfrom = 0, $timesortto = null,
341 $aftereventid = 0, $limitnum = 20) {
342 global $CFG, $PAGE, $USER;
343
344 require_once($CFG->dirroot . '/calendar/lib.php');
345
346 $user = null;
347 $params = self::validate_parameters(
348 self::get_calendar_action_events_by_timesort_parameters(),
349 [
350 'timesortfrom' => $timesortfrom,
351 'timesortto' => $timesortto,
352 'aftereventid' => $aftereventid,
353 'limitnum' => $limitnum,
354 ]
355 );
356 $context = \context_user::instance($USER->id);
357 self::validate_context($context);
358
359 if (empty($params['aftereventid'])) {
360 $params['aftereventid'] = null;
361 }
362
363 $renderer = $PAGE->get_renderer('core_calendar');
364 $events = local_api::get_action_events_by_timesort(
365 $params['timesortfrom'],
366 $params['timesortto'],
367 $params['aftereventid'],
368 $params['limitnum']
369 );
370
371 $exportercache = new events_related_objects_cache($events);
372 $exporter = new events_exporter($events, ['cache' => $exportercache]);
373
374 return $exporter->export($renderer);
375 }
376
377 /**
378 * Returns description of method result value.
379 *
380 * @since Moodle 3.3
381 * @return external_description
382 */
383 public static function get_calendar_action_events_by_timesort_returns() {
384 return events_exporter::get_read_structure();
385 }
386
60774b28
RW
387 /**
388 * Returns description of method parameters.
389 *
390 * @return external_function_parameters
391 */
392 public static function get_calendar_action_events_by_course_parameters() {
393 return new external_function_parameters(
394 array(
395 'courseid' => new external_value(PARAM_INT, 'Course id'),
396 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, null),
397 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null),
398 'aftereventid' => new external_value(PARAM_INT, 'The last seen event id', VALUE_DEFAULT, 0),
399 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 20)
400 )
401 );
402 }
403
404 /**
405 * Get calendar action events for the given course.
406 *
407 * @since Moodle 3.3
408 * @param int $courseid Only events in this course
409 * @param null|int $timesortfrom Events after this time (inclusive)
410 * @param null|int $timesortto Events before this time (inclusive)
411 * @param null|int $aftereventid Get events with ids greater than this one
412 * @param int $limitnum Limit the number of results to this value
413 * @return array
414 */
415 public static function get_calendar_action_events_by_course(
416 $courseid, $timesortfrom = null, $timesortto = null, $aftereventid = 0, $limitnum = 20) {
417
418 global $CFG, $PAGE, $USER;
419
420 require_once($CFG->dirroot . '/calendar/lib.php');
421
422 $user = null;
423 $params = self::validate_parameters(
424 self::get_calendar_action_events_by_course_parameters(),
425 [
426 'courseid' => $courseid,
427 'timesortfrom' => $timesortfrom,
428 'timesortto' => $timesortto,
429 'aftereventid' => $aftereventid,
430 'limitnum' => $limitnum,
431 ]
432 );
433 $context = \context_user::instance($USER->id);
434 self::validate_context($context);
435
436 if (empty($params['aftereventid'])) {
437 $params['aftereventid'] = null;
438 }
439
440 $courses = enrol_get_my_courses('*', 'visible DESC,sortorder ASC', 0, [$courseid]);
441 $courses = array_values($courses);
442
443 if (empty($courses)) {
444 return [];
445 }
446
447 $course = $courses[0];
448 $renderer = $PAGE->get_renderer('core_calendar');
449 $events = local_api::get_action_events_by_course(
450 $course,
451 $params['timesortfrom'],
452 $params['timesortto'],
453 $params['aftereventid'],
454 $params['limitnum']
455 );
456
457 $exportercache = new events_related_objects_cache($events, $courses);
458 $exporter = new events_exporter($events, ['cache' => $exportercache]);
459
460 return $exporter->export($renderer);
461 }
462
463 /**
464 * Returns description of method result value.
465 *
466 * @return external_description
467 */
468 public static function get_calendar_action_events_by_course_returns() {
469 return events_exporter::get_read_structure();
470 }
471
494a6389
AA
472 /**
473 * Returns description of method parameters.
474 *
475 * @return external_function_parameters.
476 * @since Moodle 2.5
477 */
478 public static function create_calendar_events_parameters() {
479 // Userid is always current user, so no need to get it from client.
480 // Module based calendar events are not allowed here. Hence no need of instance and modulename.
481 // subscription id and uuid is not allowed as this is not an ical api.
482 return new external_function_parameters(
483 array('events' => new external_multiple_structure(
484 new external_single_structure(
485 array(
486 'name' => new external_value(PARAM_TEXT, 'event name', VALUE_REQUIRED, '', NULL_NOT_ALLOWED),
487 'description' => new external_value(PARAM_RAW, 'Description', VALUE_DEFAULT, null, NULL_ALLOWED),
488 'format' => new external_format_value('description', VALUE_DEFAULT),
489 'courseid' => new external_value(PARAM_INT, 'course id', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED),
490 'groupid' => new external_value(PARAM_INT, 'group id', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED),
491 'repeats' => new external_value(PARAM_INT, 'number of repeats', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED),
492 'eventtype' => new external_value(PARAM_TEXT, 'Event type', VALUE_DEFAULT, 'user', NULL_NOT_ALLOWED),
493 'timestart' => new external_value(PARAM_INT, 'timestart', VALUE_DEFAULT, time(), NULL_NOT_ALLOWED),
494 'timeduration' => new external_value(PARAM_INT, 'time duration', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED),
495 'visible' => new external_value(PARAM_INT, 'visible', VALUE_DEFAULT, 1, NULL_NOT_ALLOWED),
496 'sequence' => new external_value(PARAM_INT, 'sequence', VALUE_DEFAULT, 1, NULL_NOT_ALLOWED),
497 ), 'event')
498 )
499 )
500 );
501 }
502
503 /**
504 * Delete Calendar events.
505 *
506 * @param array $events A list of events to create.
507 * @return array array of events created.
508 * @since Moodle 2.5
509 * @throws moodle_exception if user doesnt have the permission to create events.
510 */
511 public static function create_calendar_events($events) {
512 global $CFG, $DB, $USER;
513 require_once($CFG->dirroot."/calendar/lib.php");
514
515 // Parameter validation.
516 $params = self::validate_parameters(self::create_calendar_events_parameters(), array('events' => $events));
517
518 $transaction = $DB->start_delegated_transaction();
519 $return = array();
520 $warnings = array();
521
522 foreach ($params['events'] as $event) {
523
524 // Let us set some defaults.
525 $event['userid'] = $USER->id;
526 $event['modulename'] = '';
527 $event['instance'] = 0;
528 $event['subscriptionid'] = null;
529 $event['uuid']= '';
530 $event['format'] = external_validate_format($event['format']);
531 if ($event['repeats'] > 0) {
532 $event['repeat'] = 1;
533 } else {
534 $event['repeat'] = 0;
535 }
536
e057f279 537 $eventobj = new \core_calendar\event($event);
494a6389
AA
538
539 // Let's check if the user is allowed to delete an event.
12cbce0a 540 if (!\core_calendar\api::can_add_event($eventobj)) {
38e4fa58 541 $warnings [] = array('item' => $event['name'], 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to create this event');
494a6389
AA
542 continue;
543 }
544 // Let's create the event.
545 $var = $eventobj->create($event);
546 $var = (array)$var->properties();
547 if ($event['repeat']) {
548 $children = $DB->get_records('event', array('repeatid' => $var['id']));
549 foreach ($children as $child) {
550 $return[] = (array) $child;
551 }
552 } else {
553 $return[] = $var;
554 }
555 }
556
557 // Everything done smoothly, let's commit.
558 $transaction->allow_commit();
559 return array('events' => $return, 'warnings' => $warnings);
560 }
561
562 /**
563 * Returns description of method result value.
564 *
565 * @return external_description.
566 * @since Moodle 2.5
567 */
568 public static function create_calendar_events_returns() {
569 return new external_single_structure(
570 array(
571 'events' => new external_multiple_structure( new external_single_structure(
572 array(
573 'id' => new external_value(PARAM_INT, 'event id'),
574 'name' => new external_value(PARAM_TEXT, 'event name'),
575 'description' => new external_value(PARAM_RAW, 'Description', VALUE_OPTIONAL),
576 'format' => new external_format_value('description'),
577 'courseid' => new external_value(PARAM_INT, 'course id'),
578 'groupid' => new external_value(PARAM_INT, 'group id'),
579 'userid' => new external_value(PARAM_INT, 'user id'),
580 'repeatid' => new external_value(PARAM_INT, 'repeat id', VALUE_OPTIONAL),
581 'modulename' => new external_value(PARAM_TEXT, 'module name', VALUE_OPTIONAL),
582 'instance' => new external_value(PARAM_INT, 'instance id'),
583 'eventtype' => new external_value(PARAM_TEXT, 'Event type'),
584 'timestart' => new external_value(PARAM_INT, 'timestart'),
585 'timeduration' => new external_value(PARAM_INT, 'time duration'),
586 'visible' => new external_value(PARAM_INT, 'visible'),
587 'uuid' => new external_value(PARAM_TEXT, 'unique id of ical events', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED),
588 'sequence' => new external_value(PARAM_INT, 'sequence'),
589 'timemodified' => new external_value(PARAM_INT, 'time modified'),
590 'subscriptionid' => new external_value(PARAM_INT, 'Subscription id', VALUE_OPTIONAL),
591 ), 'event')
592 ),
593 'warnings' => new external_warnings()
594 )
595 );
596 }
01bea07d 597}