> */ public function getCalendarsForUser($principalUri) { if (1 !== preg_match('/^principals\/(.*)$/', $principalUri, $matches)) { return []; } User::where('email', $matches[1])->firstOrFail(); return [ [ 'id' => 'birthdays', 'principaluri' => $principalUri, 'uri' => 'birthdays', '{DAV:}displayname' => 'Geburtstage', ], ]; } /** * Creates a new calendar for a principal. * * If the creation was a success, an id must be returned that can be used to * reference this calendar in other methods, such as updateCalendar. * * The id can be any type, including ints, strings, objects or array. * * @param string $principalUri * @param string $calendarUri * @param array $properties * * @return mixed */ public function createCalendar($principalUri, $calendarUri, array $properties) { } /** * Updates properties for a calendar. * * The list of mutations is stored in a Sabre\DAV\PropPatch object. * To do the actual updates, you must tell this object which properties * you're going to process with the handle() method. * * Calling the handle method is like telling the PropPatch object "I * promise I can handle updating this property". * * Read the PropPatch documentation for more info and examples. * * @param mixed $calendarId * @return void */ public function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch) { } /** * Delete a calendar and all its objects. * * @param mixed $calendarId * @return void */ public function deleteCalendar($calendarId) { } /** * Returns all calendar objects within a calendar. * * Every item contains an array with the following keys: * * calendardata - The iCalendar-compatible calendar data * * uri - a unique key which will be used to construct the uri. This can * be any arbitrary string, but making sure it ends with '.ics' is a * good idea. This is only the basename, or filename, not the full * path. * * lastmodified - a timestamp of the last modification time * * etag - An arbitrary string, surrounded by double-quotes. (e.g.: * '"abcdef"') * * size - The size of the calendar objects, in bytes. * * component - optional, a string containing the type of object, such * as 'vevent' or 'vtodo'. If specified, this will be used to populate * the Content-Type header. * * Note that the etag is optional, but it's highly encouraged to return for * speed reasons. * * The calendardata is also optional. If it's not returned * 'getCalendarObject' will be called later, which *is* expected to return * calendardata. * * If neither etag or size are specified, the calendardata will be * used/fetched to determine these numbers. If both are specified the * amount of times this is needed is reduced by a great degree. * * @param mixed $calendarId * * @return array * @return void */ public function getCalendarObjects($calendarId) { return Member::whereNotNull('birthday')->get()->map(fn ($member) => $this->calendarObjectMeta($member))->toArray(); } private function calendarObjectMeta(Member $member): array { return [ 'calendardata' => $member->toCalendarObject()->serialize(), 'uri' => $member->slug . '.ics', 'lastmodified' => $member->updated_at->timestamp, 'etag' => '"' . $member->etag . '"', 'size' => strlen($member->toCalendarObject()->serialize()), 'component' => 'vevent', ]; } /** * Returns information from a single calendar object, based on it's object * uri. * * The object uri is only the basename, or filename and not a full path. * * The returned array must have the same keys as getCalendarObjects. The * 'calendardata' object is required here though, while it's not required * for getCalendarObjects. * * This method must return null if the object did not exist. * * @param mixed $calendarId * @param string $objectUri * * @return array|null */ public function getCalendarObject($calendarId, $objectUri) { $member = Member::where('slug', str($objectUri)->replace('.ics', ''))->first(); if (!$member || !$member->toCalendarObject()) { return null; } return [ ...$this->calendarObjectMeta($member), 'calendardata' => $member->toCalendarObject()->serialize(), ]; } /** * Returns a list of calendar objects. * * This method should work identical to getCalendarObject, but instead * return all the calendar objects in the list as an array. * * If the backend supports this, it may allow for some speed-ups. * * @param mixed $calendarId * * @return array */ public function getMultipleCalendarObjects($calendarId, array $uris) { return Member::whereNotNull('birthday')->get()->map(fn ($member) => $this->getCalendarObject($calendarId, $member->slug . '.ics'))->toArray(); } /** * Creates a new calendar object. * * The object uri is only the basename, or filename and not a full path. * * It is possible to return an etag from this function, which will be used * in the response to this PUT request. Note that the ETag must be * surrounded by double-quotes. * * However, you should only really return this ETag if you don't mangle the * calendar-data. If the result of a subsequent GET to this object is not * the exact same as this request body, you should omit the ETag. * * @param mixed $calendarId * @param string $objectUri * @param string $calendarData * * @return string|null */ public function createCalendarObject($calendarId, $objectUri, $calendarData) { } /** * Updates an existing calendarobject, based on it's uri. * * The object uri is only the basename, or filename and not a full path. * * It is possible return an etag from this function, which will be used in * the response to this PUT request. Note that the ETag must be surrounded * by double-quotes. * * However, you should only really return this ETag if you don't mangle the * calendar-data. If the result of a subsequent GET to this object is not * the exact same as this request body, you should omit the ETag. * * @param mixed $calendarId * @param string $objectUri * @param string $calendarData * * @return string|null */ public function updateCalendarObject($calendarId, $objectUri, $calendarData) { } /** * Deletes an existing calendar object. * * The object uri is only the basename, or filename and not a full path. * * @param mixed $calendarId * @param string $objectUri */ public function deleteCalendarObject($calendarId, $objectUri) { } /** * Performs a calendar-query on the contents of this calendar. * * The calendar-query is defined in RFC4791 : CalDAV. Using the * calendar-query it is possible for a client to request a specific set of * object, based on contents of iCalendar properties, date-ranges and * iCalendar component types (VTODO, VEVENT). * * This method should just return a list of (relative) urls that match this * query. * * The list of filters are specified as an array. The exact array is * documented by Sabre\CalDAV\CalendarQueryParser. * * Note that it is extremely likely that getCalendarObject for every path * returned from this method will be called almost immediately after. You * may want to anticipate this to speed up these requests. * * This method provides a default implementation, which parses *all* the * iCalendar objects in the specified calendar. * * This default may well be good enough for personal use, and calendars * that aren't very large. But if you anticipate high usage, big calendars * or high loads, you are strongly adviced to optimize certain paths. * * The best way to do so is override this method and to optimize * specifically for 'common filters'. * * Requests that are extremely common are: * * requests for just VEVENTS * * requests for just VTODO * * requests with a time-range-filter on either VEVENT or VTODO. * * ..and combinations of these requests. It may not be worth it to try to * handle every possible situation and just rely on the (relatively * easy to use) CalendarQueryValidator to handle the rest. * * Note that especially time-range-filters may be difficult to parse. A * time-range filter specified on a VEVENT must for instance also handle * recurrence rules correctly. * A good example of how to interprete all these filters can also simply * be found in Sabre\CalDAV\CalendarQueryFilter. This class is as correct * as possible, so it gives you a good idea on what type of stuff you need * to think of. * * @param mixed $calendarId * * @return array */ public function calendarQuery($calendarId, array $filters) { } /** * Searches through all of a users calendars and calendar objects to find * an object with a specific UID. * * This method should return the path to this object, relative to the * calendar home, so this path usually only contains two parts: * * calendarpath/objectpath.ics * * If the uid is not found, return null. * * This method should only consider * objects that the principal owns, so * any calendars owned by other principals that also appear in this * collection should be ignored. * * @param string $principalUri * @param string $uid * * @return string|null */ public function getCalendarObjectByUID($principalUri, $uid) { } }