MDL-37624 calendar: Added location support
[moodle.git] / calendar / classes / local / api.php
CommitLineData
392d6a49
RW
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 * Contains class containing the internal calendar API.
19 *
20 * @package core_calendar
21 * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25namespace core_calendar\local;
26
27defined('MOODLE_INTERNAL') || die();
28
55f5fcb9
RW
29use core_calendar\local\event\container;
30use core_calendar\local\event\entities\event_interface;
e62cd85f
RW
31use core_calendar\local\event\exceptions\limit_invalid_parameter_exception;
32
392d6a49
RW
33/**
34 * Class containing the local calendar API.
35 *
2229368a
MN
36 * This should not be used outside of core_calendar.
37 *
392d6a49
RW
38 * @package core_calendar
39 * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 */
42class api {
258a5705
CB
43 /**
44 * Get all events restricted by various parameters, taking in to account user and group overrides.
45 *
20592f5f
JP
46 * @param int|null $timestartfrom Events with timestart from this value (inclusive).
47 * @param int|null $timestartto Events with timestart until this value (inclusive).
48 * @param int|null $timesortfrom Events with timesort from this value (inclusive).
49 * @param int|null $timesortto Events with timesort until this value (inclusive).
50 * @param int|null $timestartaftereventid Restrict the events in the timestart range to ones after this ID.
51 * @param int|null $timesortaftereventid Restrict the events in the timesort range to ones after this ID.
52 * @param int $limitnum Return at most this number of events.
53 * @param int|null $type Return only events of this type.
54 * @param array|null $usersfilter Return only events for these users.
55 * @param array|null $groupsfilter Return only events for these groups.
56 * @param array|null $coursesfilter Return only events for these courses.
57 * @param bool $withduration If true return only events starting within specified
58 * timestart otherwise return in progress events as well.
59 * @param bool $ignorehidden If true don't return hidden events.
42e76c3f 60 * @return \core_calendar\local\event\entities\event_interface[] Array of event_interfaces.
258a5705
CB
61 */
62 public static function get_events(
63 $timestartfrom = null,
64 $timestartto = null,
65 $timesortfrom = null,
66 $timesortto = null,
67 $timestartaftereventid = null,
68 $timesortaftereventid = null,
69 $limitnum = 20,
70 $type = null,
71 array $usersfilter = null,
72 array $groupsfilter = null,
73 array $coursesfilter = null,
0085b0ea 74 array $categoriesfilter = null,
258a5705 75 $withduration = true,
7fe41af5
AN
76 $ignorehidden = true,
77 callable $filter = null
258a5705
CB
78 ) {
79 global $USER;
80
d10693cb 81 $vault = \core_calendar\local\event\container::get_event_vault();
258a5705
CB
82
83 $timestartafterevent = null;
84 $timesortafterevent = null;
85
86 if ($timestartaftereventid && $event = $vault->get_event_by_id($timestartaftereventid)) {
87 $timestartafterevent = $event;
88 }
89
90 if ($timesortaftereventid && $event = $vault->get_event_by_id($timesortaftereventid)) {
91 $timesortafterevent = $event;
92 }
93
94 return $vault->get_events(
95 $timestartfrom,
96 $timestartto,
97 $timesortfrom,
98 $timesortto,
99 $timestartafterevent,
100 $timesortafterevent,
101 $limitnum,
102 $type,
103 $usersfilter,
104 $groupsfilter,
105 $coursesfilter,
0085b0ea 106 $categoriesfilter,
258a5705 107 $withduration,
7fe41af5
AN
108 $ignorehidden,
109 $filter
258a5705
CB
110 );
111 }
392d6a49
RW
112
113 /**
114 * Get a list of action events for the logged in user by the given
115 * timesort values.
116 *
117 * @param int|null $timesortfrom The start timesort value (inclusive)
118 * @param int|null $timesortto The end timesort value (inclusive)
119 * @param int|null $aftereventid Only return events after this one
120 * @param int $limitnum Limit results to this amount (between 1 and 50)
121 * @return array A list of action_event_interface objects
20592f5f 122 * @throws \moodle_exception
392d6a49
RW
123 */
124 public static function get_action_events_by_timesort(
125 $timesortfrom = null,
126 $timesortto = null,
127 $aftereventid = null,
128 $limitnum = 20
129 ) {
130 global $USER;
131
132 if (is_null($timesortfrom) && is_null($timesortto)) {
133 throw new \moodle_exception("Must provide a timesort to and/or from value");
134 }
135
136 if ($limitnum < 1 || $limitnum > 50) {
137 throw new \moodle_exception("Limit must be between 1 and 50 (inclusive)");
138 }
139
d10693cb 140 $vault = \core_calendar\local\event\container::get_event_vault();
392d6a49
RW
141
142 $afterevent = null;
143 if ($aftereventid && $event = $vault->get_event_by_id($aftereventid)) {
144 $afterevent = $event;
145 }
146
147 return $vault->get_action_events_by_timesort($USER, $timesortfrom, $timesortto, $afterevent, $limitnum);
148 }
e62cd85f
RW
149
150 /**
151 * Get a list of action events for the logged in user by the given
152 * course and timesort values.
153 *
154 * @param \stdClass $course The course the events must belong to
155 * @param int|null $timesortfrom The start timesort value (inclusive)
156 * @param int|null $timesortto The end timesort value (inclusive)
157 * @param int|null $aftereventid Only return events after this one
158 * @param int $limitnum Limit results to this amount (between 1 and 50)
159 * @return array A list of action_event_interface objects
20592f5f 160 * @throws limit_invalid_parameter_exception
e62cd85f
RW
161 */
162 public static function get_action_events_by_course(
163 $course,
164 $timesortfrom = null,
165 $timesortto = null,
166 $aftereventid = null,
167 $limitnum = 20
168 ) {
169 global $USER;
170
171 if ($limitnum < 1 || $limitnum > 50) {
172 throw new limit_invalid_parameter_exception(
173 "Limit must be between 1 and 50 (inclusive)");
174 }
175
d10693cb 176 $vault = \core_calendar\local\event\container::get_event_vault();
e62cd85f
RW
177
178 $afterevent = null;
179 if ($aftereventid && $event = $vault->get_event_by_id($aftereventid)) {
180 $afterevent = $event;
181 }
182
183 return $vault->get_action_events_by_course(
184 $USER, $course, $timesortfrom, $timesortto, $afterevent, $limitnum);
185 }
8a082024
RW
186
187 /**
188 * Get a list of action events for the logged in user by the given
189 * courses and timesort values.
190 *
191 * The limit number applies per course, not for the result set as a whole.
192 * E.g. Requesting 3 courses with a limit of 10 will result in up to 30
193 * events being returned (up to 10 per course).
194 *
195 * @param array $courses The courses the events must belong to
196 * @param int|null $timesortfrom The start timesort value (inclusive)
197 * @param int|null $timesortto The end timesort value (inclusive)
198 * @param int $limitnum Limit results per course to this amount (between 1 and 50)
199 * @return array A list of action_event_interface objects indexed by course id
200 */
201 public static function get_action_events_by_courses(
202 $courses = [],
203 $timesortfrom = null,
204 $timesortto = null,
205 $limitnum = 20
206 ) {
207 $return = [];
208
209 foreach ($courses as $course) {
210 $return[$course->id] = self::get_action_events_by_course(
211 $course,
212 $timesortfrom,
213 $timesortto,
214 null,
215 $limitnum
216 );
217 }
218
219 return $return;
220 }
55f5fcb9
RW
221
222 /**
223 * Change the start day for an event. Only the date will be
224 * modified, the time of day for the event will be left as is.
225 *
226 * @param event_interface $event The existing event to modify
96283892 227 * @param DateTimeInterface $startdate The new date to use for the start day
55f5fcb9
RW
228 * @return event_interface The new event with updated start date
229 */
230 public static function update_event_start_day(
231 event_interface $event,
96283892 232 \DateTimeInterface $startdate
55f5fcb9 233 ) {
478b1d19
RW
234 global $DB;
235
55f5fcb9
RW
236 $mapper = container::get_event_mapper();
237 $legacyevent = $mapper->from_event_to_legacy_event($event);
39fe5929 238 $hascoursemodule = !empty($event->get_course_module());
478b1d19 239 $moduleinstance = null;
55f5fcb9 240 $starttime = $event->get_times()->get_start_time()->setDate(
96283892
RW
241 $startdate->format('Y'),
242 $startdate->format('n'),
243 $startdate->format('j')
55f5fcb9
RW
244 );
245
39fe5929 246 if ($hascoursemodule) {
478b1d19
RW
247 $moduleinstance = $DB->get_record(
248 $event->get_course_module()->get('modname'),
249 ['id' => $event->get_course_module()->get('instance')],
250 '*',
251 MUST_EXIST
252 );
39fe5929 253 $legacyevent->timestart = $starttime->getTimestamp();
478b1d19
RW
254
255 // If there is a timestart range callback implemented then we can
256 // use the values returned from the valid timestart range to apply
257 // some default validation on the event's timestart value to ensure
258 // that it falls within the specified range.
259 list($min, $max) = component_callback(
39fe5929 260 'mod_' . $event->get_course_module()->get('modname'),
478b1d19
RW
261 'core_calendar_get_valid_event_timestart_range',
262 [$legacyevent, $moduleinstance],
6688ae2b 263 [false, false]
39fe5929 264 );
478b1d19 265
6688ae2b
RW
266 // If the callback returns false for either value it means that
267 // there is no valid time start range.
268 if ($min === false || $max === false) {
269 throw new \moodle_exception('The start day of this event can not be modified');
270 }
271
478b1d19
RW
272 if ($min && $legacyevent->timestart < $min[0]) {
273 throw new \moodle_exception($min[1]);
274 }
275
276 if ($max && $legacyevent->timestart > $max[0]) {
277 throw new \moodle_exception($max[1]);
278 }
39fe5929
RW
279 }
280
55f5fcb9
RW
281 // This function does our capability checks.
282 $legacyevent->update((object) ['timestart' => $starttime->getTimestamp()]);
283
39fe5929
RW
284 // Check that the user is allowed to manually edit calendar events before
285 // calling the event updated callback. The manual flag causes the code to
286 // check the user has the capabilities to modify the modules.
287 //
288 // We don't want to call the event update callback if the user isn't allowed
289 // to modify course modules because depending on the callback it can make
290 // some changes that would be considered security issues, such as updating the
478b1d19 291 // due date for an assignment.
39fe5929
RW
292 if ($hascoursemodule && calendar_edit_event_allowed($legacyevent, true)) {
293 // If this event is from an activity then we need to call
294 // the activity callback to let it know that the event it
295 // created has been modified so it needs to update accordingly.
296 component_callback(
297 'mod_' . $event->get_course_module()->get('modname'),
298 'core_calendar_event_timestart_updated',
478b1d19 299 [$legacyevent, $moduleinstance]
39fe5929
RW
300 );
301 }
302
55f5fcb9
RW
303 return $mapper->from_legacy_event_to_event($legacyevent);
304 }
392d6a49 305}