xref: /plugin/davcal/calendarBackendDokuwiki.php (revision d5703f5ab52f470e8a65f18aad4b649cbb5febeb)
1a1a3b679SAndreas Boehler<?php
2a1a3b679SAndreas Boehler
3a1a3b679SAndreas Boehleruse \Sabre\VObject;
4a1a3b679SAndreas Boehleruse \Sabre\CalDAV;
5a1a3b679SAndreas Boehleruse \Sabre\DAV;
6a1a3b679SAndreas Boehleruse \Sabre\DAV\Exception\Forbidden;
7a1a3b679SAndreas Boehler/**
8a1a3b679SAndreas Boehler * PDO CalDAV backend for DokuWiki - based on Sabre's CalDAV backend
9a1a3b679SAndreas Boehler *
10a1a3b679SAndreas Boehler * This backend is used to store calendar-data in a PDO database, such as
11a1a3b679SAndreas Boehler * sqlite or MySQL
12a1a3b679SAndreas Boehler *
13a1a3b679SAndreas Boehler * @copyright Copyright (C) 2007-2015 fruux GmbH (https://fruux.com/).
14a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/)
15a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License
16a1a3b679SAndreas Boehler */
17*d5703f5aSAndreas Boehlerclass DokuWikiSabreCalendarBackend extends \Sabre\CalDAV\Backend\AbstractBackend
18*d5703f5aSAndreas Boehler{
19a1a3b679SAndreas Boehler
20a1a3b679SAndreas Boehler
21a1a3b679SAndreas Boehler    /**
22a1a3b679SAndreas Boehler     * DokuWiki PlugIn Helper
23a1a3b679SAndreas Boehler     */
24a1a3b679SAndreas Boehler    protected $hlp = null;
25a1a3b679SAndreas Boehler    /**
26a1a3b679SAndreas Boehler
27a1a3b679SAndreas Boehler    /**
28a1a3b679SAndreas Boehler     * List of CalDAV properties, and how they map to database fieldnames
29a1a3b679SAndreas Boehler     * Add your own properties by simply adding on to this array.
30a1a3b679SAndreas Boehler     *
31a1a3b679SAndreas Boehler     * Note that only string-based properties are supported here.
32a1a3b679SAndreas Boehler     *
33a1a3b679SAndreas Boehler     * @var array
34a1a3b679SAndreas Boehler     */
35*d5703f5aSAndreas Boehler    public $propertyMap = array(
36a1a3b679SAndreas Boehler        '{DAV:}displayname'                                   => 'displayname',
37a1a3b679SAndreas Boehler        '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'description',
38a1a3b679SAndreas Boehler        '{urn:ietf:params:xml:ns:caldav}calendar-timezone'    => 'timezone',
39*d5703f5aSAndreas Boehler        //'{http://apple.com/ns/ical/}calendar-order'           => 'calendarorder',
40*d5703f5aSAndreas Boehler        //'{http://apple.com/ns/ical/}calendar-color'           => 'calendarcolor',
41*d5703f5aSAndreas Boehler    );
42a1a3b679SAndreas Boehler
43a1a3b679SAndreas Boehler    /**
44a1a3b679SAndreas Boehler     * Creates the backend
45a1a3b679SAndreas Boehler     *
46a1a3b679SAndreas Boehler     * @param \PDO $pdo
47a1a3b679SAndreas Boehler     */
48*d5703f5aSAndreas Boehler    function __construct(&$hlp)
49*d5703f5aSAndreas Boehler    {
50a1a3b679SAndreas Boehler
51*d5703f5aSAndreas Boehler        $this->hlp = $hlp;
52a1a3b679SAndreas Boehler
53a1a3b679SAndreas Boehler    }
54a1a3b679SAndreas Boehler
55a1a3b679SAndreas Boehler    /**
56a1a3b679SAndreas Boehler     * Returns a list of calendars for a principal.
57a1a3b679SAndreas Boehler     *
58a1a3b679SAndreas Boehler     * Every project is an array with the following keys:
59a1a3b679SAndreas Boehler     *  * id, a unique id that will be used by other functions to modify the
60a1a3b679SAndreas Boehler     *    calendar. This can be the same as the uri or a database key.
61a1a3b679SAndreas Boehler     *  * uri. This is just the 'base uri' or 'filename' of the calendar.
62a1a3b679SAndreas Boehler     *  * principaluri. The owner of the calendar. Almost always the same as
63a1a3b679SAndreas Boehler     *    principalUri passed to this method.
64a1a3b679SAndreas Boehler     *
65a1a3b679SAndreas Boehler     * Furthermore it can contain webdav properties in clark notation. A very
66a1a3b679SAndreas Boehler     * common one is '{DAV:}displayname'.
67a1a3b679SAndreas Boehler     *
68a1a3b679SAndreas Boehler     * Many clients also require:
69a1a3b679SAndreas Boehler     * {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
70a1a3b679SAndreas Boehler     * For this property, you can just return an instance of
71a1a3b679SAndreas Boehler     * Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet.
72a1a3b679SAndreas Boehler     *
73a1a3b679SAndreas Boehler     * If you return {http://sabredav.org/ns}read-only and set the value to 1,
74a1a3b679SAndreas Boehler     * ACL will automatically be put in read-only mode.
75a1a3b679SAndreas Boehler     *
76a1a3b679SAndreas Boehler     * @param string $principalUri
77a1a3b679SAndreas Boehler     * @return array
78a1a3b679SAndreas Boehler     */
79*d5703f5aSAndreas Boehler    function getCalendarsForUser($principalUri)
80*d5703f5aSAndreas Boehler    {
81a1a3b679SAndreas Boehler
82a1a3b679SAndreas Boehler        $fields = array_values($this->propertyMap);
83a1a3b679SAndreas Boehler        $fields[] = 'id';
84a1a3b679SAndreas Boehler        $fields[] = 'uri';
85a1a3b679SAndreas Boehler        $fields[] = 'synctoken';
86a1a3b679SAndreas Boehler        $fields[] = 'components';
87a1a3b679SAndreas Boehler        $fields[] = 'principaluri';
88a1a3b679SAndreas Boehler        $fields[] = 'transparent';
89a1a3b679SAndreas Boehler
90a1a3b679SAndreas Boehler        $idInfo = $this->hlp->getCalendarIdsForUser($principalUri);
91*d5703f5aSAndreas Boehler        $calendars = array();
92*d5703f5aSAndreas Boehler        foreach($idInfo as $id => $data)
93*d5703f5aSAndreas Boehler        {
94*d5703f5aSAndreas Boehler            $row = $this->hlp->getCalendarSettings($id);
95*d5703f5aSAndreas Boehler            $components = array();
96*d5703f5aSAndreas Boehler            if ($row['components'])
97*d5703f5aSAndreas Boehler            {
98a1a3b679SAndreas Boehler                $components = explode(',', $row['components']);
99a1a3b679SAndreas Boehler            }
100a1a3b679SAndreas Boehler
101*d5703f5aSAndreas Boehler            $calendar = array(
102a1a3b679SAndreas Boehler                'id'                                                                 => $row['id'],
103a1a3b679SAndreas Boehler                'uri'                                                                => $row['uri'],
104*d5703f5aSAndreas Boehler                'principaluri'                                                       => $principalUri,//Overwrite principaluri from database, we actually don't need it.
105a1a3b679SAndreas Boehler                '{' . CalDAV\Plugin::NS_CALENDARSERVER . '}getctag'                  => 'http://sabre.io/ns/sync/' . ($row['synctoken'] ? $row['synctoken'] : '0'),
106a1a3b679SAndreas Boehler                '{http://sabredav.org/ns}sync-token'                                 => $row['synctoken'] ? $row['synctoken'] : '0',
107a1a3b679SAndreas Boehler                '{' . CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new CalDAV\Xml\Property\SupportedCalendarComponentSet($components),
108*d5703f5aSAndreas Boehler                //'{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp'         => new CalDAV\Xml\Property\ScheduleCalendarTransp($row['transparent'] ? 'transparent' : 'opaque'),
109*d5703f5aSAndreas Boehler            );
110a1a3b679SAndreas Boehler            if($idInfo[$row['id']]['readonly'] === true)
111a1a3b679SAndreas Boehler                $calendar['{http://sabredav.org/ns}read-only'] = '1';
112a1a3b679SAndreas Boehler
113a1a3b679SAndreas Boehler
114*d5703f5aSAndreas Boehler            foreach ($this->propertyMap as $xmlName => $dbName)
115*d5703f5aSAndreas Boehler            {
116a1a3b679SAndreas Boehler                $calendar[$xmlName] = $row[$dbName];
117a1a3b679SAndreas Boehler            }
118a1a3b679SAndreas Boehler
119a1a3b679SAndreas Boehler            $calendars[] = $calendar;
120a1a3b679SAndreas Boehler
121a1a3b679SAndreas Boehler        }
122a1a3b679SAndreas Boehler
123a1a3b679SAndreas Boehler        return $calendars;
124a1a3b679SAndreas Boehler
125a1a3b679SAndreas Boehler    }
126a1a3b679SAndreas Boehler
127a1a3b679SAndreas Boehler    /**
128a1a3b679SAndreas Boehler     * Creates a new calendar for a principal.
129a1a3b679SAndreas Boehler     *
130a1a3b679SAndreas Boehler     * If the creation was a success, an id must be returned that can be used
131a1a3b679SAndreas Boehler     * to reference this calendar in other methods, such as updateCalendar.
132a1a3b679SAndreas Boehler     *
133a1a3b679SAndreas Boehler     * @param string $principalUri
134a1a3b679SAndreas Boehler     * @param string $calendarUri
135a1a3b679SAndreas Boehler     * @param array $properties
136a1a3b679SAndreas Boehler     * @return string
137a1a3b679SAndreas Boehler     */
138*d5703f5aSAndreas Boehler    function createCalendar($principalUri, $calendarUri, array $properties)
139*d5703f5aSAndreas Boehler    {
140a1a3b679SAndreas Boehler
141a1a3b679SAndreas Boehler        return false;
142a1a3b679SAndreas Boehler    }
143a1a3b679SAndreas Boehler
144a1a3b679SAndreas Boehler    /**
145a1a3b679SAndreas Boehler     * Updates properties for a calendar.
146a1a3b679SAndreas Boehler     *
147a1a3b679SAndreas Boehler     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
148a1a3b679SAndreas Boehler     * To do the actual updates, you must tell this object which properties
149a1a3b679SAndreas Boehler     * you're going to process with the handle() method.
150a1a3b679SAndreas Boehler     *
151a1a3b679SAndreas Boehler     * Calling the handle method is like telling the PropPatch object "I
152a1a3b679SAndreas Boehler     * promise I can handle updating this property".
153a1a3b679SAndreas Boehler     *
154a1a3b679SAndreas Boehler     * Read the PropPatch documenation for more info and examples.
155a1a3b679SAndreas Boehler     *
156a1a3b679SAndreas Boehler     * @param string $calendarId
157a1a3b679SAndreas Boehler     * @param \Sabre\DAV\PropPatch $propPatch
158a1a3b679SAndreas Boehler     * @return void
159a1a3b679SAndreas Boehler     */
160*d5703f5aSAndreas Boehler    function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch)
161*d5703f5aSAndreas Boehler    {
162a1a3b679SAndreas Boehler
163a1a3b679SAndreas Boehler        $supportedProperties = array_keys($this->propertyMap);
164a1a3b679SAndreas Boehler
165*d5703f5aSAndreas Boehler        $propPatch->handle($supportedProperties, function($mutations) use ($calendarId)
166*d5703f5aSAndreas Boehler        {
167*d5703f5aSAndreas Boehler            foreach ($mutations as $propertyName => $propertyValue)
168*d5703f5aSAndreas Boehler            {
169a1a3b679SAndreas Boehler
170*d5703f5aSAndreas Boehler                switch ($propertyName)
171*d5703f5aSAndreas Boehler                {
172*d5703f5aSAndreas Boehler                    case '{DAV:}displayname' :
173*d5703f5aSAndreas Boehler                        $this->hlp->updateCalendarName($calendarId, $propertyValue);
174*d5703f5aSAndreas Boehler                        break;
175*d5703f5aSAndreas Boehler                    case '{urn:ietf:params:xml:ns:caldav}calendar-description':
176*d5703f5aSAndreas Boehler                        $this->hlp->updateCalendarDescription($calendarId, $propertyValue);
177*d5703f5aSAndreas Boehler                        break;
178*d5703f5aSAndreas Boehler                    case '{urn:ietf:params:xml:ns:caldav}calendar-timezone':
179*d5703f5aSAndreas Boehler                        $this->hlp->updateCalendarTimezone($calendarId, $propertyValue);
180a1a3b679SAndreas Boehler                        break;
181a1a3b679SAndreas Boehler                    default :
182a1a3b679SAndreas Boehler                        break;
183a1a3b679SAndreas Boehler                }
184a1a3b679SAndreas Boehler
185a1a3b679SAndreas Boehler            }
186a1a3b679SAndreas Boehler            return true;
187a1a3b679SAndreas Boehler
188a1a3b679SAndreas Boehler        });
189a1a3b679SAndreas Boehler
190a1a3b679SAndreas Boehler    }
191a1a3b679SAndreas Boehler
192a1a3b679SAndreas Boehler    /**
193a1a3b679SAndreas Boehler     * Delete a calendar and all it's objects
194a1a3b679SAndreas Boehler     *
195a1a3b679SAndreas Boehler     * @param string $calendarId
196a1a3b679SAndreas Boehler     * @return void
197a1a3b679SAndreas Boehler     */
198*d5703f5aSAndreas Boehler    function deleteCalendar($calendarId)
199*d5703f5aSAndreas Boehler    {
200*d5703f5aSAndreas Boehler        return;
201a1a3b679SAndreas Boehler    }
202a1a3b679SAndreas Boehler
203a1a3b679SAndreas Boehler    /**
204a1a3b679SAndreas Boehler     * Returns all calendar objects within a calendar.
205a1a3b679SAndreas Boehler     *
206a1a3b679SAndreas Boehler     * Every item contains an array with the following keys:
207a1a3b679SAndreas Boehler     *   * calendardata - The iCalendar-compatible calendar data
208a1a3b679SAndreas Boehler     *   * uri - a unique key which will be used to construct the uri. This can
209a1a3b679SAndreas Boehler     *     be any arbitrary string, but making sure it ends with '.ics' is a
210a1a3b679SAndreas Boehler     *     good idea. This is only the basename, or filename, not the full
211a1a3b679SAndreas Boehler     *     path.
212a1a3b679SAndreas Boehler     *   * lastmodified - a timestamp of the last modification time
213a1a3b679SAndreas Boehler     *   * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
214a1a3b679SAndreas Boehler     *   '  "abcdef"')
215a1a3b679SAndreas Boehler     *   * size - The size of the calendar objects, in bytes.
216a1a3b679SAndreas Boehler     *   * component - optional, a string containing the type of object, such
217a1a3b679SAndreas Boehler     *     as 'vevent' or 'vtodo'. If specified, this will be used to populate
218a1a3b679SAndreas Boehler     *     the Content-Type header.
219a1a3b679SAndreas Boehler     *
220a1a3b679SAndreas Boehler     * Note that the etag is optional, but it's highly encouraged to return for
221a1a3b679SAndreas Boehler     * speed reasons.
222a1a3b679SAndreas Boehler     *
223a1a3b679SAndreas Boehler     * The calendardata is also optional. If it's not returned
224a1a3b679SAndreas Boehler     * 'getCalendarObject' will be called later, which *is* expected to return
225a1a3b679SAndreas Boehler     * calendardata.
226a1a3b679SAndreas Boehler     *
227a1a3b679SAndreas Boehler     * If neither etag or size are specified, the calendardata will be
228a1a3b679SAndreas Boehler     * used/fetched to determine these numbers. If both are specified the
229a1a3b679SAndreas Boehler     * amount of times this is needed is reduced by a great degree.
230a1a3b679SAndreas Boehler     *
231a1a3b679SAndreas Boehler     * @param string $calendarId
232a1a3b679SAndreas Boehler     * @return array
233a1a3b679SAndreas Boehler     */
234*d5703f5aSAndreas Boehler    function getCalendarObjects($calendarId)
235*d5703f5aSAndreas Boehler    {
236a1a3b679SAndreas Boehler
237*d5703f5aSAndreas Boehler        $arr = $this->hlp->getCalendarObjects($calendarId);
238*d5703f5aSAndreas Boehler        $result = array();
239*d5703f5aSAndreas Boehler        foreach ($arr as $row)
240*d5703f5aSAndreas Boehler        {
241*d5703f5aSAndreas Boehler            $result[] = array(
242a1a3b679SAndreas Boehler                'id'           => $row['id'],
243a1a3b679SAndreas Boehler                'uri'          => $row['uri'],
244a1a3b679SAndreas Boehler                'lastmodified' => $row['lastmodified'],
245a1a3b679SAndreas Boehler                'etag'         => '"' . $row['etag'] . '"',
246a1a3b679SAndreas Boehler                'calendarid'   => $row['calendarid'],
247a1a3b679SAndreas Boehler                'size'         => (int)$row['size'],
248a1a3b679SAndreas Boehler                'component'    => strtolower($row['componenttype']),
249*d5703f5aSAndreas Boehler            );
250a1a3b679SAndreas Boehler        }
251a1a3b679SAndreas Boehler
252a1a3b679SAndreas Boehler        return $result;
253a1a3b679SAndreas Boehler
254a1a3b679SAndreas Boehler    }
255a1a3b679SAndreas Boehler
256a1a3b679SAndreas Boehler    /**
257a1a3b679SAndreas Boehler     * Returns information from a single calendar object, based on it's object
258a1a3b679SAndreas Boehler     * uri.
259a1a3b679SAndreas Boehler     *
260a1a3b679SAndreas Boehler     * The object uri is only the basename, or filename and not a full path.
261a1a3b679SAndreas Boehler     *
262a1a3b679SAndreas Boehler     * The returned array must have the same keys as getCalendarObjects. The
263a1a3b679SAndreas Boehler     * 'calendardata' object is required here though, while it's not required
264a1a3b679SAndreas Boehler     * for getCalendarObjects.
265a1a3b679SAndreas Boehler     *
266a1a3b679SAndreas Boehler     * This method must return null if the object did not exist.
267a1a3b679SAndreas Boehler     *
268a1a3b679SAndreas Boehler     * @param string $calendarId
269a1a3b679SAndreas Boehler     * @param string $objectUri
270a1a3b679SAndreas Boehler     * @return array|null
271a1a3b679SAndreas Boehler     */
272*d5703f5aSAndreas Boehler    function getCalendarObject($calendarId, $objectUri)
273*d5703f5aSAndreas Boehler    {
274a1a3b679SAndreas Boehler
275*d5703f5aSAndreas Boehler        $row = $this->hlp->getCalendarObjectByUri($calendarId, $objectUri);
276a1a3b679SAndreas Boehler
277*d5703f5aSAndreas Boehler        if (!$row)
278*d5703f5aSAndreas Boehler            return null;
279a1a3b679SAndreas Boehler
280*d5703f5aSAndreas Boehler        return array(
281a1a3b679SAndreas Boehler            'id'            => $row['id'],
282a1a3b679SAndreas Boehler            'uri'           => $row['uri'],
283a1a3b679SAndreas Boehler            'lastmodified'  => $row['lastmodified'],
284a1a3b679SAndreas Boehler            'etag'          => '"' . $row['etag'] . '"',
285a1a3b679SAndreas Boehler            'calendarid'    => $row['calendarid'],
286a1a3b679SAndreas Boehler            'size'          => (int)$row['size'],
287a1a3b679SAndreas Boehler            'calendardata'  => $row['calendardata'],
288a1a3b679SAndreas Boehler            'component'     => strtolower($row['componenttype']),
289*d5703f5aSAndreas Boehler         );
290a1a3b679SAndreas Boehler
291a1a3b679SAndreas Boehler    }
292a1a3b679SAndreas Boehler
293a1a3b679SAndreas Boehler    /**
294a1a3b679SAndreas Boehler     * Returns a list of calendar objects.
295a1a3b679SAndreas Boehler     *
296a1a3b679SAndreas Boehler     * This method should work identical to getCalendarObject, but instead
297a1a3b679SAndreas Boehler     * return all the calendar objects in the list as an array.
298a1a3b679SAndreas Boehler     *
299a1a3b679SAndreas Boehler     * If the backend supports this, it may allow for some speed-ups.
300a1a3b679SAndreas Boehler     *
301a1a3b679SAndreas Boehler     * @param mixed $calendarId
302a1a3b679SAndreas Boehler     * @param array $uris
303a1a3b679SAndreas Boehler     * @return array
304a1a3b679SAndreas Boehler     */
305*d5703f5aSAndreas Boehler    function getMultipleCalendarObjects($calendarId, array $uris)
306*d5703f5aSAndreas Boehler    {
307a1a3b679SAndreas Boehler
308*d5703f5aSAndreas Boehler        $arr = $this->hlp->getMultipleCalendarObjectsByUri($calendarId, $uris);
309a1a3b679SAndreas Boehler
310*d5703f5aSAndreas Boehler        $result = array();
311*d5703f5aSAndreas Boehler        foreach($arr as $row)
312*d5703f5aSAndreas Boehler        {
313a1a3b679SAndreas Boehler
314*d5703f5aSAndreas Boehler            $result[] = array(
315a1a3b679SAndreas Boehler                'id'           => $row['id'],
316a1a3b679SAndreas Boehler                'uri'          => $row['uri'],
317a1a3b679SAndreas Boehler                'lastmodified' => $row['lastmodified'],
318a1a3b679SAndreas Boehler                'etag'         => '"' . $row['etag'] . '"',
319a1a3b679SAndreas Boehler                'calendarid'   => $row['calendarid'],
320a1a3b679SAndreas Boehler                'size'         => (int)$row['size'],
321a1a3b679SAndreas Boehler                'calendardata' => $row['calendardata'],
322a1a3b679SAndreas Boehler                'component'    => strtolower($row['componenttype']),
323*d5703f5aSAndreas Boehler            );
324a1a3b679SAndreas Boehler
325a1a3b679SAndreas Boehler        }
326a1a3b679SAndreas Boehler        return $result;
327a1a3b679SAndreas Boehler
328a1a3b679SAndreas Boehler    }
329a1a3b679SAndreas Boehler
330a1a3b679SAndreas Boehler
331a1a3b679SAndreas Boehler    /**
332a1a3b679SAndreas Boehler     * Creates a new calendar object.
333a1a3b679SAndreas Boehler     *
334a1a3b679SAndreas Boehler     * The object uri is only the basename, or filename and not a full path.
335a1a3b679SAndreas Boehler     *
336a1a3b679SAndreas Boehler     * It is possible return an etag from this function, which will be used in
337a1a3b679SAndreas Boehler     * the response to this PUT request. Note that the ETag must be surrounded
338a1a3b679SAndreas Boehler     * by double-quotes.
339a1a3b679SAndreas Boehler     *
340a1a3b679SAndreas Boehler     * However, you should only really return this ETag if you don't mangle the
341a1a3b679SAndreas Boehler     * calendar-data. If the result of a subsequent GET to this object is not
342a1a3b679SAndreas Boehler     * the exact same as this request body, you should omit the ETag.
343a1a3b679SAndreas Boehler     *
344a1a3b679SAndreas Boehler     * @param mixed $calendarId
345a1a3b679SAndreas Boehler     * @param string $objectUri
346a1a3b679SAndreas Boehler     * @param string $calendarData
347a1a3b679SAndreas Boehler     * @return string|null
348a1a3b679SAndreas Boehler     */
349*d5703f5aSAndreas Boehler    function createCalendarObject($calendarId, $objectUri, $calendarData)
350*d5703f5aSAndreas Boehler    {
351a1a3b679SAndreas Boehler
352*d5703f5aSAndreas Boehler        $etag = $this->hlp->addCalendarEntryToCalendarByICS($calendarId, $objectUri, $calendarData);
353a1a3b679SAndreas Boehler
354*d5703f5aSAndreas Boehler        return '"' . $etag . '"';
355a1a3b679SAndreas Boehler    }
356a1a3b679SAndreas Boehler
357a1a3b679SAndreas Boehler    /**
358a1a3b679SAndreas Boehler     * Updates an existing calendarobject, based on it's uri.
359a1a3b679SAndreas Boehler     *
360a1a3b679SAndreas Boehler     * The object uri is only the basename, or filename and not a full path.
361a1a3b679SAndreas Boehler     *
362a1a3b679SAndreas Boehler     * It is possible return an etag from this function, which will be used in
363a1a3b679SAndreas Boehler     * the response to this PUT request. Note that the ETag must be surrounded
364a1a3b679SAndreas Boehler     * by double-quotes.
365a1a3b679SAndreas Boehler     *
366a1a3b679SAndreas Boehler     * However, you should only really return this ETag if you don't mangle the
367a1a3b679SAndreas Boehler     * calendar-data. If the result of a subsequent GET to this object is not
368a1a3b679SAndreas Boehler     * the exact same as this request body, you should omit the ETag.
369a1a3b679SAndreas Boehler     *
370a1a3b679SAndreas Boehler     * @param mixed $calendarId
371a1a3b679SAndreas Boehler     * @param string $objectUri
372a1a3b679SAndreas Boehler     * @param string $calendarData
373a1a3b679SAndreas Boehler     * @return string|null
374a1a3b679SAndreas Boehler     */
375*d5703f5aSAndreas Boehler    function updateCalendarObject($calendarId, $objectUri, $calendarData)
376*d5703f5aSAndreas Boehler    {
377a1a3b679SAndreas Boehler
378*d5703f5aSAndreas Boehler        $etag = $this->hlp->editCalendarEntryToCalendarByICS($calendarId, $objectUri, $calendarData);
379*d5703f5aSAndreas Boehler        return '"' . $etag. '"';
380a1a3b679SAndreas Boehler
381a1a3b679SAndreas Boehler    }
382a1a3b679SAndreas Boehler
383a1a3b679SAndreas Boehler
384a1a3b679SAndreas Boehler
385a1a3b679SAndreas Boehler    /**
386a1a3b679SAndreas Boehler     * Deletes an existing calendar object.
387a1a3b679SAndreas Boehler     *
388a1a3b679SAndreas Boehler     * The object uri is only the basename, or filename and not a full path.
389a1a3b679SAndreas Boehler     *
390a1a3b679SAndreas Boehler     * @param string $calendarId
391a1a3b679SAndreas Boehler     * @param string $objectUri
392a1a3b679SAndreas Boehler     * @return void
393a1a3b679SAndreas Boehler     */
394*d5703f5aSAndreas Boehler    function deleteCalendarObject($calendarId, $objectUri)
395*d5703f5aSAndreas Boehler    {
396*d5703f5aSAndreas Boehler        $this->hlp->deleteCalendarEntryForCalendarByUri($calendarId, $objectUri);
397a1a3b679SAndreas Boehler
398a1a3b679SAndreas Boehler    }
399a1a3b679SAndreas Boehler
400a1a3b679SAndreas Boehler    /**
401a1a3b679SAndreas Boehler     * Performs a calendar-query on the contents of this calendar.
402a1a3b679SAndreas Boehler     *
403a1a3b679SAndreas Boehler     * The calendar-query is defined in RFC4791 : CalDAV. Using the
404a1a3b679SAndreas Boehler     * calendar-query it is possible for a client to request a specific set of
405a1a3b679SAndreas Boehler     * object, based on contents of iCalendar properties, date-ranges and
406a1a3b679SAndreas Boehler     * iCalendar component types (VTODO, VEVENT).
407a1a3b679SAndreas Boehler     *
408a1a3b679SAndreas Boehler     * This method should just return a list of (relative) urls that match this
409a1a3b679SAndreas Boehler     * query.
410a1a3b679SAndreas Boehler     *
411a1a3b679SAndreas Boehler     * The list of filters are specified as an array. The exact array is
412a1a3b679SAndreas Boehler     * documented by \Sabre\CalDAV\CalendarQueryParser.
413a1a3b679SAndreas Boehler     *
414a1a3b679SAndreas Boehler     * Note that it is extremely likely that getCalendarObject for every path
415a1a3b679SAndreas Boehler     * returned from this method will be called almost immediately after. You
416a1a3b679SAndreas Boehler     * may want to anticipate this to speed up these requests.
417a1a3b679SAndreas Boehler     *
418a1a3b679SAndreas Boehler     * This method provides a default implementation, which parses *all* the
419a1a3b679SAndreas Boehler     * iCalendar objects in the specified calendar.
420a1a3b679SAndreas Boehler     *
421a1a3b679SAndreas Boehler     * This default may well be good enough for personal use, and calendars
422a1a3b679SAndreas Boehler     * that aren't very large. But if you anticipate high usage, big calendars
423a1a3b679SAndreas Boehler     * or high loads, you are strongly adviced to optimize certain paths.
424a1a3b679SAndreas Boehler     *
425a1a3b679SAndreas Boehler     * The best way to do so is override this method and to optimize
426a1a3b679SAndreas Boehler     * specifically for 'common filters'.
427a1a3b679SAndreas Boehler     *
428a1a3b679SAndreas Boehler     * Requests that are extremely common are:
429a1a3b679SAndreas Boehler     *   * requests for just VEVENTS
430a1a3b679SAndreas Boehler     *   * requests for just VTODO
431a1a3b679SAndreas Boehler     *   * requests with a time-range-filter on a VEVENT.
432a1a3b679SAndreas Boehler     *
433a1a3b679SAndreas Boehler     * ..and combinations of these requests. It may not be worth it to try to
434a1a3b679SAndreas Boehler     * handle every possible situation and just rely on the (relatively
435a1a3b679SAndreas Boehler     * easy to use) CalendarQueryValidator to handle the rest.
436a1a3b679SAndreas Boehler     *
437a1a3b679SAndreas Boehler     * Note that especially time-range-filters may be difficult to parse. A
438a1a3b679SAndreas Boehler     * time-range filter specified on a VEVENT must for instance also handle
439a1a3b679SAndreas Boehler     * recurrence rules correctly.
440a1a3b679SAndreas Boehler     * A good example of how to interprete all these filters can also simply
441a1a3b679SAndreas Boehler     * be found in \Sabre\CalDAV\CalendarQueryFilter. This class is as correct
442a1a3b679SAndreas Boehler     * as possible, so it gives you a good idea on what type of stuff you need
443a1a3b679SAndreas Boehler     * to think of.
444a1a3b679SAndreas Boehler     *
445a1a3b679SAndreas Boehler     * This specific implementation (for the PDO) backend optimizes filters on
446a1a3b679SAndreas Boehler     * specific components, and VEVENT time-ranges.
447a1a3b679SAndreas Boehler     *
448a1a3b679SAndreas Boehler     * @param string $calendarId
449a1a3b679SAndreas Boehler     * @param array $filters
450a1a3b679SAndreas Boehler     * @return array
451a1a3b679SAndreas Boehler     */
452*d5703f5aSAndreas Boehler    function calendarQuery($calendarId, array $filters)
453*d5703f5aSAndreas Boehler    {
454*d5703f5aSAndreas Boehler        $result = $this->hlp->calendarQuery($calendarId, $filters);
455a1a3b679SAndreas Boehler        return $result;
456a1a3b679SAndreas Boehler    }
457a1a3b679SAndreas Boehler
458a1a3b679SAndreas Boehler    /**
459a1a3b679SAndreas Boehler     * Searches through all of a users calendars and calendar objects to find
460a1a3b679SAndreas Boehler     * an object with a specific UID.
461a1a3b679SAndreas Boehler     *
462a1a3b679SAndreas Boehler     * This method should return the path to this object, relative to the
463a1a3b679SAndreas Boehler     * calendar home, so this path usually only contains two parts:
464a1a3b679SAndreas Boehler     *
465a1a3b679SAndreas Boehler     * calendarpath/objectpath.ics
466a1a3b679SAndreas Boehler     *
467a1a3b679SAndreas Boehler     * If the uid is not found, return null.
468a1a3b679SAndreas Boehler     *
469a1a3b679SAndreas Boehler     * This method should only consider * objects that the principal owns, so
470a1a3b679SAndreas Boehler     * any calendars owned by other principals that also appear in this
471a1a3b679SAndreas Boehler     * collection should be ignored.
472a1a3b679SAndreas Boehler     *
473a1a3b679SAndreas Boehler     * @param string $principalUri
474a1a3b679SAndreas Boehler     * @param string $uid
475a1a3b679SAndreas Boehler     * @return string|null
476a1a3b679SAndreas Boehler     */
477*d5703f5aSAndreas Boehler    function getCalendarObjectByUID($principalUri, $uid)
478*d5703f5aSAndreas Boehler    {
479*d5703f5aSAndreas Boehler        $calids = array_keys($this->hlp->getCalendarIsForUser($principalUri));
480*d5703f5aSAndreas Boehler        $event = $this->hlp->getEventWithUid($uid);
481a1a3b679SAndreas Boehler
482*d5703f5aSAndreas Boehler        if(in_array($event['calendarid'], $calids))
483*d5703f5aSAndreas Boehler        {
484*d5703f5aSAndreas Boehler            $settings = $this->hlp->getCalendarSettings($event['calendarid']);
485*d5703f5aSAndreas Boehler            return $settings['uri'] . '/' . $event['uri'];
486a1a3b679SAndreas Boehler        }
487*d5703f5aSAndreas Boehler        return null;
488a1a3b679SAndreas Boehler    }
489a1a3b679SAndreas Boehler
490a1a3b679SAndreas Boehler    /**
491a1a3b679SAndreas Boehler     * The getChanges method returns all the changes that have happened, since
492a1a3b679SAndreas Boehler     * the specified syncToken in the specified calendar.
493a1a3b679SAndreas Boehler     *
494a1a3b679SAndreas Boehler     * This function should return an array, such as the following:
495a1a3b679SAndreas Boehler     *
496a1a3b679SAndreas Boehler     * [
497a1a3b679SAndreas Boehler     *   'syncToken' => 'The current synctoken',
498a1a3b679SAndreas Boehler     *   'added'   => [
499a1a3b679SAndreas Boehler     *      'new.txt',
500a1a3b679SAndreas Boehler     *   ],
501a1a3b679SAndreas Boehler     *   'modified'   => [
502a1a3b679SAndreas Boehler     *      'modified.txt',
503a1a3b679SAndreas Boehler     *   ],
504a1a3b679SAndreas Boehler     *   'deleted' => [
505a1a3b679SAndreas Boehler     *      'foo.php.bak',
506a1a3b679SAndreas Boehler     *      'old.txt'
507a1a3b679SAndreas Boehler     *   ]
508a1a3b679SAndreas Boehler     * ];
509a1a3b679SAndreas Boehler     *
510a1a3b679SAndreas Boehler     * The returned syncToken property should reflect the *current* syncToken
511a1a3b679SAndreas Boehler     * of the calendar, as reported in the {http://sabredav.org/ns}sync-token
512a1a3b679SAndreas Boehler     * property this is needed here too, to ensure the operation is atomic.
513a1a3b679SAndreas Boehler     *
514a1a3b679SAndreas Boehler     * If the $syncToken argument is specified as null, this is an initial
515a1a3b679SAndreas Boehler     * sync, and all members should be reported.
516a1a3b679SAndreas Boehler     *
517a1a3b679SAndreas Boehler     * The modified property is an array of nodenames that have changed since
518a1a3b679SAndreas Boehler     * the last token.
519a1a3b679SAndreas Boehler     *
520a1a3b679SAndreas Boehler     * The deleted property is an array with nodenames, that have been deleted
521a1a3b679SAndreas Boehler     * from collection.
522a1a3b679SAndreas Boehler     *
523a1a3b679SAndreas Boehler     * The $syncLevel argument is basically the 'depth' of the report. If it's
524a1a3b679SAndreas Boehler     * 1, you only have to report changes that happened only directly in
525a1a3b679SAndreas Boehler     * immediate descendants. If it's 2, it should also include changes from
526a1a3b679SAndreas Boehler     * the nodes below the child collections. (grandchildren)
527a1a3b679SAndreas Boehler     *
528a1a3b679SAndreas Boehler     * The $limit argument allows a client to specify how many results should
529a1a3b679SAndreas Boehler     * be returned at most. If the limit is not specified, it should be treated
530a1a3b679SAndreas Boehler     * as infinite.
531a1a3b679SAndreas Boehler     *
532a1a3b679SAndreas Boehler     * If the limit (infinite or not) is higher than you're willing to return,
533a1a3b679SAndreas Boehler     * you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
534a1a3b679SAndreas Boehler     *
535a1a3b679SAndreas Boehler     * If the syncToken is expired (due to data cleanup) or unknown, you must
536a1a3b679SAndreas Boehler     * return null.
537a1a3b679SAndreas Boehler     *
538a1a3b679SAndreas Boehler     * The limit is 'suggestive'. You are free to ignore it.
539a1a3b679SAndreas Boehler     *
540a1a3b679SAndreas Boehler     * @param string $calendarId
541a1a3b679SAndreas Boehler     * @param string $syncToken
542a1a3b679SAndreas Boehler     * @param int $syncLevel
543a1a3b679SAndreas Boehler     * @param int $limit
544a1a3b679SAndreas Boehler     * @return array
545a1a3b679SAndreas Boehler     */
546*d5703f5aSAndreas Boehler    function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null)
547*d5703f5aSAndreas Boehler    {
548*d5703f5aSAndreas Boehler        $result = $this->hlp->getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit);
549a1a3b679SAndreas Boehler        return $result;
550a1a3b679SAndreas Boehler    }
551a1a3b679SAndreas Boehler
552a1a3b679SAndreas Boehler    /**
553a1a3b679SAndreas Boehler     * Returns a list of subscriptions for a principal.
554a1a3b679SAndreas Boehler     *
555a1a3b679SAndreas Boehler     * Every subscription is an array with the following keys:
556a1a3b679SAndreas Boehler     *  * id, a unique id that will be used by other functions to modify the
557a1a3b679SAndreas Boehler     *    subscription. This can be the same as the uri or a database key.
558a1a3b679SAndreas Boehler     *  * uri. This is just the 'base uri' or 'filename' of the subscription.
559a1a3b679SAndreas Boehler     *  * principaluri. The owner of the subscription. Almost always the same as
560a1a3b679SAndreas Boehler     *    principalUri passed to this method.
561a1a3b679SAndreas Boehler     *  * source. Url to the actual feed
562a1a3b679SAndreas Boehler     *
563a1a3b679SAndreas Boehler     * Furthermore, all the subscription info must be returned too:
564a1a3b679SAndreas Boehler     *
565a1a3b679SAndreas Boehler     * 1. {DAV:}displayname
566a1a3b679SAndreas Boehler     * 2. {http://apple.com/ns/ical/}refreshrate
567a1a3b679SAndreas Boehler     * 3. {http://calendarserver.org/ns/}subscribed-strip-todos (omit if todos
568a1a3b679SAndreas Boehler     *    should not be stripped).
569a1a3b679SAndreas Boehler     * 4. {http://calendarserver.org/ns/}subscribed-strip-alarms (omit if alarms
570a1a3b679SAndreas Boehler     *    should not be stripped).
571a1a3b679SAndreas Boehler     * 5. {http://calendarserver.org/ns/}subscribed-strip-attachments (omit if
572a1a3b679SAndreas Boehler     *    attachments should not be stripped).
573a1a3b679SAndreas Boehler     * 7. {http://apple.com/ns/ical/}calendar-color
574a1a3b679SAndreas Boehler     * 8. {http://apple.com/ns/ical/}calendar-order
575a1a3b679SAndreas Boehler     * 9. {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
576a1a3b679SAndreas Boehler     *    (should just be an instance of
577a1a3b679SAndreas Boehler     *    Sabre\CalDAV\Property\SupportedCalendarComponentSet, with a bunch of
578a1a3b679SAndreas Boehler     *    default components).
579a1a3b679SAndreas Boehler     *
580a1a3b679SAndreas Boehler     * @param string $principalUri
581a1a3b679SAndreas Boehler     * @return array
582a1a3b679SAndreas Boehler     */
583*d5703f5aSAndreas Boehler    function getSubscriptionsForUser($principalUri)
584*d5703f5aSAndreas Boehler    {
585*d5703f5aSAndreas Boehler        return array();
586a1a3b679SAndreas Boehler
587a1a3b679SAndreas Boehler    }
588a1a3b679SAndreas Boehler
589a1a3b679SAndreas Boehler    /**
590a1a3b679SAndreas Boehler     * Creates a new subscription for a principal.
591a1a3b679SAndreas Boehler     *
592a1a3b679SAndreas Boehler     * If the creation was a success, an id must be returned that can be used to reference
593a1a3b679SAndreas Boehler     * this subscription in other methods, such as updateSubscription.
594a1a3b679SAndreas Boehler     *
595a1a3b679SAndreas Boehler     * @param string $principalUri
596a1a3b679SAndreas Boehler     * @param string $uri
597a1a3b679SAndreas Boehler     * @param array $properties
598a1a3b679SAndreas Boehler     * @return mixed
599a1a3b679SAndreas Boehler     */
600*d5703f5aSAndreas Boehler    function createSubscription($principalUri, $uri, array $properties)
601*d5703f5aSAndreas Boehler    {
602*d5703f5aSAndreas Boehler        return null;
603a1a3b679SAndreas Boehler
604a1a3b679SAndreas Boehler    }
605a1a3b679SAndreas Boehler
606a1a3b679SAndreas Boehler    /**
607a1a3b679SAndreas Boehler     * Updates a subscription
608a1a3b679SAndreas Boehler     *
609a1a3b679SAndreas Boehler     * The list of mutations is stored in a Sabre\DAV\PropPatch object.
610a1a3b679SAndreas Boehler     * To do the actual updates, you must tell this object which properties
611a1a3b679SAndreas Boehler     * you're going to process with the handle() method.
612a1a3b679SAndreas Boehler     *
613a1a3b679SAndreas Boehler     * Calling the handle method is like telling the PropPatch object "I
614a1a3b679SAndreas Boehler     * promise I can handle updating this property".
615a1a3b679SAndreas Boehler     *
616a1a3b679SAndreas Boehler     * Read the PropPatch documenation for more info and examples.
617a1a3b679SAndreas Boehler     *
618a1a3b679SAndreas Boehler     * @param mixed $subscriptionId
619a1a3b679SAndreas Boehler     * @param \Sabre\DAV\PropPatch $propPatch
620a1a3b679SAndreas Boehler     * @return void
621a1a3b679SAndreas Boehler     */
622*d5703f5aSAndreas Boehler    function updateSubscription($subscriptionId, DAV\PropPatch $propPatch)
623*d5703f5aSAndreas Boehler    {
624*d5703f5aSAndreas Boehler        return;
625a1a3b679SAndreas Boehler    }
626a1a3b679SAndreas Boehler
627a1a3b679SAndreas Boehler    /**
628a1a3b679SAndreas Boehler     * Deletes a subscription
629a1a3b679SAndreas Boehler     *
630a1a3b679SAndreas Boehler     * @param mixed $subscriptionId
631a1a3b679SAndreas Boehler     * @return void
632a1a3b679SAndreas Boehler     */
633*d5703f5aSAndreas Boehler    function deleteSubscription($subscriptionId)
634*d5703f5aSAndreas Boehler    {
635a1a3b679SAndreas Boehler
636*d5703f5aSAndreas Boehler        return;
637a1a3b679SAndreas Boehler
638a1a3b679SAndreas Boehler    }
639a1a3b679SAndreas Boehler
640a1a3b679SAndreas Boehler    /**
641a1a3b679SAndreas Boehler     * Returns a single scheduling object.
642a1a3b679SAndreas Boehler     *
643a1a3b679SAndreas Boehler     * The returned array should contain the following elements:
644a1a3b679SAndreas Boehler     *   * uri - A unique basename for the object. This will be used to
645a1a3b679SAndreas Boehler     *           construct a full uri.
646a1a3b679SAndreas Boehler     *   * calendardata - The iCalendar object
647a1a3b679SAndreas Boehler     *   * lastmodified - The last modification date. Can be an int for a unix
648a1a3b679SAndreas Boehler     *                    timestamp, or a PHP DateTime object.
649a1a3b679SAndreas Boehler     *   * etag - A unique token that must change if the object changed.
650a1a3b679SAndreas Boehler     *   * size - The size of the object, in bytes.
651a1a3b679SAndreas Boehler     *
652a1a3b679SAndreas Boehler     * @param string $principalUri
653a1a3b679SAndreas Boehler     * @param string $objectUri
654a1a3b679SAndreas Boehler     * @return array
655a1a3b679SAndreas Boehler     */
656*d5703f5aSAndreas Boehler    function getSchedulingObject($principalUri, $objectUri)
657*d5703f5aSAndreas Boehler    {
658a1a3b679SAndreas Boehler
659*d5703f5aSAndreas Boehler        return null;
660a1a3b679SAndreas Boehler
661a1a3b679SAndreas Boehler    }
662a1a3b679SAndreas Boehler
663a1a3b679SAndreas Boehler    /**
664a1a3b679SAndreas Boehler     * Returns all scheduling objects for the inbox collection.
665a1a3b679SAndreas Boehler     *
666a1a3b679SAndreas Boehler     * These objects should be returned as an array. Every item in the array
667a1a3b679SAndreas Boehler     * should follow the same structure as returned from getSchedulingObject.
668a1a3b679SAndreas Boehler     *
669a1a3b679SAndreas Boehler     * The main difference is that 'calendardata' is optional.
670a1a3b679SAndreas Boehler     *
671a1a3b679SAndreas Boehler     * @param string $principalUri
672a1a3b679SAndreas Boehler     * @return array
673a1a3b679SAndreas Boehler     */
674*d5703f5aSAndreas Boehler    function getSchedulingObjects($principalUri)
675*d5703f5aSAndreas Boehler    {
676*d5703f5aSAndreas Boehler        return null;
677a1a3b679SAndreas Boehler
678a1a3b679SAndreas Boehler    }
679a1a3b679SAndreas Boehler
680a1a3b679SAndreas Boehler    /**
681a1a3b679SAndreas Boehler     * Deletes a scheduling object
682a1a3b679SAndreas Boehler     *
683a1a3b679SAndreas Boehler     * @param string $principalUri
684a1a3b679SAndreas Boehler     * @param string $objectUri
685a1a3b679SAndreas Boehler     * @return void
686a1a3b679SAndreas Boehler     */
687*d5703f5aSAndreas Boehler    function deleteSchedulingObject($principalUri, $objectUri)
688*d5703f5aSAndreas Boehler    {
689a1a3b679SAndreas Boehler
690*d5703f5aSAndreas Boehler        return;
691a1a3b679SAndreas Boehler    }
692a1a3b679SAndreas Boehler
693a1a3b679SAndreas Boehler    /**
694a1a3b679SAndreas Boehler     * Creates a new scheduling object. This should land in a users' inbox.
695a1a3b679SAndreas Boehler     *
696a1a3b679SAndreas Boehler     * @param string $principalUri
697a1a3b679SAndreas Boehler     * @param string $objectUri
698a1a3b679SAndreas Boehler     * @param string $objectData
699a1a3b679SAndreas Boehler     * @return void
700a1a3b679SAndreas Boehler     */
701*d5703f5aSAndreas Boehler    function createSchedulingObject($principalUri, $objectUri, $objectData)
702*d5703f5aSAndreas Boehler    {
703a1a3b679SAndreas Boehler
704*d5703f5aSAndreas Boehler        return;
705a1a3b679SAndreas Boehler
706a1a3b679SAndreas Boehler    }
707a1a3b679SAndreas Boehler
708a1a3b679SAndreas Boehler}
709