Commit | Line | Data |
---|---|---|
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 | ||
28 | defined('MOODLE_INTERNAL') || die; | |
29 | ||
30 | require_once("$CFG->libdir/externallib.php"); | |
2aad6b82 | 31 | require_once($CFG->dirroot . '/calendar/lib.php'); |
01bea07d | 32 | |
c0f877fa | 33 | use \core_calendar\local\api as local_api; |
aa091225 RW |
34 | use \core_calendar\local\event\container as event_container; |
35 | use \core_calendar\local\event\forms\create as create_event_form; | |
36 | use \core_calendar\local\event\forms\update as update_event_form; | |
37 | use \core_calendar\local\event\mappers\create_update_form_mapper; | |
38 | use \core_calendar\external\event_exporter; | |
c0f877fa | 39 | use \core_calendar\external\events_exporter; |
60774b28 | 40 | use \core_calendar\external\events_grouped_by_course_exporter; |
c0f877fa MN |
41 | use \core_calendar\external\events_related_objects_cache; |
42 | ||
01bea07d AA |
43 | /** |
44 | * Calendar external functions | |
45 | * | |
46 | * @package core_calendar | |
47 | * @category external | |
48 | * @copyright 2012 Ankit Agarwal | |
49 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
50 | * @since Moodle 2.5 | |
51 | */ | |
52 | class core_calendar_external extends external_api { | |
53 | ||
54 | ||
55 | /** | |
56 | * Returns description of method parameters | |
57 | * | |
58 | * @return external_function_parameters | |
59 | * @since Moodle 2.5 | |
60 | */ | |
61 | public static function delete_calendar_events_parameters() { | |
62 | return new external_function_parameters( | |
63 | array('events' => new external_multiple_structure( | |
64 | new external_single_structure( | |
65 | array( | |
66 | 'eventid' => new external_value(PARAM_INT, 'Event ID', VALUE_REQUIRED, '', NULL_NOT_ALLOWED), | |
67 | 'repeat' => new external_value(PARAM_BOOL, 'Delete comeplete series if repeated event') | |
68 | ), 'List of events to delete' | |
69 | ) | |
70 | ) | |
71 | ) | |
72 | ); | |
73 | } | |
74 | ||
75 | /** | |
76 | * Delete Calendar events | |
77 | * | |
78 | * @param array $eventids A list of event ids with repeat flag to delete | |
79 | * @return null | |
80 | * @since Moodle 2.5 | |
81 | */ | |
82 | public static function delete_calendar_events($events) { | |
2aad6b82 | 83 | global $DB; |
01bea07d AA |
84 | |
85 | // Parameter validation. | |
86 | $params = self::validate_parameters(self:: delete_calendar_events_parameters(), array('events' => $events)); | |
87 | ||
88 | $transaction = $DB->start_delegated_transaction(); | |
89 | ||
90 | foreach ($params['events'] as $event) { | |
e1cd93ce | 91 | $eventobj = calendar_event::load($event['eventid']); |
01bea07d AA |
92 | |
93 | // Let's check if the user is allowed to delete an event. | |
436d39ba SL |
94 | if (!calendar_delete_event_allowed($eventobj)) { |
95 | throw new moodle_exception('nopermissions', 'error', '', get_string('deleteevent', 'calendar')); | |
01bea07d AA |
96 | } |
97 | // Time to do the magic. | |
98 | $eventobj->delete($event['repeat']); | |
99 | } | |
100 | ||
101 | // Everything done smoothly, let's commit. | |
102 | $transaction->allow_commit(); | |
103 | ||
104 | return null; | |
105 | } | |
106 | ||
107 | /** | |
108 | * Returns description of method result value | |
109 | * | |
110 | * @return external_description | |
111 | * @since Moodle 2.5 | |
112 | */ | |
113 | public static function delete_calendar_events_returns() { | |
114 | return null; | |
115 | } | |
475896bd AA |
116 | |
117 | /** | |
118 | * Returns description of method parameters | |
119 | * | |
120 | * @return external_function_parameters | |
121 | * @since Moodle 2.5 | |
122 | */ | |
123 | public static function get_calendar_events_parameters() { | |
124 | return new external_function_parameters( | |
125 | array('events' => new external_single_structure( | |
126 | array( | |
127 | 'eventids' => new external_multiple_structure( | |
128 | new external_value(PARAM_INT, 'event ids') | |
129 | , 'List of event ids', | |
7e781cfc | 130 | VALUE_DEFAULT, array()), |
475896bd AA |
131 | 'courseids' => new external_multiple_structure( |
132 | new external_value(PARAM_INT, 'course ids') | |
133 | , 'List of course ids for which events will be returned', | |
7e781cfc | 134 | VALUE_DEFAULT, array()), |
475896bd AA |
135 | 'groupids' => new external_multiple_structure( |
136 | new external_value(PARAM_INT, 'group ids') | |
137 | , 'List of group ids for which events should be returned', | |
7e781cfc | 138 | VALUE_DEFAULT, array()), |
10c17dcc SL |
139 | 'categoryids' => new external_multiple_structure( |
140 | new external_value(PARAM_INT, 'Category ids'), | |
141 | 'List of category ids for which events will be returned', | |
7e781cfc | 142 | VALUE_DEFAULT, array()), |
475896bd AA |
143 | ), 'Event details', VALUE_DEFAULT, array()), |
144 | 'options' => new external_single_structure( | |
145 | array( | |
146 | 'userevents' => new external_value(PARAM_BOOL, | |
147 | "Set to true to return current user's user events", | |
148 | VALUE_DEFAULT, true, NULL_ALLOWED), | |
149 | 'siteevents' => new external_value(PARAM_BOOL, | |
375d82ca | 150 | "Set to true to return site events", |
475896bd AA |
151 | VALUE_DEFAULT, true, NULL_ALLOWED), |
152 | 'timestart' => new external_value(PARAM_INT, | |
153 | "Time from which events should be returned", | |
154 | VALUE_DEFAULT, 0, NULL_ALLOWED), | |
155 | 'timeend' => new external_value(PARAM_INT, | |
e07e04c1 DM |
156 | "Time to which the events should be returned. We treat 0 and null as no end", |
157 | VALUE_DEFAULT, 0, NULL_ALLOWED), | |
475896bd AA |
158 | 'ignorehidden' => new external_value(PARAM_BOOL, |
159 | "Ignore hidden events or not", | |
160 | VALUE_DEFAULT, true, NULL_ALLOWED), | |
161 | ||
162 | ), 'Options', VALUE_DEFAULT, array()) | |
163 | ) | |
164 | ); | |
165 | } | |
166 | ||
167 | /** | |
168 | * Get Calendar events | |
475896bd AA |
169 | * |
170 | * @param array $events A list of events | |
e5adc5a1 | 171 | * @param array $options various options |
475896bd AA |
172 | * @return array Array of event details |
173 | * @since Moodle 2.5 | |
174 | */ | |
175 | public static function get_calendar_events($events = array(), $options = array()) { | |
2aad6b82 | 176 | global $SITE, $DB, $USER; |
475896bd AA |
177 | |
178 | // Parameter validation. | |
e6a1f8c1 | 179 | $params = self::validate_parameters(self::get_calendar_events_parameters(), array('events' => $events, 'options' => $options)); |
10c17dcc | 180 | $funcparam = array('courses' => array(), 'groups' => array(), 'categories' => array()); |
475896bd | 181 | $hassystemcap = has_capability('moodle/calendar:manageentries', context_system::instance()); |
e6a1f8c1 | 182 | $warnings = array(); |
c4172077 | 183 | $coursecategories = array(); |
475896bd | 184 | |
c4172077 | 185 | // Let us find out courses and their categories that we can return events from. |
475896bd | 186 | if (!$hassystemcap) { |
c4172077 MG |
187 | $courseobjs = enrol_get_my_courses(); |
188 | $courses = array_keys($courseobjs); | |
189 | ||
190 | $coursecategories = array_flip(array_map(function($course) { | |
191 | return $course->category; | |
192 | }, $courseobjs)); | |
193 | ||
e6a1f8c1 | 194 | foreach ($params['events']['courseids'] as $id) { |
76aea854 SL |
195 | try { |
196 | $context = context_course::instance($id); | |
197 | self::validate_context($context); | |
e6a1f8c1 | 198 | $funcparam['courses'][] = $id; |
76aea854 SL |
199 | } catch (Exception $e) { |
200 | $warnings[] = array( | |
201 | 'item' => 'course', | |
202 | 'itemid' => $id, | |
203 | 'warningcode' => 'nopermissions', | |
204 | 'message' => 'No access rights in course context '.$e->getMessage().$e->getTraceAsString() | |
205 | ); | |
e6a1f8c1 AA |
206 | } |
207 | } | |
475896bd AA |
208 | } else { |
209 | $courses = $params['events']['courseids']; | |
210 | $funcparam['courses'] = $courses; | |
c4172077 MG |
211 | |
212 | if (!empty($courses)) { | |
213 | list($wheresql, $sqlparams) = $DB->get_in_or_equal($courses); | |
214 | $wheresql = "id $wheresql"; | |
215 | $coursecategories = array_flip(array_map(function($course) { | |
216 | return $course->category; | |
217 | }, $DB->get_records_select('course', $wheresql, $sqlparams, '', 'category'))); | |
218 | } | |
475896bd AA |
219 | } |
220 | ||
221 | // Let us findout groups that we can return events from. | |
222 | if (!$hassystemcap) { | |
223 | $groups = groups_get_my_groups(); | |
224 | $groups = array_keys($groups); | |
e6a1f8c1 AA |
225 | foreach ($params['events']['groupids'] as $id) { |
226 | if (in_array($id, $groups)) { | |
227 | $funcparam['groups'][] = $id; | |
228 | } else { | |
38e4fa58 | 229 | $warnings[] = array('item' => $id, 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to access this group'); |
e6a1f8c1 AA |
230 | } |
231 | } | |
475896bd AA |
232 | } else { |
233 | $groups = $params['events']['groupids']; | |
234 | $funcparam['groups'] = $groups; | |
235 | } | |
236 | ||
10c17dcc | 237 | $categories = array(); |
44ae0838 | 238 | if ($hassystemcap || !empty($courses)) { |
c4172077 MG |
239 | // Use the category id as the key in the following array. That way we do not have to remove duplicates and |
240 | // have a faster lookup later. | |
241 | $categories = []; | |
242 | ||
243 | if (!empty($params['events']['categoryids'])) { | |
442f12f8 MG |
244 | $catobjs = \core_course_category::get_many( |
245 | array_merge($params['events']['categoryids'], array_keys($coursecategories))); | |
c4172077 MG |
246 | foreach ($catobjs as $catobj) { |
247 | if (isset($coursecategories[$catobj->id]) || | |
248 | has_capability('moodle/category:manage', $catobj->get_context())) { | |
249 | // If the user has access to a course in this category or can manage the category, | |
250 | // then they can see all parent categories too. | |
251 | $categories[$catobj->id] = true; | |
252 | foreach ($catobj->get_parents() as $catid) { | |
253 | $categories[$catid] = true; | |
44ae0838 | 254 | } |
10c17dcc SL |
255 | } |
256 | } | |
c4172077 MG |
257 | $funcparam['categories'] = array_keys($categories); |
258 | } else { | |
259 | // Fetch all categories where this user has any enrolment, and all categories that this user can manage. | |
260 | $calcatcache = cache::make('core', 'calendar_categories'); | |
261 | // Do not use cache if the user has the system capability as $coursecategories might not represent the | |
262 | // courses the user is enrolled in. | |
263 | $categories = (!$hassystemcap) ? $calcatcache->get('site') : false; | |
264 | if ($categories !== false) { | |
265 | // The ids are stored in a list in the cache. | |
266 | $funcparam['categories'] = $categories; | |
267 | $categories = array_flip($categories); | |
268 | } else { | |
269 | $categories = []; | |
442f12f8 | 270 | foreach (\core_course_category::get_all() as $category) { |
c4172077 MG |
271 | if (isset($coursecategories[$category->id]) || |
272 | has_capability('moodle/category:manage', $category->get_context(), $USER, false)) { | |
273 | // If the user has access to a course in this category or can manage the category, | |
274 | // then they can see all parent categories too. | |
275 | $categories[$category->id] = true; | |
276 | foreach ($category->get_parents() as $catid) { | |
277 | $categories[$catid] = true; | |
278 | } | |
10c17dcc SL |
279 | } |
280 | } | |
c4172077 MG |
281 | $funcparam['categories'] = array_keys($categories); |
282 | if (!$hassystemcap) { | |
283 | $calcatcache->set('site', $funcparam['categories']); | |
284 | } | |
10c17dcc SL |
285 | } |
286 | } | |
10c17dcc SL |
287 | } |
288 | ||
475896bd AA |
289 | // Do we need user events? |
290 | if (!empty($params['options']['userevents'])) { | |
291 | $funcparam['users'] = array($USER->id); | |
292 | } else { | |
293 | $funcparam['users'] = false; | |
294 | } | |
295 | ||
296 | // Do we need site events? | |
297 | if (!empty($params['options']['siteevents'])) { | |
298 | $funcparam['courses'][] = $SITE->id; | |
299 | } | |
300 | ||
e07e04c1 DM |
301 | // We treat 0 and null as no end. |
302 | if (empty($params['options']['timeend'])) { | |
303 | $params['options']['timeend'] = PHP_INT_MAX; | |
304 | } | |
305 | ||
39b85137 | 306 | // Event list does not check visibility and permissions, we'll check that later. |
22753c8c | 307 | $eventlist = calendar_get_legacy_events($params['options']['timestart'], $params['options']['timeend'], |
10c17dcc SL |
308 | $funcparam['users'], $funcparam['groups'], $funcparam['courses'], true, |
309 | $params['options']['ignorehidden'], $funcparam['categories']); | |
39b85137 | 310 | |
7c30224a AA |
311 | // WS expects arrays. |
312 | $events = array(); | |
475896bd AA |
313 | |
314 | // We need to get events asked for eventids. | |
23a29de7 | 315 | if ($eventsbyid = calendar_get_events_by_id($params['events']['eventids'])) { |
39b85137 JL |
316 | $eventlist += $eventsbyid; |
317 | } | |
39b85137 | 318 | foreach ($eventlist as $eventid => $eventobj) { |
7c30224a | 319 | $event = (array) $eventobj; |
871988b0 | 320 | // Description formatting. |
e1cd93ce | 321 | $calendareventobj = new calendar_event($event); |
8c84eeee | 322 | $event['name'] = $calendareventobj->format_external_name(); |
871988b0 | 323 | list($event['description'], $event['format']) = $calendareventobj->format_external_text(); |
39b85137 | 324 | |
475896bd AA |
325 | if ($hassystemcap) { |
326 | // User can see everything, no further check is needed. | |
7c30224a AA |
327 | $events[$eventid] = $event; |
328 | } else if (!empty($eventobj->modulename)) { | |
5900513f MG |
329 | $courseid = $eventobj->courseid; |
330 | if (!$courseid) { | |
331 | if (!$calendareventobj->context || !($context = $calendareventobj->context->get_course_context(false))) { | |
332 | continue; | |
333 | } | |
334 | $courseid = $context->instanceid; | |
335 | } | |
336 | $instances = get_fast_modinfo($courseid)->get_instances_of($eventobj->modulename); | |
337 | if (!empty($instances[$eventobj->instance]->uservisible)) { | |
7c30224a | 338 | $events[$eventid] = $event; |
475896bd AA |
339 | } |
340 | } else { | |
341 | // Can the user actually see this event? | |
e1cd93ce | 342 | $eventobj = calendar_event::load($eventobj); |
af25b8fc | 343 | if ((($eventobj->courseid == $SITE->id) && (empty($eventobj->categoryid))) || |
c4172077 | 344 | (!empty($eventobj->categoryid) && isset($categories[$eventobj->categoryid])) || |
e6a1f8c1 AA |
345 | (!empty($eventobj->groupid) && in_array($eventobj->groupid, $groups)) || |
346 | (!empty($eventobj->courseid) && in_array($eventobj->courseid, $courses)) || | |
347 | ($USER->id == $eventobj->userid) || | |
86679cb1 | 348 | (calendar_edit_event_allowed($eventobj))) { |
7c30224a | 349 | $events[$eventid] = $event; |
e6a1f8c1 | 350 | } else { |
38e4fa58 | 351 | $warnings[] = array('item' => $eventid, 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to view this event'); |
475896bd AA |
352 | } |
353 | } | |
354 | } | |
e6a1f8c1 | 355 | return array('events' => $events, 'warnings' => $warnings); |
475896bd AA |
356 | } |
357 | ||
358 | /** | |
359 | * Returns description of method result value | |
360 | * | |
361 | * @return external_description | |
362 | * @since Moodle 2.5 | |
363 | */ | |
364 | public static function get_calendar_events_returns() { | |
e6a1f8c1 AA |
365 | return new external_single_structure(array( |
366 | 'events' => new external_multiple_structure( new external_single_structure( | |
475896bd AA |
367 | array( |
368 | 'id' => new external_value(PARAM_INT, 'event id'), | |
8c84eeee | 369 | 'name' => new external_value(PARAM_RAW, 'event name'), |
e6a1f8c1 | 370 | 'description' => new external_value(PARAM_RAW, 'Description', VALUE_OPTIONAL, null, NULL_ALLOWED), |
475896bd AA |
371 | 'format' => new external_format_value('description'), |
372 | 'courseid' => new external_value(PARAM_INT, 'course id'), | |
e3c04bd9 JL |
373 | 'categoryid' => new external_value(PARAM_INT, 'Category id (only for category events).', |
374 | VALUE_OPTIONAL), | |
475896bd AA |
375 | 'groupid' => new external_value(PARAM_INT, 'group id'), |
376 | 'userid' => new external_value(PARAM_INT, 'user id'), | |
377 | 'repeatid' => new external_value(PARAM_INT, 'repeat id'), | |
e6a1f8c1 | 378 | 'modulename' => new external_value(PARAM_TEXT, 'module name', VALUE_OPTIONAL, null, NULL_ALLOWED), |
475896bd AA |
379 | 'instance' => new external_value(PARAM_INT, 'instance id'), |
380 | 'eventtype' => new external_value(PARAM_TEXT, 'Event type'), | |
381 | 'timestart' => new external_value(PARAM_INT, 'timestart'), | |
382 | 'timeduration' => new external_value(PARAM_INT, 'time duration'), | |
383 | 'visible' => new external_value(PARAM_INT, 'visible'), | |
e6a1f8c1 | 384 | 'uuid' => new external_value(PARAM_TEXT, 'unique id of ical events', VALUE_OPTIONAL, null, NULL_NOT_ALLOWED), |
475896bd AA |
385 | 'sequence' => new external_value(PARAM_INT, 'sequence'), |
386 | 'timemodified' => new external_value(PARAM_INT, 'time modified'), | |
e6a1f8c1 AA |
387 | 'subscriptionid' => new external_value(PARAM_INT, 'Subscription id', VALUE_OPTIONAL, null, NULL_ALLOWED), |
388 | ), 'event') | |
389 | ), | |
390 | 'warnings' => new external_warnings() | |
475896bd AA |
391 | ) |
392 | ); | |
393 | } | |
494a6389 | 394 | |
c0f877fa MN |
395 | /** |
396 | * Returns description of method parameters. | |
397 | * | |
398 | * @since Moodle 3.3 | |
399 | * @return external_function_parameters | |
400 | */ | |
401 | public static function get_calendar_action_events_by_timesort_parameters() { | |
402 | return new external_function_parameters( | |
403 | array( | |
404 | 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, 0), | |
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), | |
644ffbd3 AG |
407 | 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 20), |
408 | 'limittononsuspendedevents' => new external_value(PARAM_BOOL, | |
7af6528e DM |
409 | 'Limit the events to courses the user is not suspended in', VALUE_DEFAULT, false), |
410 | 'userid' => new external_value(PARAM_INT, 'The user id', VALUE_DEFAULT, null), | |
c0f877fa MN |
411 | ) |
412 | ); | |
413 | } | |
414 | ||
415 | /** | |
416 | * Get calendar action events based on the timesort value. | |
417 | * | |
418 | * @since Moodle 3.3 | |
419 | * @param null|int $timesortfrom Events after this time (inclusive) | |
420 | * @param null|int $timesortto Events before this time (inclusive) | |
421 | * @param null|int $aftereventid Get events with ids greater than this one | |
422 | * @param int $limitnum Limit the number of results to this value | |
7af6528e | 423 | * @param null|int $userid The user id |
c0f877fa MN |
424 | * @return array |
425 | */ | |
426 | public static function get_calendar_action_events_by_timesort($timesortfrom = 0, $timesortto = null, | |
7af6528e DM |
427 | $aftereventid = 0, $limitnum = 20, $limittononsuspendedevents = false, |
428 | $userid = null) { | |
2aad6b82 | 429 | global $PAGE, $USER; |
c0f877fa | 430 | |
c0f877fa MN |
431 | $params = self::validate_parameters( |
432 | self::get_calendar_action_events_by_timesort_parameters(), | |
433 | [ | |
434 | 'timesortfrom' => $timesortfrom, | |
435 | 'timesortto' => $timesortto, | |
436 | 'aftereventid' => $aftereventid, | |
437 | 'limitnum' => $limitnum, | |
7af6528e DM |
438 | 'limittononsuspendedevents' => $limittononsuspendedevents, |
439 | 'userid' => $userid, | |
c0f877fa MN |
440 | ] |
441 | ); | |
7af6528e DM |
442 | if ($params['userid']) { |
443 | $user = \core_user::get_user($params['userid']); | |
444 | } else { | |
445 | $user = $USER; | |
446 | } | |
447 | ||
448 | $context = \context_user::instance($user->id); | |
c0f877fa MN |
449 | self::validate_context($context); |
450 | ||
451 | if (empty($params['aftereventid'])) { | |
452 | $params['aftereventid'] = null; | |
453 | } | |
454 | ||
455 | $renderer = $PAGE->get_renderer('core_calendar'); | |
456 | $events = local_api::get_action_events_by_timesort( | |
457 | $params['timesortfrom'], | |
458 | $params['timesortto'], | |
459 | $params['aftereventid'], | |
644ffbd3 | 460 | $params['limitnum'], |
7af6528e DM |
461 | $params['limittononsuspendedevents'], |
462 | $user | |
c0f877fa MN |
463 | ); |
464 | ||
465 | $exportercache = new events_related_objects_cache($events); | |
466 | $exporter = new events_exporter($events, ['cache' => $exportercache]); | |
467 | ||
468 | return $exporter->export($renderer); | |
469 | } | |
470 | ||
471 | /** | |
472 | * Returns description of method result value. | |
473 | * | |
474 | * @since Moodle 3.3 | |
475 | * @return external_description | |
476 | */ | |
477 | public static function get_calendar_action_events_by_timesort_returns() { | |
478 | return events_exporter::get_read_structure(); | |
479 | } | |
480 | ||
60774b28 RW |
481 | /** |
482 | * Returns description of method parameters. | |
483 | * | |
484 | * @return external_function_parameters | |
485 | */ | |
486 | public static function get_calendar_action_events_by_course_parameters() { | |
487 | return new external_function_parameters( | |
488 | array( | |
489 | 'courseid' => new external_value(PARAM_INT, 'Course id'), | |
490 | 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, null), | |
491 | 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null), | |
492 | 'aftereventid' => new external_value(PARAM_INT, 'The last seen event id', VALUE_DEFAULT, 0), | |
493 | 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 20) | |
494 | ) | |
495 | ); | |
496 | } | |
497 | ||
498 | /** | |
499 | * Get calendar action events for the given course. | |
500 | * | |
501 | * @since Moodle 3.3 | |
502 | * @param int $courseid Only events in this course | |
503 | * @param null|int $timesortfrom Events after this time (inclusive) | |
504 | * @param null|int $timesortto Events before this time (inclusive) | |
505 | * @param null|int $aftereventid Get events with ids greater than this one | |
506 | * @param int $limitnum Limit the number of results to this value | |
507 | * @return array | |
508 | */ | |
509 | public static function get_calendar_action_events_by_course( | |
510 | $courseid, $timesortfrom = null, $timesortto = null, $aftereventid = 0, $limitnum = 20) { | |
511 | ||
2aad6b82 | 512 | global $PAGE, $USER; |
60774b28 RW |
513 | |
514 | $user = null; | |
515 | $params = self::validate_parameters( | |
516 | self::get_calendar_action_events_by_course_parameters(), | |
517 | [ | |
518 | 'courseid' => $courseid, | |
519 | 'timesortfrom' => $timesortfrom, | |
520 | 'timesortto' => $timesortto, | |
521 | 'aftereventid' => $aftereventid, | |
522 | 'limitnum' => $limitnum, | |
523 | ] | |
524 | ); | |
525 | $context = \context_user::instance($USER->id); | |
526 | self::validate_context($context); | |
527 | ||
528 | if (empty($params['aftereventid'])) { | |
529 | $params['aftereventid'] = null; | |
530 | } | |
531 | ||
04985346 | 532 | $courses = enrol_get_my_courses('*', null, 0, [$courseid]); |
60774b28 RW |
533 | $courses = array_values($courses); |
534 | ||
535 | if (empty($courses)) { | |
536 | return []; | |
537 | } | |
538 | ||
539 | $course = $courses[0]; | |
540 | $renderer = $PAGE->get_renderer('core_calendar'); | |
541 | $events = local_api::get_action_events_by_course( | |
542 | $course, | |
543 | $params['timesortfrom'], | |
544 | $params['timesortto'], | |
545 | $params['aftereventid'], | |
546 | $params['limitnum'] | |
547 | ); | |
548 | ||
549 | $exportercache = new events_related_objects_cache($events, $courses); | |
550 | $exporter = new events_exporter($events, ['cache' => $exportercache]); | |
551 | ||
552 | return $exporter->export($renderer); | |
553 | } | |
554 | ||
555 | /** | |
556 | * Returns description of method result value. | |
557 | * | |
558 | * @return external_description | |
559 | */ | |
560 | public static function get_calendar_action_events_by_course_returns() { | |
561 | return events_exporter::get_read_structure(); | |
562 | } | |
563 | ||
9b8e5057 RW |
564 | /** |
565 | * Returns description of method parameters. | |
566 | * | |
567 | * @return external_function_parameters | |
568 | */ | |
569 | public static function get_calendar_action_events_by_courses_parameters() { | |
570 | return new external_function_parameters( | |
571 | array( | |
572 | 'courseids' => new external_multiple_structure( | |
573 | new external_value(PARAM_INT, 'Course id') | |
574 | ), | |
575 | 'timesortfrom' => new external_value(PARAM_INT, 'Time sort from', VALUE_DEFAULT, null), | |
576 | 'timesortto' => new external_value(PARAM_INT, 'Time sort to', VALUE_DEFAULT, null), | |
577 | 'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 10) | |
578 | ) | |
579 | ); | |
580 | } | |
581 | ||
582 | /** | |
583 | * Get calendar action events for a given list of courses. | |
584 | * | |
585 | * @since Moodle 3.3 | |
586 | * @param array $courseids Only include events for these courses | |
587 | * @param null|int $timesortfrom Events after this time (inclusive) | |
588 | * @param null|int $timesortto Events before this time (inclusive) | |
589 | * @param int $limitnum Limit the number of results per course to this value | |
590 | * @return array | |
591 | */ | |
592 | public static function get_calendar_action_events_by_courses( | |
593 | array $courseids, $timesortfrom = null, $timesortto = null, $limitnum = 10) { | |
594 | ||
2aad6b82 | 595 | global $PAGE, $USER; |
9b8e5057 RW |
596 | |
597 | $user = null; | |
598 | $params = self::validate_parameters( | |
599 | self::get_calendar_action_events_by_courses_parameters(), | |
600 | [ | |
601 | 'courseids' => $courseids, | |
602 | 'timesortfrom' => $timesortfrom, | |
603 | 'timesortto' => $timesortto, | |
604 | 'limitnum' => $limitnum, | |
605 | ] | |
606 | ); | |
607 | $context = \context_user::instance($USER->id); | |
608 | self::validate_context($context); | |
609 | ||
610 | if (empty($params['courseids'])) { | |
611 | return ['groupedbycourse' => []]; | |
612 | } | |
613 | ||
614 | $renderer = $PAGE->get_renderer('core_calendar'); | |
04985346 | 615 | $courses = enrol_get_my_courses('*', null, 0, $params['courseids']); |
9b8e5057 RW |
616 | $courses = array_values($courses); |
617 | ||
618 | if (empty($courses)) { | |
619 | return ['groupedbycourse' => []]; | |
620 | } | |
621 | ||
622 | $events = local_api::get_action_events_by_courses( | |
623 | $courses, | |
624 | $params['timesortfrom'], | |
625 | $params['timesortto'], | |
626 | $params['limitnum'] | |
627 | ); | |
628 | ||
629 | if (empty($events)) { | |
630 | return ['groupedbycourse' => []]; | |
631 | } | |
632 | ||
633 | $exportercache = new events_related_objects_cache($events, $courses); | |
634 | $exporter = new events_grouped_by_course_exporter($events, ['cache' => $exportercache]); | |
635 | ||
636 | return $exporter->export($renderer); | |
637 | } | |
638 | ||
639 | /** | |
640 | * Returns description of method result value. | |
641 | * | |
642 | * @return external_description | |
643 | */ | |
644 | public static function get_calendar_action_events_by_courses_returns() { | |
645 | return events_grouped_by_course_exporter::get_read_structure(); | |
646 | } | |
647 | ||
494a6389 AA |
648 | /** |
649 | * Returns description of method parameters. | |
650 | * | |
651 | * @return external_function_parameters. | |
652 | * @since Moodle 2.5 | |
653 | */ | |
654 | public static function create_calendar_events_parameters() { | |
655 | // Userid is always current user, so no need to get it from client. | |
656 | // Module based calendar events are not allowed here. Hence no need of instance and modulename. | |
657 | // subscription id and uuid is not allowed as this is not an ical api. | |
658 | return new external_function_parameters( | |
659 | array('events' => new external_multiple_structure( | |
660 | new external_single_structure( | |
661 | array( | |
662 | 'name' => new external_value(PARAM_TEXT, 'event name', VALUE_REQUIRED, '', NULL_NOT_ALLOWED), | |
663 | 'description' => new external_value(PARAM_RAW, 'Description', VALUE_DEFAULT, null, NULL_ALLOWED), | |
664 | 'format' => new external_format_value('description', VALUE_DEFAULT), | |
665 | 'courseid' => new external_value(PARAM_INT, 'course id', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), | |
666 | 'groupid' => new external_value(PARAM_INT, 'group id', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), | |
667 | 'repeats' => new external_value(PARAM_INT, 'number of repeats', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), | |
668 | 'eventtype' => new external_value(PARAM_TEXT, 'Event type', VALUE_DEFAULT, 'user', NULL_NOT_ALLOWED), | |
669 | 'timestart' => new external_value(PARAM_INT, 'timestart', VALUE_DEFAULT, time(), NULL_NOT_ALLOWED), | |
670 | 'timeduration' => new external_value(PARAM_INT, 'time duration', VALUE_DEFAULT, 0, NULL_NOT_ALLOWED), | |
671 | 'visible' => new external_value(PARAM_INT, 'visible', VALUE_DEFAULT, 1, NULL_NOT_ALLOWED), | |
672 | 'sequence' => new external_value(PARAM_INT, 'sequence', VALUE_DEFAULT, 1, NULL_NOT_ALLOWED), | |
673 | ), 'event') | |
674 | ) | |
675 | ) | |
676 | ); | |
677 | } | |
678 | ||
679 | /** | |
1db417c2 | 680 | * Create calendar events. |
494a6389 AA |
681 | * |
682 | * @param array $events A list of events to create. | |
683 | * @return array array of events created. | |
684 | * @since Moodle 2.5 | |
685 | * @throws moodle_exception if user doesnt have the permission to create events. | |
686 | */ | |
687 | public static function create_calendar_events($events) { | |
2aad6b82 | 688 | global $DB, $USER; |
494a6389 AA |
689 | |
690 | // Parameter validation. | |
691 | $params = self::validate_parameters(self::create_calendar_events_parameters(), array('events' => $events)); | |
692 | ||
693 | $transaction = $DB->start_delegated_transaction(); | |
694 | $return = array(); | |
695 | $warnings = array(); | |
696 | ||
697 | foreach ($params['events'] as $event) { | |
698 | ||
699 | // Let us set some defaults. | |
700 | $event['userid'] = $USER->id; | |
701 | $event['modulename'] = ''; | |
702 | $event['instance'] = 0; | |
703 | $event['subscriptionid'] = null; | |
704 | $event['uuid']= ''; | |
705 | $event['format'] = external_validate_format($event['format']); | |
706 | if ($event['repeats'] > 0) { | |
707 | $event['repeat'] = 1; | |
708 | } else { | |
709 | $event['repeat'] = 0; | |
710 | } | |
711 | ||
e1cd93ce | 712 | $eventobj = new calendar_event($event); |
494a6389 AA |
713 | |
714 | // Let's check if the user is allowed to delete an event. | |
23a29de7 | 715 | if (!calendar_add_event_allowed($eventobj)) { |
38e4fa58 | 716 | $warnings [] = array('item' => $event['name'], 'warningcode' => 'nopermissions', 'message' => 'you do not have permissions to create this event'); |
494a6389 AA |
717 | continue; |
718 | } | |
719 | // Let's create the event. | |
720 | $var = $eventobj->create($event); | |
721 | $var = (array)$var->properties(); | |
722 | if ($event['repeat']) { | |
723 | $children = $DB->get_records('event', array('repeatid' => $var['id'])); | |
724 | foreach ($children as $child) { | |
725 | $return[] = (array) $child; | |
726 | } | |
727 | } else { | |
728 | $return[] = $var; | |
729 | } | |
730 | } | |
731 | ||
732 | // Everything done smoothly, let's commit. | |
733 | $transaction->allow_commit(); | |
734 | return array('events' => $return, 'warnings' => $warnings); | |
735 | } | |
736 | ||
737 | /** | |
738 | * Returns description of method result value. | |
739 | * | |
740 | * @return external_description. | |
741 | * @since Moodle 2.5 | |
742 | */ | |
743 | public static function create_calendar_events_returns() { | |
744 | return new external_single_structure( | |
745 | array( | |
746 | 'events' => new external_multiple_structure( new external_single_structure( | |
747 | array( | |
748 | 'id' => new external_value(PARAM_INT, 'event id'), | |
8c84eeee | 749 | 'name' => new external_value(PARAM_RAW, 'event name'), |
494a6389 AA |
750 | 'description' => new external_value(PARAM_RAW, 'Description', VALUE_OPTIONAL), |
751 | 'format' => new external_format_value('description'), | |
752 | 'courseid' => new external_value(PARAM_INT, 'course id'), | |
753 | 'groupid' => new external_value(PARAM_INT, 'group id'), | |
754 | 'userid' => new external_value(PARAM_INT, 'user id'), | |
755 | 'repeatid' => new external_value(PARAM_INT, 'repeat id', VALUE_OPTIONAL), | |
756 | 'modulename' => new external_value(PARAM_TEXT, 'module name', VALUE_OPTIONAL), | |
757 | 'instance' => new external_value(PARAM_INT, 'instance id'), | |
758 | 'eventtype' => new external_value(PARAM_TEXT, 'Event type'), | |
759 | 'timestart' => new external_value(PARAM_INT, 'timestart'), | |
760 | 'timeduration' => new external_value(PARAM_INT, 'time duration'), | |
761 | 'visible' => new external_value(PARAM_INT, 'visible'), | |
762 | 'uuid' => new external_value(PARAM_TEXT, 'unique id of ical events', VALUE_OPTIONAL, '', NULL_NOT_ALLOWED), | |
763 | 'sequence' => new external_value(PARAM_INT, 'sequence'), | |
764 | 'timemodified' => new external_value(PARAM_INT, 'time modified'), | |
765 | 'subscriptionid' => new external_value(PARAM_INT, 'Subscription id', VALUE_OPTIONAL), | |
766 | ), 'event') | |
767 | ), | |
768 | 'warnings' => new external_warnings() | |
769 | ) | |
770 | ); | |
771 | } | |
5813d1b9 SL |
772 | |
773 | /** | |
774 | * Returns description of method parameters. | |
775 | * | |
776 | * @return external_function_parameters | |
777 | */ | |
778 | public static function get_calendar_event_by_id_parameters() { | |
779 | return new external_function_parameters( | |
780 | array( | |
781 | 'eventid' => new external_value(PARAM_INT, 'The event id to be retrieved'), | |
782 | ) | |
783 | ); | |
784 | } | |
695c5726 | 785 | |
5813d1b9 SL |
786 | /** |
787 | * Get calendar event by id. | |
788 | * | |
789 | * @param int $eventid The calendar event id to be retrieved. | |
790 | * @return array Array of event details | |
791 | */ | |
792 | public static function get_calendar_event_by_id($eventid) { | |
2aad6b82 | 793 | global $PAGE, $USER; |
5813d1b9 | 794 | |
e20752c4 | 795 | $params = self::validate_parameters(self::get_calendar_event_by_id_parameters(), ['eventid' => $eventid]); |
6fb75156 | 796 | $context = \context_user::instance($USER->id); |
5813d1b9 | 797 | |
6fb75156 | 798 | self::validate_context($context); |
5813d1b9 SL |
799 | $warnings = array(); |
800 | ||
1a972b06 MG |
801 | $eventvault = event_container::get_event_vault(); |
802 | if ($event = $eventvault->get_event_by_id($eventid)) { | |
803 | $mapper = event_container::get_event_mapper(); | |
804 | if (!calendar_view_event_allowed($mapper->from_event_to_legacy_event($event))) { | |
805 | $event = null; | |
806 | } | |
807 | } | |
808 | ||
809 | if (!$event) { | |
af25b8fc DW |
810 | // We can't return a warning in this case because the event is not optional. |
811 | // We don't know the context for the event and it's not worth loading it. | |
812 | $syscontext = context_system::instance(); | |
813 | throw new \required_capability_exception($syscontext, 'moodle/course:view', 'nopermission', ''); | |
814 | } | |
815 | ||
6fb75156 SL |
816 | $cache = new events_related_objects_cache([$event]); |
817 | $relatedobjects = [ | |
818 | 'context' => $cache->get_context($event), | |
819 | 'course' => $cache->get_course($event), | |
820 | ]; | |
57d5b1b7 | 821 | |
6fb75156 SL |
822 | $exporter = new event_exporter($event, $relatedobjects); |
823 | $renderer = $PAGE->get_renderer('core_calendar'); | |
824 | ||
825 | return array('event' => $exporter->export($renderer), 'warnings' => $warnings); | |
5813d1b9 SL |
826 | } |
827 | ||
828 | /** | |
829 | * Returns description of method result value | |
830 | * | |
831 | * @return external_description | |
832 | */ | |
695c5726 | 833 | public static function get_calendar_event_by_id_returns() { |
6fb75156 | 834 | $eventstructure = event_exporter::get_read_structure(); |
5813d1b9 SL |
835 | |
836 | return new external_single_structure(array( | |
6fb75156 | 837 | 'event' => $eventstructure, |
5813d1b9 SL |
838 | 'warnings' => new external_warnings() |
839 | ) | |
840 | ); | |
841 | } | |
aa091225 RW |
842 | |
843 | /** | |
844 | * Returns description of method parameters. | |
845 | * | |
846 | * @return external_function_parameters. | |
847 | */ | |
848 | public static function submit_create_update_form_parameters() { | |
849 | return new external_function_parameters( | |
850 | [ | |
851 | 'formdata' => new external_value(PARAM_RAW, 'The data from the event form'), | |
852 | ] | |
853 | ); | |
854 | } | |
855 | ||
856 | /** | |
857 | * Handles the event form submission. | |
858 | * | |
859 | * @param string $formdata The event form data in a URI encoded param string | |
860 | * @return array The created or modified event | |
861 | * @throws moodle_exception | |
862 | */ | |
863 | public static function submit_create_update_form($formdata) { | |
2aad6b82 | 864 | global $USER, $PAGE, $CFG; |
ea5f7707 | 865 | require_once($CFG->libdir."/filelib.php"); |
aa091225 RW |
866 | |
867 | // Parameter validation. | |
868 | $params = self::validate_parameters(self::submit_create_update_form_parameters(), ['formdata' => $formdata]); | |
869 | $context = \context_user::instance($USER->id); | |
870 | $data = []; | |
871 | ||
872 | self::validate_context($context); | |
873 | parse_str($params['formdata'], $data); | |
874 | ||
bb0ce479 JL |
875 | if (WS_SERVER) { |
876 | // Request via WS, ignore sesskey checks in form library. | |
877 | $USER->ignoresesskey = true; | |
878 | } | |
879 | ||
dfc609e5 SL |
880 | $eventtype = isset($data['eventtype']) ? $data['eventtype'] : null; |
881 | $coursekey = ($eventtype == 'group') ? 'groupcourseid' : 'courseid'; | |
882 | $courseid = (!empty($data[$coursekey])) ? $data[$coursekey] : null; | |
883 | $editoroptions = \core_calendar\local\event\forms\create::build_editor_options($context); | |
884 | $formoptions = ['editoroptions' => $editoroptions, 'courseid' => $courseid]; | |
bcd0583e | 885 | $formoptions['eventtypes'] = calendar_get_allowed_event_types($courseid); |
dfc609e5 SL |
886 | if ($courseid) { |
887 | require_once($CFG->libdir . '/grouplib.php'); | |
888 | $groupcoursedata = groups_get_course_data($courseid); | |
889 | if (!empty($groupcoursedata->groups)) { | |
890 | $formoptions['groups'] = []; | |
891 | foreach ($groupcoursedata->groups as $groupid => $groupdata) { | |
892 | $formoptions['groups'][$groupid] = $groupdata->name; | |
893 | } | |
894 | } | |
895 | } | |
896 | ||
aa091225 RW |
897 | if (!empty($data['id'])) { |
898 | $eventid = clean_param($data['id'], PARAM_INT); | |
899 | $legacyevent = calendar_event::load($eventid); | |
900 | $legacyevent->count_repeats(); | |
dfc609e5 | 901 | $formoptions['event'] = $legacyevent; |
aa091225 RW |
902 | $mform = new update_event_form(null, $formoptions, 'post', '', null, true, $data); |
903 | } else { | |
904 | $legacyevent = null; | |
dfc609e5 | 905 | $mform = new create_event_form(null, $formoptions, 'post', '', null, true, $data); |
aa091225 RW |
906 | } |
907 | ||
908 | if ($validateddata = $mform->get_data()) { | |
909 | $formmapper = new create_update_form_mapper(); | |
910 | $properties = $formmapper->from_data_to_event_properties($validateddata); | |
911 | ||
912 | if (is_null($legacyevent)) { | |
913 | $legacyevent = new \calendar_event($properties); | |
6cb58071 RW |
914 | // Need to do this in order to initialise the description |
915 | // property which then triggers the update function below | |
916 | // to set the appropriate default properties on the event. | |
917 | $properties = $legacyevent->properties(true); | |
aa091225 RW |
918 | } |
919 | ||
909d0858 RW |
920 | if (!calendar_edit_event_allowed($legacyevent, true)) { |
921 | print_error('nopermissiontoupdatecalendar'); | |
922 | } | |
923 | ||
aa091225 | 924 | $legacyevent->update($properties); |
ea5f7707 RW |
925 | $eventcontext = $legacyevent->context; |
926 | ||
927 | file_remove_editor_orphaned_files($validateddata->description); | |
928 | ||
929 | // Take any files added to the description draft file area and | |
930 | // convert them into the proper event description file area. Also | |
931 | // parse the description text and replace the URLs to the draft files | |
932 | // with the @@PLUGIN_FILE@@ placeholder to be persisted in the DB. | |
933 | $description = file_save_draft_area_files( | |
934 | $validateddata->description['itemid'], | |
935 | $eventcontext->id, | |
936 | 'calendar', | |
937 | 'event_description', | |
938 | $legacyevent->id, | |
939 | create_event_form::build_editor_options($eventcontext), | |
940 | $validateddata->description['text'] | |
941 | ); | |
942 | ||
943 | // If draft files were found then we need to save the new | |
944 | // description value. | |
945 | if ($description != $validateddata->description['text']) { | |
946 | $properties->id = $legacyevent->id; | |
947 | $properties->description = $description; | |
948 | $legacyevent->update($properties); | |
949 | } | |
aa091225 RW |
950 | |
951 | $eventmapper = event_container::get_event_mapper(); | |
952 | $event = $eventmapper->from_legacy_event_to_event($legacyevent); | |
953 | $cache = new events_related_objects_cache([$event]); | |
954 | $relatedobjects = [ | |
955 | 'context' => $cache->get_context($event), | |
956 | 'course' => $cache->get_course($event), | |
957 | ]; | |
958 | $exporter = new event_exporter($event, $relatedobjects); | |
959 | $renderer = $PAGE->get_renderer('core_calendar'); | |
960 | ||
961 | return [ 'event' => $exporter->export($renderer) ]; | |
962 | } else { | |
963 | return [ 'validationerror' => true ]; | |
964 | } | |
965 | } | |
966 | ||
967 | /** | |
968 | * Returns description of method result value. | |
969 | * | |
970 | * @return external_description. | |
971 | */ | |
972 | public static function submit_create_update_form_returns() { | |
973 | $eventstructure = event_exporter::get_read_structure(); | |
974 | $eventstructure->required = VALUE_OPTIONAL; | |
975 | ||
976 | return new external_single_structure( | |
977 | array( | |
978 | 'event' => $eventstructure, | |
979 | 'validationerror' => new external_value(PARAM_BOOL, 'Invalid form data', VALUE_DEFAULT, false), | |
980 | ) | |
981 | ); | |
982 | } | |
695c5726 AN |
983 | |
984 | /** | |
985 | * Get data for the monthly calendar view. | |
986 | * | |
f58424c7 AN |
987 | * @param int $year The year to be shown |
988 | * @param int $month The month to be shown | |
695c5726 | 989 | * @param int $courseid The course to be included |
d0e56d84 | 990 | * @param int $categoryid The category to be included |
fee025ec | 991 | * @param bool $includenavigation Whether to include navigation |
60908b21 | 992 | * @param bool $mini Whether to return the mini month view or not |
f046b703 | 993 | * @param int $day The day we want to keep as the current day |
695c5726 AN |
994 | * @return array |
995 | */ | |
f046b703 SR |
996 | public static function get_calendar_monthly_view($year, $month, $courseid, $categoryid, $includenavigation, $mini, $day) { |
997 | global $USER, $PAGE; | |
695c5726 | 998 | |
695c5726 AN |
999 | // Parameter validation. |
1000 | $params = self::validate_parameters(self::get_calendar_monthly_view_parameters(), [ | |
f58424c7 AN |
1001 | 'year' => $year, |
1002 | 'month' => $month, | |
695c5726 | 1003 | 'courseid' => $courseid, |
d0e56d84 | 1004 | 'categoryid' => $categoryid, |
fee025ec | 1005 | 'includenavigation' => $includenavigation, |
60908b21 | 1006 | 'mini' => $mini, |
f046b703 | 1007 | 'day' => $day, |
695c5726 AN |
1008 | ]); |
1009 | ||
d0e56d84 AN |
1010 | $context = \context_user::instance($USER->id); |
1011 | self::validate_context($context); | |
d097bfdd | 1012 | $PAGE->set_url('/calendar/'); |
d0e56d84 | 1013 | |
f58424c7 AN |
1014 | $type = \core_calendar\type_factory::get_calendar_instance(); |
1015 | ||
f046b703 | 1016 | $time = $type->convert_to_timestamp($params['year'], $params['month'], $params['day']); |
6607c5ff AN |
1017 | $calendar = \calendar_information::create($time, $params['courseid'], $params['categoryid']); |
1018 | self::validate_context($calendar->context); | |
695c5726 | 1019 | |
60908b21 RW |
1020 | $view = $params['mini'] ? 'mini' : 'month'; |
1021 | list($data, $template) = calendar_get_view($calendar, $view, $params['includenavigation']); | |
695c5726 AN |
1022 | |
1023 | return $data; | |
1024 | } | |
1025 | ||
1026 | /** | |
1027 | * Returns description of method parameters. | |
1028 | * | |
1029 | * @return external_function_parameters | |
1030 | */ | |
1031 | public static function get_calendar_monthly_view_parameters() { | |
1032 | return new external_function_parameters( | |
1033 | [ | |
316412be SL |
1034 | 'year' => new external_value(PARAM_INT, 'Year to be viewed', VALUE_REQUIRED), |
1035 | 'month' => new external_value(PARAM_INT, 'Month to be viewed', VALUE_REQUIRED), | |
695c5726 | 1036 | 'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED), |
d0e56d84 | 1037 | 'categoryid' => new external_value(PARAM_INT, 'Category being viewed', VALUE_DEFAULT, null, NULL_ALLOWED), |
fee025ec AN |
1038 | 'includenavigation' => new external_value( |
1039 | PARAM_BOOL, | |
1040 | 'Whether to show course navigation', | |
1041 | VALUE_DEFAULT, | |
1042 | true, | |
1043 | NULL_ALLOWED | |
1044 | ), | |
60908b21 RW |
1045 | 'mini' => new external_value( |
1046 | PARAM_BOOL, | |
1047 | 'Whether to return the mini month view or not', | |
1048 | VALUE_DEFAULT, | |
1049 | false, | |
1050 | NULL_ALLOWED | |
1051 | ), | |
f046b703 | 1052 | 'day' => new external_value(PARAM_INT, 'Day to be viewed', VALUE_DEFAULT, 1), |
695c5726 AN |
1053 | ] |
1054 | ); | |
1055 | } | |
1056 | ||
1057 | /** | |
1058 | * Returns description of method result value. | |
1059 | * | |
1060 | * @return external_description | |
1061 | */ | |
1062 | public static function get_calendar_monthly_view_returns() { | |
1063 | return \core_calendar\external\month_exporter::get_read_structure(); | |
1064 | } | |
c6fb9310 | 1065 | |
3ea4f446 AN |
1066 | /** |
1067 | * Get data for the daily calendar view. | |
1068 | * | |
1069 | * @param int $year The year to be shown | |
1070 | * @param int $month The month to be shown | |
1071 | * @param int $day The day to be shown | |
1072 | * @param int $courseid The course to be included | |
1073 | * @return array | |
1074 | */ | |
1075 | public static function get_calendar_day_view($year, $month, $day, $courseid, $categoryid) { | |
2aad6b82 | 1076 | global $DB, $USER, $PAGE; |
3ea4f446 AN |
1077 | |
1078 | // Parameter validation. | |
1079 | $params = self::validate_parameters(self::get_calendar_day_view_parameters(), [ | |
1080 | 'year' => $year, | |
1081 | 'month' => $month, | |
1082 | 'day' => $day, | |
1083 | 'courseid' => $courseid, | |
1084 | 'categoryid' => $categoryid, | |
1085 | ]); | |
1086 | ||
3ea4f446 AN |
1087 | $context = \context_user::instance($USER->id); |
1088 | self::validate_context($context); | |
1089 | ||
1090 | $type = \core_calendar\type_factory::get_calendar_instance(); | |
1091 | ||
6607c5ff AN |
1092 | $time = $type->convert_to_timestamp($params['year'], $params['month'], $params['day']); |
1093 | $calendar = \calendar_information::create($time, $params['courseid'], $params['categoryid']); | |
1094 | self::validate_context($calendar->context); | |
3ea4f446 | 1095 | |
af25b8fc | 1096 | list($data, $template) = calendar_get_view($calendar, 'day'); |
3ea4f446 AN |
1097 | |
1098 | return $data; | |
1099 | } | |
1100 | ||
1101 | /** | |
1102 | * Returns description of method parameters. | |
1103 | * | |
1104 | * @return external_function_parameters | |
1105 | */ | |
1106 | public static function get_calendar_day_view_parameters() { | |
1107 | return new external_function_parameters( | |
1108 | [ | |
1109 | 'year' => new external_value(PARAM_INT, 'Year to be viewed', VALUE_REQUIRED), | |
1110 | 'month' => new external_value(PARAM_INT, 'Month to be viewed', VALUE_REQUIRED), | |
1111 | 'day' => new external_value(PARAM_INT, 'Day to be viewed', VALUE_REQUIRED), | |
1112 | 'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED), | |
1113 | 'categoryid' => new external_value(PARAM_INT, 'Category being viewed', VALUE_DEFAULT, null, NULL_ALLOWED), | |
1114 | ] | |
1115 | ); | |
1116 | } | |
1117 | ||
1118 | /** | |
1119 | * Returns description of method result value. | |
1120 | * | |
1121 | * @return external_description | |
1122 | */ | |
1123 | public static function get_calendar_day_view_returns() { | |
1124 | return \core_calendar\external\calendar_day_exporter::get_read_structure(); | |
1125 | } | |
1126 | ||
1127 | ||
c6fb9310 RW |
1128 | /** |
1129 | * Returns description of method parameters. | |
1130 | * | |
1131 | * @return external_function_parameters | |
1132 | */ | |
1133 | public static function update_event_start_day_parameters() { | |
1134 | return new external_function_parameters( | |
1135 | [ | |
96283892 RW |
1136 | 'eventid' => new external_value(PARAM_INT, 'Id of event to be updated', VALUE_REQUIRED), |
1137 | 'daytimestamp' => new external_value(PARAM_INT, 'Timestamp for the new start day', VALUE_REQUIRED), | |
c6fb9310 RW |
1138 | ] |
1139 | ); | |
1140 | } | |
1141 | ||
1142 | /** | |
1143 | * Change the start day for the given calendar event to the day that | |
1144 | * corresponds with the provided timestamp. | |
1145 | * | |
1146 | * The timestamp only needs to be anytime within the desired day as only | |
1147 | * the date data is extracted from it. | |
1148 | * | |
1149 | * The event's original time of day is maintained, only the date is shifted. | |
1150 | * | |
96283892 RW |
1151 | * @param int $eventid Id of event to be updated |
1152 | * @param int $daytimestamp Timestamp for the new start day | |
c6fb9310 RW |
1153 | * @return array |
1154 | */ | |
96283892 | 1155 | public static function update_event_start_day($eventid, $daytimestamp) { |
c6fb9310 RW |
1156 | global $USER, $PAGE; |
1157 | ||
1158 | // Parameter validation. | |
1159 | $params = self::validate_parameters(self::update_event_start_day_parameters(), [ | |
96283892 RW |
1160 | 'eventid' => $eventid, |
1161 | 'daytimestamp' => $daytimestamp, | |
c6fb9310 RW |
1162 | ]); |
1163 | ||
c6fb9310 | 1164 | $vault = event_container::get_event_vault(); |
909d0858 | 1165 | $mapper = event_container::get_event_mapper(); |
96283892 | 1166 | $event = $vault->get_event_by_id($eventid); |
909d0858 RW |
1167 | |
1168 | if (!$event) { | |
96283892 | 1169 | throw new \moodle_exception('Unable to find event with id ' . $eventid); |
909d0858 RW |
1170 | } |
1171 | ||
1172 | $legacyevent = $mapper->from_event_to_legacy_event($event); | |
1173 | ||
1174 | if (!calendar_edit_event_allowed($legacyevent, true)) { | |
1175 | print_error('nopermissiontoupdatecalendar'); | |
1176 | } | |
1177 | ||
ca518350 RW |
1178 | self::validate_context($legacyevent->context); |
1179 | ||
96283892 | 1180 | $newdate = usergetdate($daytimestamp); |
c6fb9310 RW |
1181 | $startdatestring = implode('-', [$newdate['year'], $newdate['mon'], $newdate['mday']]); |
1182 | $startdate = new DateTimeImmutable($startdatestring); | |
1183 | $event = local_api::update_event_start_day($event, $startdate); | |
1184 | $cache = new events_related_objects_cache([$event]); | |
1185 | $relatedobjects = [ | |
1186 | 'context' => $cache->get_context($event), | |
1187 | 'course' => $cache->get_course($event), | |
1188 | ]; | |
1189 | $exporter = new event_exporter($event, $relatedobjects); | |
1190 | $renderer = $PAGE->get_renderer('core_calendar'); | |
1191 | ||
1192 | return array('event' => $exporter->export($renderer)); | |
1193 | } | |
1194 | ||
1195 | /** | |
1196 | * Returns description of method result value. | |
1197 | * | |
1198 | * @return external_description | |
1199 | */ | |
1200 | public static function update_event_start_day_returns() { | |
1201 | return new external_single_structure( | |
1202 | array( | |
1203 | 'event' => event_exporter::get_read_structure() | |
1204 | ) | |
1205 | ); | |
1206 | } | |
e8306438 SL |
1207 | |
1208 | /** | |
1209 | * Get data for the monthly calendar view. | |
1210 | * | |
1211 | * @param int $courseid The course to be included | |
7f14def2 | 1212 | * @param int $categoryid The category to be included |
e8306438 SL |
1213 | * @return array |
1214 | */ | |
7f14def2 | 1215 | public static function get_calendar_upcoming_view($courseid, $categoryid) { |
2aad6b82 | 1216 | global $DB, $USER, $PAGE; |
e8306438 SL |
1217 | |
1218 | // Parameter validation. | |
6607c5ff | 1219 | $params = self::validate_parameters(self::get_calendar_upcoming_view_parameters(), [ |
e8306438 | 1220 | 'courseid' => $courseid, |
d523cbcb | 1221 | 'categoryid' => $categoryid, |
e8306438 | 1222 | ]); |
e8306438 SL |
1223 | |
1224 | $context = \context_user::instance($USER->id); | |
1225 | self::validate_context($context); | |
6607c5ff | 1226 | $PAGE->set_url('/calendar/'); |
e8306438 | 1227 | |
6607c5ff AN |
1228 | $calendar = \calendar_information::create(time(), $params['courseid'], $params['categoryid']); |
1229 | self::validate_context($calendar->context); | |
e8306438 SL |
1230 | |
1231 | list($data, $template) = calendar_get_view($calendar, 'upcoming'); | |
1232 | ||
1233 | return $data; | |
1234 | } | |
1235 | ||
1236 | /** | |
1237 | * Returns description of method parameters. | |
1238 | * | |
1239 | * @return external_function_parameters | |
1240 | */ | |
1241 | public static function get_calendar_upcoming_view_parameters() { | |
1242 | return new external_function_parameters( | |
1243 | [ | |
1244 | 'courseid' => new external_value(PARAM_INT, 'Course being viewed', VALUE_DEFAULT, SITEID, NULL_ALLOWED), | |
d523cbcb | 1245 | 'categoryid' => new external_value(PARAM_INT, 'Category being viewed', VALUE_DEFAULT, null, NULL_ALLOWED), |
e8306438 SL |
1246 | ] |
1247 | ); | |
1248 | } | |
1249 | ||
1250 | /** | |
1251 | * Returns description of method result value. | |
1252 | * | |
1253 | * @return external_description | |
1254 | */ | |
1255 | public static function get_calendar_upcoming_view_returns() { | |
1256 | return \core_calendar\external\calendar_upcoming_exporter::get_read_structure(); | |
1257 | } | |
a46980fa JL |
1258 | |
1259 | ||
1260 | /** | |
1261 | * Returns description of method parameters. | |
1262 | * | |
1263 | * @return external_function_parameters. | |
1264 | * @since Moodle 3.7 | |
1265 | */ | |
1266 | public static function get_calendar_access_information_parameters() { | |
1267 | return new external_function_parameters( | |
1268 | [ | |
1269 | 'courseid' => new external_value(PARAM_INT, 'Course to check, empty for site calendar events.', VALUE_DEFAULT, 0), | |
1270 | ] | |
1271 | ); | |
1272 | } | |
1273 | ||
1274 | /** | |
1275 | * Convenience function to retrieve some permissions information for the given course calendar. | |
1276 | * | |
1277 | * @param int $courseid Course to check, empty for site. | |
1278 | * @return array The access information | |
1279 | * @throws moodle_exception | |
1280 | * @since Moodle 3.7 | |
1281 | */ | |
1282 | public static function get_calendar_access_information($courseid = 0) { | |
1283 | ||
1284 | $params = self::validate_parameters(self::get_calendar_access_information_parameters(), ['courseid' => $courseid]); | |
1285 | ||
1286 | if (empty($params['courseid']) || $params['courseid'] == SITEID) { | |
1287 | $context = \context_system::instance(); | |
1288 | } else { | |
1289 | $context = \context_course::instance($params['courseid']); | |
1290 | } | |
1291 | ||
1292 | self::validate_context($context); | |
1293 | ||
1294 | return [ | |
1295 | 'canmanageentries' => has_capability('moodle/calendar:manageentries', $context), | |
1296 | 'canmanageownentries' => has_capability('moodle/calendar:manageownentries', $context), | |
1297 | 'canmanagegroupentries' => has_capability('moodle/calendar:managegroupentries', $context), | |
1298 | 'warnings' => [], | |
1299 | ]; | |
1300 | } | |
1301 | ||
1302 | /** | |
1303 | * Returns description of method result value. | |
1304 | * | |
1305 | * @return external_description. | |
1306 | * @since Moodle 3.7 | |
1307 | */ | |
1308 | public static function get_calendar_access_information_returns() { | |
1309 | ||
1310 | return new external_single_structure( | |
1311 | [ | |
1312 | 'canmanageentries' => new external_value(PARAM_BOOL, 'Whether the user can manage entries.'), | |
1313 | 'canmanageownentries' => new external_value(PARAM_BOOL, 'Whether the user can manage its own entries.'), | |
1314 | 'canmanagegroupentries' => new external_value(PARAM_BOOL, 'Whether the user can manage group entries.'), | |
1315 | 'warnings' => new external_warnings(), | |
1316 | ] | |
1317 | ); | |
1318 | } | |
2aad6b82 JL |
1319 | |
1320 | /** | |
1321 | * Returns description of method parameters. | |
1322 | * | |
1323 | * @return external_function_parameters. | |
1324 | * @since Moodle 3.7 | |
1325 | */ | |
1326 | public static function get_allowed_event_types_parameters() { | |
1327 | return new external_function_parameters( | |
1328 | [ | |
1329 | 'courseid' => new external_value(PARAM_INT, 'Course to check, empty for site.', VALUE_DEFAULT, 0), | |
1330 | ] | |
1331 | ); | |
1332 | } | |
1333 | ||
1334 | /** | |
1335 | * Get the type of events a user can create in the given course. | |
1336 | * | |
1337 | * @param int $courseid Course to check, empty for site. | |
1338 | * @return array The types allowed | |
1339 | * @throws moodle_exception | |
1340 | * @since Moodle 3.7 | |
1341 | */ | |
1342 | public static function get_allowed_event_types($courseid = 0) { | |
1343 | ||
1344 | $params = self::validate_parameters(self::get_allowed_event_types_parameters(), ['courseid' => $courseid]); | |
1345 | ||
1346 | if (empty($params['courseid']) || $params['courseid'] == SITEID) { | |
1347 | $context = \context_system::instance(); | |
1348 | } else { | |
1349 | $context = \context_course::instance($params['courseid']); | |
1350 | } | |
1351 | ||
1352 | self::validate_context($context); | |
1353 | ||
1354 | $allowedeventtypes = array_filter(calendar_get_allowed_event_types($params['courseid'])); | |
1355 | ||
1356 | return [ | |
1357 | 'allowedeventtypes' => array_keys($allowedeventtypes), | |
1358 | 'warnings' => [], | |
1359 | ]; | |
1360 | } | |
1361 | ||
1362 | /** | |
1363 | * Returns description of method result value. | |
1364 | * | |
1365 | * @return external_description. | |
1366 | * @since Moodle 3.7 | |
1367 | */ | |
1368 | public static function get_allowed_event_types_returns() { | |
1369 | ||
1370 | return new external_single_structure( | |
1371 | [ | |
1372 | 'allowedeventtypes' => new external_multiple_structure( | |
1373 | new external_value(PARAM_NOTAGS, 'Allowed event types to be created in the given course.') | |
1374 | ), | |
1375 | 'warnings' => new external_warnings(), | |
1376 | ] | |
1377 | ); | |
1378 | } | |
23affd76 MH |
1379 | |
1380 | /** | |
1381 | * Convert the specified dates into unix timestamps. | |
1382 | * | |
1383 | * @param array $datetimes Array of arrays containing date time details, each in the format: | |
1384 | * ['year' => a, 'month' => b, 'day' => c, | |
1385 | * 'hour' => d (optional), 'minute' => e (optional), 'key' => 'x' (optional)] | |
1386 | * @return array Provided array of dates converted to unix timestamps | |
1387 | * @throws moodle_exception If one or more of the dates provided does not convert to a valid timestamp. | |
1388 | */ | |
1389 | public static function get_timestamps($datetimes) { | |
1390 | $params = self::validate_parameters(self::get_timestamps_parameters(), ['data' => $datetimes]); | |
1391 | ||
1392 | $type = \core_calendar\type_factory::get_calendar_instance(); | |
1393 | $timestamps = ['timestamps' => []]; | |
1394 | ||
1395 | foreach ($params['data'] as $key => $datetime) { | |
1396 | $hour = $datetime['hour'] ?? 0; | |
1397 | $minute = $datetime['minute'] ?? 0; | |
1398 | ||
1399 | try { | |
1400 | $timestamp = $type->convert_to_timestamp( | |
1401 | $datetime['year'], $datetime['month'], $datetime['day'], $hour, $minute); | |
1402 | ||
1403 | $timestamps['timestamps'][] = [ | |
1404 | 'key' => $datetime['key'] ?? $key, | |
1405 | 'timestamp' => $timestamp, | |
1406 | ]; | |
1407 | ||
1408 | } catch (Exception $e) { | |
1409 | throw new moodle_exception('One or more of the dates provided were invalid'); | |
1410 | } | |
1411 | } | |
1412 | ||
1413 | return $timestamps; | |
1414 | } | |
1415 | ||
1416 | /** | |
1417 | * Describes the parameters for get_timestamps. | |
1418 | * | |
1419 | * @return external_function_parameters | |
1420 | */ | |
1421 | public static function get_timestamps_parameters() { | |
1422 | return new external_function_parameters ([ | |
1423 | 'data' => new external_multiple_structure( | |
1424 | new external_single_structure( | |
1425 | [ | |
1426 | 'key' => new external_value(PARAM_ALPHANUMEXT, 'key', VALUE_OPTIONAL), | |
1427 | 'year' => new external_value(PARAM_INT, 'year'), | |
1428 | 'month' => new external_value(PARAM_INT, 'month'), | |
1429 | 'day' => new external_value(PARAM_INT, 'day'), | |
1430 | 'hour' => new external_value(PARAM_INT, 'hour', VALUE_OPTIONAL), | |
1431 | 'minute' => new external_value(PARAM_INT, 'minute', VALUE_OPTIONAL), | |
1432 | ] | |
1433 | ) | |
1434 | ) | |
1435 | ]); | |
1436 | } | |
1437 | ||
1438 | /** | |
1439 | * Describes the timestamps return format. | |
1440 | * | |
1441 | * @return external_single_structure | |
1442 | */ | |
1443 | public static function get_timestamps_returns() { | |
1444 | return new external_single_structure( | |
1445 | [ | |
1446 | 'timestamps' => new external_multiple_structure( | |
1447 | new external_single_structure( | |
1448 | [ | |
1449 | 'key' => new external_value(PARAM_ALPHANUMEXT, 'Timestamp key'), | |
1450 | 'timestamp' => new external_value(PARAM_INT, 'Unix timestamp'), | |
1451 | ] | |
1452 | ) | |
1453 | ) | |
1454 | ] | |
1455 | ); | |
1456 | } | |
01bea07d | 1457 | } |