xref: /plugin/davcal/helper.php (revision cb71a62a32c9da24e9fd44e8cf1e3b9946e1dec2)
1a1a3b679SAndreas Boehler<?php
2a1a3b679SAndreas Boehler/**
3*cb71a62aSAndreas Boehler  * Helper Class for the DAVCal plugin
4a1a3b679SAndreas Boehler  * This helper does the actual work.
5a1a3b679SAndreas Boehler  *
6a1a3b679SAndreas Boehler  */
7a1a3b679SAndreas Boehler
8a1a3b679SAndreas Boehler// must be run within Dokuwiki
9a1a3b679SAndreas Boehlerif(!defined('DOKU_INC')) die();
10a1a3b679SAndreas Boehler
11a1a3b679SAndreas Boehlerclass helper_plugin_davcal extends DokuWiki_Plugin {
12a1a3b679SAndreas Boehler
13a1a3b679SAndreas Boehler  protected $sqlite = null;
14a1a3b679SAndreas Boehler
15a1a3b679SAndreas Boehler  /**
16*cb71a62aSAndreas Boehler    * Constructor to load the configuration and the SQLite plugin
17a1a3b679SAndreas Boehler    */
18a1a3b679SAndreas Boehler  public function helper_plugin_davcal() {
19a1a3b679SAndreas Boehler    $this->sqlite =& plugin_load('helper', 'sqlite');
20a1a3b679SAndreas Boehler    if(!$this->sqlite)
21a1a3b679SAndreas Boehler    {
22a1a3b679SAndreas Boehler        msg('This plugin requires the sqlite plugin. Please install it.');
23a1a3b679SAndreas Boehler        return;
24a1a3b679SAndreas Boehler    }
25a1a3b679SAndreas Boehler
26a1a3b679SAndreas Boehler    if(!$this->sqlite->init('davcal', DOKU_PLUGIN.'davcal/db/'))
27a1a3b679SAndreas Boehler    {
28a1a3b679SAndreas Boehler        return;
29a1a3b679SAndreas Boehler    }
30a1a3b679SAndreas Boehler  }
31a1a3b679SAndreas Boehler
32*cb71a62aSAndreas Boehler  /**
33*cb71a62aSAndreas Boehler   * Set the calendar name and description for a given page with a given
34*cb71a62aSAndreas Boehler   * page id.
35*cb71a62aSAndreas Boehler   * If the calendar doesn't exist, the calendar is created!
36*cb71a62aSAndreas Boehler   *
37*cb71a62aSAndreas Boehler   * @param string  $name The name of the new calendar
38*cb71a62aSAndreas Boehler   * @param string  $description The description of the new calendar
39*cb71a62aSAndreas Boehler   * @param string  $id (optional) The ID of the page
40*cb71a62aSAndreas Boehler   * @param string  $userid The userid of the creating user
41*cb71a62aSAndreas Boehler   *
42*cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false.
43*cb71a62aSAndreas Boehler   */
44a1a3b679SAndreas Boehler  public function setCalendarNameForPage($name, $description, $id = null, $userid = null)
45a1a3b679SAndreas Boehler  {
46a1a3b679SAndreas Boehler      if(is_null($id))
47a1a3b679SAndreas Boehler      {
48a1a3b679SAndreas Boehler          global $ID;
49a1a3b679SAndreas Boehler          $id = $ID;
50a1a3b679SAndreas Boehler      }
51a1a3b679SAndreas Boehler      if(is_null($userid))
52a1a3b679SAndreas Boehler        $userid = $_SERVER['REMOTE_USER'];
53a1a3b679SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
54a1a3b679SAndreas Boehler      if($calid === false)
55a1a3b679SAndreas Boehler        return $this->createCalendarForPage($name, $description, $id, $userid);
56a1a3b679SAndreas Boehler
57b269830cSAndreas Boehler      $query = "UPDATE calendars SET displayname=".$this->sqlite->quote_string($name).", ".
58b269830cSAndreas Boehler               "description=".$this->sqlite->quote_string($description)." WHERE ".
59b269830cSAndreas Boehler               "id=".$this->sqlite->quote_string($calid);
60b269830cSAndreas Boehler      $res = $this->sqlite->query($query);
61b269830cSAndreas Boehler      if($res !== false)
62b269830cSAndreas Boehler        return true;
63b269830cSAndreas Boehler      return false;
64a1a3b679SAndreas Boehler  }
65a1a3b679SAndreas Boehler
66*cb71a62aSAndreas Boehler  /**
67*cb71a62aSAndreas Boehler   * Save the personal settings to the SQLite database 'calendarsettings'.
68*cb71a62aSAndreas Boehler   *
69*cb71a62aSAndreas Boehler   * @param array  $settings The settings array to store
70*cb71a62aSAndreas Boehler   * @param string $userid (optional) The userid to store
71*cb71a62aSAndreas Boehler   *
72*cb71a62aSAndreas Boehler   * @param boolean True on success, otherwise false
73*cb71a62aSAndreas Boehler   */
74a495d34cSAndreas Boehler  public function savePersonalSettings($settings, $userid = null)
75a495d34cSAndreas Boehler  {
76a495d34cSAndreas Boehler      if(is_null($userid))
77a495d34cSAndreas Boehler          $userid = $_SERVER['REMOTE_USER'];
78a495d34cSAndreas Boehler      $this->sqlite->query("BEGIN TRANSACTION");
79a495d34cSAndreas Boehler
80bd883736SAndreas Boehler      $query = "DELETE FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid);
81bd883736SAndreas Boehler      $this->sqlite->query($query);
82bd883736SAndreas Boehler
83a495d34cSAndreas Boehler      foreach($settings as $key => $value)
84a495d34cSAndreas Boehler      {
85bd883736SAndreas Boehler          $query = "INSERT INTO calendarsettings (userid, key, value) VALUES (".
86a495d34cSAndreas Boehler                   $this->sqlite->quote_string($userid).", ".
87a495d34cSAndreas Boehler                   $this->sqlite->quote_string($key).", ".
88a495d34cSAndreas Boehler                   $this->sqlite->quote_string($value).")";
89a495d34cSAndreas Boehler          $res = $this->sqlite->query($query);
90a495d34cSAndreas Boehler          if($res === false)
91a495d34cSAndreas Boehler              return false;
92a495d34cSAndreas Boehler      }
93a495d34cSAndreas Boehler      $this->sqlite->query("COMMIT TRANSACTION");
94a495d34cSAndreas Boehler      return true;
95a495d34cSAndreas Boehler  }
96a495d34cSAndreas Boehler
97*cb71a62aSAndreas Boehler  /**
98*cb71a62aSAndreas Boehler   * Retrieve the settings array for a given user id.
99*cb71a62aSAndreas Boehler   * Some sane defaults are returned, currently:
100*cb71a62aSAndreas Boehler   *
101*cb71a62aSAndreas Boehler   *    timezone    => local
102*cb71a62aSAndreas Boehler   *    weeknumbers => 0
103*cb71a62aSAndreas Boehler   *    workweek    => 0
104*cb71a62aSAndreas Boehler   *
105*cb71a62aSAndreas Boehler   * @param string $userid (optional) The user id to retrieve
106*cb71a62aSAndreas Boehler   *
107*cb71a62aSAndreas Boehler   * @return array The settings array
108*cb71a62aSAndreas Boehler   */
109a495d34cSAndreas Boehler  public function getPersonalSettings($userid = null)
110a495d34cSAndreas Boehler  {
111a495d34cSAndreas Boehler      if(is_null($userid))
112a495d34cSAndreas Boehler        $userid = $_SERVER['REMOTE_USER'];
113bd883736SAndreas Boehler      // Some sane default settings
114bd883736SAndreas Boehler      $settings = array(
115bd883736SAndreas Boehler        'timezone' => 'local',
116bd883736SAndreas Boehler        'weeknumbers' => '0',
117bd883736SAndreas Boehler        'workweek' => '0'
118bd883736SAndreas Boehler      );
119a495d34cSAndreas Boehler      $query = "SELECT key, value FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid);
120a495d34cSAndreas Boehler      $res = $this->sqlite->query($query);
121a495d34cSAndreas Boehler      $arr = $this->sqlite->res2arr($res);
122a495d34cSAndreas Boehler      foreach($arr as $row)
123a495d34cSAndreas Boehler      {
124a495d34cSAndreas Boehler          $settings[$row['key']] = $row['value'];
125a495d34cSAndreas Boehler      }
126a495d34cSAndreas Boehler      return $settings;
127a495d34cSAndreas Boehler  }
128a495d34cSAndreas Boehler
129*cb71a62aSAndreas Boehler  /**
130*cb71a62aSAndreas Boehler   * Retrieve the calendar ID based on a page ID from the SQLite table
131*cb71a62aSAndreas Boehler   * 'pagetocalendarmapping'.
132*cb71a62aSAndreas Boehler   *
133*cb71a62aSAndreas Boehler   * @param string $id (optional) The page ID to retrieve the corresponding calendar
134*cb71a62aSAndreas Boehler   *
135*cb71a62aSAndreas Boehler   * @return mixed the ID on success, otherwise false
136*cb71a62aSAndreas Boehler   */
137a1a3b679SAndreas Boehler  public function getCalendarIdForPage($id = null)
138a1a3b679SAndreas Boehler  {
139a1a3b679SAndreas Boehler      if(is_null($id))
140a1a3b679SAndreas Boehler      {
141a1a3b679SAndreas Boehler          global $ID;
142a1a3b679SAndreas Boehler          $id = $ID;
143a1a3b679SAndreas Boehler      }
144a1a3b679SAndreas Boehler
145a1a3b679SAndreas Boehler      $query = "SELECT calid FROM pagetocalendarmapping WHERE page=".$this->sqlite->quote_string($id);
146a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
147a1a3b679SAndreas Boehler      $row = $this->sqlite->res2row($res);
148a1a3b679SAndreas Boehler      if(isset($row['calid']))
149a1a3b679SAndreas Boehler        return $row['calid'];
150a1a3b679SAndreas Boehler      else
151a1a3b679SAndreas Boehler        return false;
152a1a3b679SAndreas Boehler  }
153a1a3b679SAndreas Boehler
154*cb71a62aSAndreas Boehler  /**
155*cb71a62aSAndreas Boehler   * Retrieve the complete calendar id to page mapping.
156*cb71a62aSAndreas Boehler   * This is necessary to be able to retrieve a list of
157*cb71a62aSAndreas Boehler   * calendars for a given user and check the access rights.
158*cb71a62aSAndreas Boehler   *
159*cb71a62aSAndreas Boehler   * @return array The mapping array
160*cb71a62aSAndreas Boehler   */
161a1a3b679SAndreas Boehler  public function getCalendarIdToPageMapping()
162a1a3b679SAndreas Boehler  {
163a1a3b679SAndreas Boehler      $query = "SELECT calid, page FROM pagetocalendarmapping";
164a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
165a1a3b679SAndreas Boehler      $arr = $this->sqlite->res2arr($res);
166a1a3b679SAndreas Boehler      return $arr;
167a1a3b679SAndreas Boehler  }
168a1a3b679SAndreas Boehler
169*cb71a62aSAndreas Boehler  /**
170*cb71a62aSAndreas Boehler   * Retrieve all calendar IDs a given user has access to.
171*cb71a62aSAndreas Boehler   * The user is specified by the principalUri, so the
172*cb71a62aSAndreas Boehler   * user name is actually split from the URI component.
173*cb71a62aSAndreas Boehler   *
174*cb71a62aSAndreas Boehler   * Access rights are checked against DokuWiki's ACL
175*cb71a62aSAndreas Boehler   * and applied accordingly.
176*cb71a62aSAndreas Boehler   *
177*cb71a62aSAndreas Boehler   * @param string $principalUri The principal URI to work on
178*cb71a62aSAndreas Boehler   *
179*cb71a62aSAndreas Boehler   * @return array An associative array of calendar IDs
180*cb71a62aSAndreas Boehler   */
181a1a3b679SAndreas Boehler  public function getCalendarIdsForUser($principalUri)
182a1a3b679SAndreas Boehler  {
183a1a3b679SAndreas Boehler      $user = explode('/', $principalUri);
184a1a3b679SAndreas Boehler      $user = end($user);
185a1a3b679SAndreas Boehler      $mapping = $this->getCalendarIdToPageMapping();
186a1a3b679SAndreas Boehler      $calids = array();
187a1a3b679SAndreas Boehler      foreach($mapping as $row)
188a1a3b679SAndreas Boehler      {
189a1a3b679SAndreas Boehler          $id = $row['calid'];
190a1a3b679SAndreas Boehler          $page = $row['page'];
191a1a3b679SAndreas Boehler          $acl = auth_quickaclcheck($page);
192a1a3b679SAndreas Boehler          if($acl >= AUTH_READ)
193a1a3b679SAndreas Boehler          {
194a1a3b679SAndreas Boehler              $write = $acl > AUTH_READ;
195a1a3b679SAndreas Boehler              $calids[$id] = array('readonly' => !$write);
196a1a3b679SAndreas Boehler          }
197a1a3b679SAndreas Boehler      }
198a1a3b679SAndreas Boehler      return $calids;
199a1a3b679SAndreas Boehler  }
200a1a3b679SAndreas Boehler
201*cb71a62aSAndreas Boehler  /**
202*cb71a62aSAndreas Boehler   * Create a new calendar for a given page ID and set name and description
203*cb71a62aSAndreas Boehler   * accordingly. Also update the pagetocalendarmapping table on success.
204*cb71a62aSAndreas Boehler   *
205*cb71a62aSAndreas Boehler   * @param string $name The calendar's name
206*cb71a62aSAndreas Boehler   * @param string $description The calendar's description
207*cb71a62aSAndreas Boehler   * @param string $id (optional) The page ID to work on
208*cb71a62aSAndreas Boehler   * @param string $userid (optional) The user ID that created the calendar
209*cb71a62aSAndreas Boehler   *
210*cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
211*cb71a62aSAndreas Boehler   */
212a1a3b679SAndreas Boehler  public function createCalendarForPage($name, $description, $id = null, $userid = null)
213a1a3b679SAndreas Boehler  {
214a1a3b679SAndreas Boehler      if(is_null($id))
215a1a3b679SAndreas Boehler      {
216a1a3b679SAndreas Boehler          global $ID;
217a1a3b679SAndreas Boehler          $id = $ID;
218a1a3b679SAndreas Boehler      }
219a1a3b679SAndreas Boehler      if(is_null($userid))
220a1a3b679SAndreas Boehler          $userid = $_SERVER['REMOTE_USER'];
221a1a3b679SAndreas Boehler      $values = array('principals/'.$userid,
222a1a3b679SAndreas Boehler                      $name,
223a1a3b679SAndreas Boehler                      str_replace(array('/', ' ', ':'), '_', $id),
224a1a3b679SAndreas Boehler                      $description,
225a1a3b679SAndreas Boehler                      'VEVENT,VTODO',
22655a741c0SAndreas Boehler                      0,
22755a741c0SAndreas Boehler                      1);
22855a741c0SAndreas Boehler      $query = "INSERT INTO calendars (principaluri, displayname, uri, description, components, transparent, synctoken) VALUES (".$this->sqlite->quote_and_join($values, ',').");";
229a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
23055a741c0SAndreas Boehler      if($res === false)
23155a741c0SAndreas Boehler        return false;
232*cb71a62aSAndreas Boehler
233*cb71a62aSAndreas Boehler      // Get the new calendar ID
234a1a3b679SAndreas Boehler      $query = "SELECT id FROM calendars WHERE principaluri=".$this->sqlite->quote_string($values[0])." AND ".
235a1a3b679SAndreas Boehler               "displayname=".$this->sqlite->quote_string($values[1])." AND ".
236a1a3b679SAndreas Boehler               "uri=".$this->sqlite->quote_string($values[2])." AND ".
237a1a3b679SAndreas Boehler               "description=".$this->sqlite->quote_string($values[3]);
238a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
239a1a3b679SAndreas Boehler      $row = $this->sqlite->res2row($res);
240*cb71a62aSAndreas Boehler
241*cb71a62aSAndreas Boehler      // Update the pagetocalendarmapping table with the new calendar ID
242a1a3b679SAndreas Boehler      if(isset($row['id']))
243a1a3b679SAndreas Boehler      {
244a1a3b679SAndreas Boehler          $values = array($id, $row['id']);
245a1a3b679SAndreas Boehler          $query = "INSERT INTO pagetocalendarmapping (page, calid) VALUES (".$this->sqlite->quote_and_join($values, ',').")";
246a1a3b679SAndreas Boehler          $res = $this->sqlite->query($query);
24755a741c0SAndreas Boehler          return ($res !== false);
248a1a3b679SAndreas Boehler      }
249a1a3b679SAndreas Boehler
250a1a3b679SAndreas Boehler      return false;
251a1a3b679SAndreas Boehler  }
252a1a3b679SAndreas Boehler
253*cb71a62aSAndreas Boehler  /**
254*cb71a62aSAndreas Boehler   * Add a new iCal entry for a given page, i.e. a given calendar.
255*cb71a62aSAndreas Boehler   *
256*cb71a62aSAndreas Boehler   * The parameter array needs to contain
257*cb71a62aSAndreas Boehler   *   timezone         => The timezone of the entries
258*cb71a62aSAndreas Boehler   *   detectedtz       => The timezone as detected by the browser
259*cb71a62aSAndreas Boehler   *   eventfrom        => The event's start date
260*cb71a62aSAndreas Boehler   *   eventfromtime    => The event's start time
261*cb71a62aSAndreas Boehler   *   eventto          => The event's end date
262*cb71a62aSAndreas Boehler   *   eventtotime      => The event's end time
263*cb71a62aSAndreas Boehler   *   eventname        => The event's name
264*cb71a62aSAndreas Boehler   *   eventdescription => The event's description
265*cb71a62aSAndreas Boehler   *
266*cb71a62aSAndreas Boehler   * @param string $id The page ID to work on
267*cb71a62aSAndreas Boehler   * @param string $user The user who created the calendar
268*cb71a62aSAndreas Boehler   * @param string $params A parameter array with values to create
269*cb71a62aSAndreas Boehler   *
270*cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
271*cb71a62aSAndreas Boehler   */
272a1a3b679SAndreas Boehler  public function addCalendarEntryToCalendarForPage($id, $user, $params)
273a1a3b679SAndreas Boehler  {
274bd883736SAndreas Boehler      $settings = $this->getPersonalSettings($user);
275bd883736SAndreas Boehler      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
276bd883736SAndreas Boehler          $timezone = new \DateTimeZone($settings['timezone']);
277a25c89eaSAndreas Boehler      elseif($settings['timezone'] === 'local')
278a25c89eaSAndreas Boehler          $timezone = new \DateTimeZone($params['detectedtz']);
279bd883736SAndreas Boehler      else
280bd883736SAndreas Boehler          $timezone = new \DateTimeZone('UTC');
281*cb71a62aSAndreas Boehler
282*cb71a62aSAndreas Boehler      // Retrieve dates from settings
283b269830cSAndreas Boehler      $startDate = explode('-', $params['eventfrom']);
284b269830cSAndreas Boehler      $startTime = explode(':', $params['eventfromtime']);
285b269830cSAndreas Boehler      $endDate = explode('-', $params['eventto']);
286b269830cSAndreas Boehler      $endTime = explode(':', $params['eventtotime']);
287*cb71a62aSAndreas Boehler
288*cb71a62aSAndreas Boehler      // Load SabreDAV
289a1a3b679SAndreas Boehler      require_once('vendor/autoload.php');
290a1a3b679SAndreas Boehler      $vcalendar = new \Sabre\VObject\Component\VCalendar();
291*cb71a62aSAndreas Boehler
292*cb71a62aSAndreas Boehler      // Add VCalendar, UID and Event Name
293a1a3b679SAndreas Boehler      $event = $vcalendar->add('VEVENT');
294b269830cSAndreas Boehler      $uuid = \Sabre\VObject\UUIDUtil::getUUID();
295b269830cSAndreas Boehler      $event->add('UID', $uuid);
296a1a3b679SAndreas Boehler      $event->summary = $params['eventname'];
297*cb71a62aSAndreas Boehler
298*cb71a62aSAndreas Boehler      // Add a description if requested
2990eebc909SAndreas Boehler      $description = $params['eventdescription'];
3000eebc909SAndreas Boehler      if($description !== '')
3010eebc909SAndreas Boehler        $event->add('DESCRIPTION', $description);
302*cb71a62aSAndreas Boehler
303*cb71a62aSAndreas Boehler      // Create a timestamp for last modified, created and dtstamp values in UTC
304b269830cSAndreas Boehler      $dtStamp = new \DateTime(null, new \DateTimeZone('UTC'));
305b269830cSAndreas Boehler      $event->add('DTSTAMP', $dtStamp);
306b269830cSAndreas Boehler      $event->add('CREATED', $dtStamp);
307b269830cSAndreas Boehler      $event->add('LAST-MODIFIED', $dtStamp);
308*cb71a62aSAndreas Boehler
309*cb71a62aSAndreas Boehler      // Adjust the start date, based on the given timezone information
310b269830cSAndreas Boehler      $dtStart = new \DateTime();
311a25c89eaSAndreas Boehler      $dtStart->setTimezone($timezone);
312b269830cSAndreas Boehler      $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2]));
313*cb71a62aSAndreas Boehler
314*cb71a62aSAndreas Boehler      // Only add the time values if it's not an allday event
315b269830cSAndreas Boehler      if($params['allday'] != '1')
316b269830cSAndreas Boehler        $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0);
317*cb71a62aSAndreas Boehler
318*cb71a62aSAndreas Boehler      // Adjust the end date, based on the given timezone information
319b269830cSAndreas Boehler      $dtEnd = new \DateTime();
320a25c89eaSAndreas Boehler      $dtEnd->setTimezone($timezone);
321b269830cSAndreas Boehler      $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2]));
322*cb71a62aSAndreas Boehler
323*cb71a62aSAndreas Boehler      // Only add the time values if it's not an allday event
324b269830cSAndreas Boehler      if($params['allday'] != '1')
325b269830cSAndreas Boehler        $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0);
326*cb71a62aSAndreas Boehler
327b269830cSAndreas Boehler      // According to the VCal spec, we need to add a whole day here
328b269830cSAndreas Boehler      if($params['allday'] == '1')
329b269830cSAndreas Boehler          $dtEnd->add(new \DateInterval('P1D'));
330*cb71a62aSAndreas Boehler
331*cb71a62aSAndreas Boehler      // Really add Start and End events
332b269830cSAndreas Boehler      $dtStartEv = $event->add('DTSTART', $dtStart);
333b269830cSAndreas Boehler      $dtEndEv = $event->add('DTEND', $dtEnd);
334*cb71a62aSAndreas Boehler
335*cb71a62aSAndreas Boehler      // Adjust the DATE format for allday events
336b269830cSAndreas Boehler      if($params['allday'] == '1')
337b269830cSAndreas Boehler      {
338b269830cSAndreas Boehler          $dtStartEv['VALUE'] = 'DATE';
339b269830cSAndreas Boehler          $dtEndEv['VALUE'] = 'DATE';
340b269830cSAndreas Boehler      }
341*cb71a62aSAndreas Boehler
342*cb71a62aSAndreas Boehler      // Actually add the values to the database
343a1a3b679SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
344a1a3b679SAndreas Boehler      $uri = uniqid('dokuwiki-').'.ics';
345a1a3b679SAndreas Boehler      $now = new DateTime();
346a1a3b679SAndreas Boehler      $eventStr = $vcalendar->serialize();
347a1a3b679SAndreas Boehler
348a1a3b679SAndreas Boehler      $values = array($calid,
349a1a3b679SAndreas Boehler                      $uri,
350a1a3b679SAndreas Boehler                      $eventStr,
351a1a3b679SAndreas Boehler                      $now->getTimestamp(),
352a1a3b679SAndreas Boehler                      'VEVENT',
353a1a3b679SAndreas Boehler                      $event->DTSTART->getDateTime()->getTimeStamp(),
354a1a3b679SAndreas Boehler                      $event->DTEND->getDateTime()->getTimeStamp(),
355a1a3b679SAndreas Boehler                      strlen($eventStr),
356a1a3b679SAndreas Boehler                      md5($eventStr),
357*cb71a62aSAndreas Boehler                      $uuid
358a1a3b679SAndreas Boehler      );
359a1a3b679SAndreas Boehler
360a1a3b679SAndreas Boehler      $query = "INSERT INTO calendarobjects (calendarid, uri, calendardata, lastmodified, componenttype, firstoccurence, lastoccurence, size, etag, uid) VALUES (".$this->sqlite->quote_and_join($values, ',').")";
361a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
362*cb71a62aSAndreas Boehler
363*cb71a62aSAndreas Boehler      // If successfully, update the sync token database
36455a741c0SAndreas Boehler      if($res !== false)
36555a741c0SAndreas Boehler      {
36655a741c0SAndreas Boehler          $this->updateSyncTokenLog($calid, $uri, 'added');
367a1a3b679SAndreas Boehler          return true;
368a1a3b679SAndreas Boehler      }
36955a741c0SAndreas Boehler      return false;
37055a741c0SAndreas Boehler  }
371a1a3b679SAndreas Boehler
372*cb71a62aSAndreas Boehler  /**
373*cb71a62aSAndreas Boehler   * Retrieve the calendar settings of a given calendar id
374*cb71a62aSAndreas Boehler   *
375*cb71a62aSAndreas Boehler   * @param string $calid The calendar ID
376*cb71a62aSAndreas Boehler   *
377*cb71a62aSAndreas Boehler   * @return array The calendar settings array
378*cb71a62aSAndreas Boehler   */
379b269830cSAndreas Boehler  public function getCalendarSettings($calid)
380b269830cSAndreas Boehler  {
381b269830cSAndreas Boehler      $query = "SELECT principaluri, displayname, uri, description, components, transparent, synctoken FROM calendars WHERE id=".$this->sqlite->quote_string($calid);
382b269830cSAndreas Boehler      $res = $this->sqlite->query($query);
383b269830cSAndreas Boehler      $row = $this->sqlite->res2row($res);
384b269830cSAndreas Boehler      return $row;
385b269830cSAndreas Boehler  }
386b269830cSAndreas Boehler
387*cb71a62aSAndreas Boehler  /**
388*cb71a62aSAndreas Boehler   * Retrieve all events that are within a given date range,
389*cb71a62aSAndreas Boehler   * based on the timezone setting.
390*cb71a62aSAndreas Boehler   *
391*cb71a62aSAndreas Boehler   * There is also support for retrieving recurring events,
392*cb71a62aSAndreas Boehler   * using Sabre's VObject Iterator. Recurring events are represented
393*cb71a62aSAndreas Boehler   * as individual calendar entries with the same UID.
394*cb71a62aSAndreas Boehler   *
395*cb71a62aSAndreas Boehler   * @param string $id The page ID to work with
396*cb71a62aSAndreas Boehler   * @param string $user The user ID to work with
397*cb71a62aSAndreas Boehler   * @param string $startDate The start date as a string
398*cb71a62aSAndreas Boehler   * @param string $endDate The end date as a string
399*cb71a62aSAndreas Boehler   *
400*cb71a62aSAndreas Boehler   * @return array An array containing the calendar entries.
401*cb71a62aSAndreas Boehler   */
402a1a3b679SAndreas Boehler  public function getEventsWithinDateRange($id, $user, $startDate, $endDate)
403a1a3b679SAndreas Boehler  {
404bd883736SAndreas Boehler      $settings = $this->getPersonalSettings($user);
405bd883736SAndreas Boehler      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
406bd883736SAndreas Boehler          $timezone = new \DateTimeZone($settings['timezone']);
407bd883736SAndreas Boehler      else
408bd883736SAndreas Boehler          $timezone = new \DateTimeZone('UTC');
409a1a3b679SAndreas Boehler      $data = array();
410*cb71a62aSAndreas Boehler
411*cb71a62aSAndreas Boehler      // Load SabreDAV
412a1a3b679SAndreas Boehler      require_once('vendor/autoload.php');
413a1a3b679SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
414a1a3b679SAndreas Boehler      $startTs = new \DateTime($startDate);
415a1a3b679SAndreas Boehler      $endTs = new \DateTime($endDate);
416*cb71a62aSAndreas Boehler
417*cb71a62aSAndreas Boehler      // Retrieve matching calendar objects
418ebc4eb57SAndreas Boehler      $query = "SELECT calendardata, componenttype, uid FROM calendarobjects WHERE calendarid=".
419ebc4eb57SAndreas Boehler                $this->sqlite->quote_string($calid)." AND firstoccurence < ".
420ebc4eb57SAndreas Boehler                $this->sqlite->quote_string($endTs->getTimestamp())." AND lastoccurence > ".
421ebc4eb57SAndreas Boehler                $this->sqlite->quote_string($startTs->getTimestamp());
422a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
423a1a3b679SAndreas Boehler      $arr = $this->sqlite->res2arr($res);
424*cb71a62aSAndreas Boehler
425*cb71a62aSAndreas Boehler      // Parse individual calendar entries
426a1a3b679SAndreas Boehler      foreach($arr as $row)
427a1a3b679SAndreas Boehler      {
428a1a3b679SAndreas Boehler          if(isset($row['calendardata']))
429a1a3b679SAndreas Boehler          {
430b269830cSAndreas Boehler              $entry = array();
431a1a3b679SAndreas Boehler              $vcal = \Sabre\VObject\Reader::read($row['calendardata']);
432ebc4eb57SAndreas Boehler              $recurrence = $vcal->VEVENT->RRULE;
433*cb71a62aSAndreas Boehler              // If it is a recurring event, pass it through Sabre's EventIterator
434ebc4eb57SAndreas Boehler              if($recurrence != null)
435ebc4eb57SAndreas Boehler              {
436ebc4eb57SAndreas Boehler                  $rEvents = new \Sabre\VObject\Recur\EventIterator(array($vcal->VEVENT));
437ebc4eb57SAndreas Boehler                  $rEvents->rewind();
438ebc4eb57SAndreas Boehler                  $done = false;
439ebc4eb57SAndreas Boehler                  while($rEvents->valid() && !$done)
440ebc4eb57SAndreas Boehler                  {
441ebc4eb57SAndreas Boehler                      $event = $rEvents->getEventObject();
442*cb71a62aSAndreas Boehler                      // If we are after the given time range, exit
443ebc4eb57SAndreas Boehler                      if(($rEvents->getDtStart()->getTimestamp() > $endTs->getTimestamp()) &&
444ebc4eb57SAndreas Boehler                         ($rEvents->getDtEnd()->getTimestamp() > $endTs->getTimestamp()))
445ebc4eb57SAndreas Boehler                        $done = true;
446*cb71a62aSAndreas Boehler
447*cb71a62aSAndreas Boehler                      // If we are before the given time range, continue
448ebc4eb57SAndreas Boehler                      if($rEvents->getDtEnd()->getTimestamp() < $startTs->getTimestamp())
449ebc4eb57SAndreas Boehler                      {
450ebc4eb57SAndreas Boehler                          $rEvents->next();
451ebc4eb57SAndreas Boehler                          continue;
452ebc4eb57SAndreas Boehler                      }
453*cb71a62aSAndreas Boehler
454*cb71a62aSAndreas Boehler                      // If we are within the given time range, parse the event
455ebc4eb57SAndreas Boehler                      $data[] = $this->convertIcalDataToEntry($event, $timezone, $row['uid']);
456ebc4eb57SAndreas Boehler                      $rEvents->next();
457ebc4eb57SAndreas Boehler                  }
458ebc4eb57SAndreas Boehler              }
459ebc4eb57SAndreas Boehler              else
460ebc4eb57SAndreas Boehler                $data[] = $this->convertIcalDataToEntry($vcal->VEVENT, $timezone, $row['uid']);
461ebc4eb57SAndreas Boehler          }
462ebc4eb57SAndreas Boehler      }
463ebc4eb57SAndreas Boehler      return $data;
464ebc4eb57SAndreas Boehler  }
465ebc4eb57SAndreas Boehler
466*cb71a62aSAndreas Boehler  /**
467*cb71a62aSAndreas Boehler   * Helper function that parses the iCal data of a VEVENT to a calendar entry.
468*cb71a62aSAndreas Boehler   *
469*cb71a62aSAndreas Boehler   * @param \Sabre\VObject\VEvent $event The event to parse
470*cb71a62aSAndreas Boehler   * @param \DateTimeZone $timezone The timezone object
471*cb71a62aSAndreas Boehler   * @param string $uid The entry's UID
472*cb71a62aSAndreas Boehler   *
473*cb71a62aSAndreas Boehler   * @return array The parse calendar entry
474*cb71a62aSAndreas Boehler   */
475ebc4eb57SAndreas Boehler  private function convertIcalDataToEntry($event, $timezone, $uid)
476ebc4eb57SAndreas Boehler  {
477ebc4eb57SAndreas Boehler      $entry = array();
478ebc4eb57SAndreas Boehler      $start = $event->DTSTART;
479*cb71a62aSAndreas Boehler      // Parse only if the start date/time is present
480b269830cSAndreas Boehler      if($start !== null)
481b269830cSAndreas Boehler      {
482b269830cSAndreas Boehler        $dtStart = $start->getDateTime();
483b269830cSAndreas Boehler        $dtStart->setTimezone($timezone);
484b269830cSAndreas Boehler        $entry['start'] = $dtStart->format(\DateTime::ATOM);
485b269830cSAndreas Boehler        if($start['VALUE'] == 'DATE')
486b269830cSAndreas Boehler          $entry['allDay'] = true;
487b269830cSAndreas Boehler        else
488b269830cSAndreas Boehler          $entry['allDay'] = false;
489b269830cSAndreas Boehler      }
490ebc4eb57SAndreas Boehler      $end = $event->DTEND;
491*cb71a62aSAndreas Boehler      // Parse onlyl if the end date/time is present
492b269830cSAndreas Boehler      if($end !== null)
493b269830cSAndreas Boehler      {
494b269830cSAndreas Boehler        $dtEnd = $end->getDateTime();
495b269830cSAndreas Boehler        $dtEnd->setTimezone($timezone);
496b269830cSAndreas Boehler        $entry['end'] = $dtEnd->format(\DateTime::ATOM);
497b269830cSAndreas Boehler      }
498ebc4eb57SAndreas Boehler      $description = $event->DESCRIPTION;
4990eebc909SAndreas Boehler      if($description !== null)
5000eebc909SAndreas Boehler        $entry['description'] = (string)$description;
5010eebc909SAndreas Boehler      else
5020eebc909SAndreas Boehler        $entry['description'] = '';
503ebc4eb57SAndreas Boehler      $entry['title'] = (string)$event->summary;
504ebc4eb57SAndreas Boehler      $entry['id'] = $uid;
505ebc4eb57SAndreas Boehler      return $entry;
506a1a3b679SAndreas Boehler  }
507a1a3b679SAndreas Boehler
508*cb71a62aSAndreas Boehler  /**
509*cb71a62aSAndreas Boehler   * Retrieve an event by its UID
510*cb71a62aSAndreas Boehler   *
511*cb71a62aSAndreas Boehler   * @param string $uid The event's UID
512*cb71a62aSAndreas Boehler   *
513*cb71a62aSAndreas Boehler   * @return mixed The table row with the given event
514*cb71a62aSAndreas Boehler   */
515a1a3b679SAndreas Boehler  public function getEventWithUid($uid)
516a1a3b679SAndreas Boehler  {
51755a741c0SAndreas Boehler      $query = "SELECT calendardata, calendarid, componenttype, uri FROM calendarobjects WHERE uid=".
518a1a3b679SAndreas Boehler                $this->sqlite->quote_string($uid);
519a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
520a1a3b679SAndreas Boehler      $row = $this->sqlite->res2row($res);
521a1a3b679SAndreas Boehler      return $row;
522a1a3b679SAndreas Boehler  }
523a1a3b679SAndreas Boehler
524*cb71a62aSAndreas Boehler  /**
525*cb71a62aSAndreas Boehler   * Retrieve all calendar events for a given calendar ID
526*cb71a62aSAndreas Boehler   *
527*cb71a62aSAndreas Boehler   * @param string $calid The calendar's ID
528*cb71a62aSAndreas Boehler   *
529*cb71a62aSAndreas Boehler   * @return array An array containing all calendar data
530*cb71a62aSAndreas Boehler   */
531f69bb449SAndreas Boehler  public function getAllCalendarEvents($calid)
532f69bb449SAndreas Boehler  {
533f69bb449SAndreas Boehler      $query = "SELECT calendardata, uid, componenttype, uri FROM calendarobjects WHERE calendarid=".
534f69bb449SAndreas Boehler               $this->sqlite->quote_string($calid);
535f69bb449SAndreas Boehler      $res = $this->sqlite->query($query);
536f69bb449SAndreas Boehler      $arr = $this->sqlite->res2arr($res);
537f69bb449SAndreas Boehler      return $arr;
538f69bb449SAndreas Boehler  }
539f69bb449SAndreas Boehler
540*cb71a62aSAndreas Boehler  /**
541*cb71a62aSAndreas Boehler   * Edit a calendar entry for a page, given by its parameters.
542*cb71a62aSAndreas Boehler   * The params array has the same format as @see addCalendarEntryForPage
543*cb71a62aSAndreas Boehler   *
544*cb71a62aSAndreas Boehler   * @param string $id The page's ID to work on
545*cb71a62aSAndreas Boehler   * @param string $user The user's ID to work on
546*cb71a62aSAndreas Boehler   * @param array $params The parameter array for the edited calendar event
547*cb71a62aSAndreas Boehler   *
548*cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
549*cb71a62aSAndreas Boehler   */
550a1a3b679SAndreas Boehler  public function editCalendarEntryForPage($id, $user, $params)
551a1a3b679SAndreas Boehler  {
552bd883736SAndreas Boehler      $settings = $this->getPersonalSettings($user);
553bd883736SAndreas Boehler      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
554bd883736SAndreas Boehler          $timezone = new \DateTimeZone($settings['timezone']);
555a25c89eaSAndreas Boehler      elseif($settings['timezone'] === 'local')
556a25c89eaSAndreas Boehler          $timezone = new \DateTimeZone($params['detectedtz']);
557bd883736SAndreas Boehler      else
558bd883736SAndreas Boehler          $timezone = new \DateTimeZone('UTC');
559*cb71a62aSAndreas Boehler
560*cb71a62aSAndreas Boehler      // Parse dates
561b269830cSAndreas Boehler      $startDate = explode('-', $params['eventfrom']);
562b269830cSAndreas Boehler      $startTime = explode(':', $params['eventfromtime']);
563b269830cSAndreas Boehler      $endDate = explode('-', $params['eventto']);
564b269830cSAndreas Boehler      $endTime = explode(':', $params['eventtotime']);
565*cb71a62aSAndreas Boehler
566*cb71a62aSAndreas Boehler      // Retrieve the existing event based on the UID
56755a741c0SAndreas Boehler      $uid = $params['uid'];
56855a741c0SAndreas Boehler      $event = $this->getEventWithUid($uid);
569*cb71a62aSAndreas Boehler
570*cb71a62aSAndreas Boehler      // Load SabreDAV
571a1a3b679SAndreas Boehler      require_once('vendor/autoload.php');
572a1a3b679SAndreas Boehler      if(!isset($event['calendardata']))
573a1a3b679SAndreas Boehler        return false;
57455a741c0SAndreas Boehler      $uri = $event['uri'];
57555a741c0SAndreas Boehler      $calid = $event['calendarid'];
576*cb71a62aSAndreas Boehler
577*cb71a62aSAndreas Boehler      // Parse the existing event
578a1a3b679SAndreas Boehler      $vcal = \Sabre\VObject\Reader::read($event['calendardata']);
579b269830cSAndreas Boehler      $vevent = $vcal->VEVENT;
580*cb71a62aSAndreas Boehler
581*cb71a62aSAndreas Boehler      // Set the new event values
582b269830cSAndreas Boehler      $vevent->summary = $params['eventname'];
583b269830cSAndreas Boehler      $dtStamp = new \DateTime(null, new \DateTimeZone('UTC'));
5840eebc909SAndreas Boehler      $description = $params['eventdescription'];
585*cb71a62aSAndreas Boehler
586*cb71a62aSAndreas Boehler      // Remove existing timestamps to overwrite them
5870eebc909SAndreas Boehler      $vevent->remove('DESCRIPTION');
588b269830cSAndreas Boehler      $vevent->remove('DTSTAMP');
589b269830cSAndreas Boehler      $vevent->remove('LAST-MODIFIED');
590*cb71a62aSAndreas Boehler
591*cb71a62aSAndreas Boehler      // Add new time stamps and description
592b269830cSAndreas Boehler      $vevent->add('DTSTAMP', $dtStamp);
593b269830cSAndreas Boehler      $vevent->add('LAST-MODIFIED', $dtStamp);
5940eebc909SAndreas Boehler      if($description !== '')
5950eebc909SAndreas Boehler        $vevent->add('DESCRIPTION', $description);
596*cb71a62aSAndreas Boehler
597*cb71a62aSAndreas Boehler      // Setup DTSTART
598b269830cSAndreas Boehler      $dtStart = new \DateTime();
599a25c89eaSAndreas Boehler      $dtStart->setTimezone($timezone);
600b269830cSAndreas Boehler      $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2]));
601b269830cSAndreas Boehler      if($params['allday'] != '1')
602b269830cSAndreas Boehler        $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0);
603*cb71a62aSAndreas Boehler
604*cb71a62aSAndreas Boehler      // Setup DETEND
605b269830cSAndreas Boehler      $dtEnd = new \DateTime();
606a25c89eaSAndreas Boehler      $dtEnd->setTimezone($timezone);
607b269830cSAndreas Boehler      $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2]));
608b269830cSAndreas Boehler      if($params['allday'] != '1')
609b269830cSAndreas Boehler        $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0);
610*cb71a62aSAndreas Boehler
611b269830cSAndreas Boehler      // According to the VCal spec, we need to add a whole day here
612b269830cSAndreas Boehler      if($params['allday'] == '1')
613b269830cSAndreas Boehler          $dtEnd->add(new \DateInterval('P1D'));
614b269830cSAndreas Boehler      $vevent->remove('DTSTART');
615b269830cSAndreas Boehler      $vevent->remove('DTEND');
616b269830cSAndreas Boehler      $dtStartEv = $vevent->add('DTSTART', $dtStart);
617b269830cSAndreas Boehler      $dtEndEv = $vevent->add('DTEND', $dtEnd);
618*cb71a62aSAndreas Boehler
619*cb71a62aSAndreas Boehler      // Remove the time for allday events
620b269830cSAndreas Boehler      if($params['allday'] == '1')
621b269830cSAndreas Boehler      {
622b269830cSAndreas Boehler          $dtStartEv['VALUE'] = 'DATE';
623b269830cSAndreas Boehler          $dtEndEv['VALUE'] = 'DATE';
624b269830cSAndreas Boehler      }
625a1a3b679SAndreas Boehler      $now = new DateTime();
626a1a3b679SAndreas Boehler      $eventStr = $vcal->serialize();
627a1a3b679SAndreas Boehler
628*cb71a62aSAndreas Boehler      // Actually write to the database
629a1a3b679SAndreas Boehler      $query = "UPDATE calendarobjects SET calendardata=".$this->sqlite->quote_string($eventStr).
630a1a3b679SAndreas Boehler               ", lastmodified=".$this->sqlite->quote_string($now->getTimestamp()).
631a1a3b679SAndreas Boehler               ", firstoccurence=".$this->sqlite->quote_string($dtStart->getTimestamp()).
632a1a3b679SAndreas Boehler               ", lastoccurence=".$this->sqlite->quote_string($dtEnd->getTimestamp()).
633a1a3b679SAndreas Boehler               ", size=".strlen($eventStr).
634a1a3b679SAndreas Boehler               ", etag=".$this->sqlite->quote_string(md5($eventStr)).
63555a741c0SAndreas Boehler               " WHERE uid=".$this->sqlite->quote_string($uid);
636a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
63755a741c0SAndreas Boehler      if($res !== false)
63855a741c0SAndreas Boehler      {
63955a741c0SAndreas Boehler          $this->updateSyncTokenLog($calid, $uri, 'modified');
640a1a3b679SAndreas Boehler          return true;
641a1a3b679SAndreas Boehler      }
64255a741c0SAndreas Boehler      return false;
64355a741c0SAndreas Boehler  }
644a1a3b679SAndreas Boehler
645*cb71a62aSAndreas Boehler  /**
646*cb71a62aSAndreas Boehler   * Delete a calendar entry for a given page. Actually, the event is removed
647*cb71a62aSAndreas Boehler   * based on the entry's UID, so that page ID is no used.
648*cb71a62aSAndreas Boehler   *
649*cb71a62aSAndreas Boehler   * @param string $id The page's ID (unused)
650*cb71a62aSAndreas Boehler   * @param array $params The parameter array to work with
651*cb71a62aSAndreas Boehler   *
652*cb71a62aSAndreas Boehler   * @return boolean True
653*cb71a62aSAndreas Boehler   */
654a1a3b679SAndreas Boehler  public function deleteCalendarEntryForPage($id, $params)
655a1a3b679SAndreas Boehler  {
656a1a3b679SAndreas Boehler      $uid = $params['uid'];
65755a741c0SAndreas Boehler      $event = $this->getEventWithUid($uid);
6582c14b82bSAndreas Boehler      $calid = $event['calendarid'];
65955a741c0SAndreas Boehler      $uri = $event['uri'];
660a1a3b679SAndreas Boehler      $query = "DELETE FROM calendarobjects WHERE uid=".$this->sqlite->quote_string($uid);
661a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
66255a741c0SAndreas Boehler      if($res !== false)
66355a741c0SAndreas Boehler      {
66455a741c0SAndreas Boehler          $this->updateSyncTokenLog($calid, $uri, 'deleted');
66555a741c0SAndreas Boehler      }
666a1a3b679SAndreas Boehler      return true;
667a1a3b679SAndreas Boehler  }
668a1a3b679SAndreas Boehler
669*cb71a62aSAndreas Boehler  /**
670*cb71a62aSAndreas Boehler   * Retrieve the current sync token for a calendar
671*cb71a62aSAndreas Boehler   *
672*cb71a62aSAndreas Boehler   * @param string $calid The calendar id
673*cb71a62aSAndreas Boehler   *
674*cb71a62aSAndreas Boehler   * @return mixed The synctoken or false
675*cb71a62aSAndreas Boehler   */
67655a741c0SAndreas Boehler  public function getSyncTokenForCalendar($calid)
67755a741c0SAndreas Boehler  {
678b269830cSAndreas Boehler      $row = $this->getCalendarSettings($calid);
67955a741c0SAndreas Boehler      if(isset($row['synctoken']))
68055a741c0SAndreas Boehler          return $row['synctoken'];
68155a741c0SAndreas Boehler      return false;
68255a741c0SAndreas Boehler  }
68355a741c0SAndreas Boehler
684*cb71a62aSAndreas Boehler  /**
685*cb71a62aSAndreas Boehler   * Helper function to convert the operation name to
686*cb71a62aSAndreas Boehler   * an operation code as stored in the database
687*cb71a62aSAndreas Boehler   *
688*cb71a62aSAndreas Boehler   * @param string $operationName The operation name
689*cb71a62aSAndreas Boehler   *
690*cb71a62aSAndreas Boehler   * @return mixed The operation code or false
691*cb71a62aSAndreas Boehler   */
69255a741c0SAndreas Boehler  public function operationNameToOperation($operationName)
69355a741c0SAndreas Boehler  {
69455a741c0SAndreas Boehler      switch($operationName)
69555a741c0SAndreas Boehler      {
69655a741c0SAndreas Boehler          case 'added':
69755a741c0SAndreas Boehler              return 1;
69855a741c0SAndreas Boehler          break;
69955a741c0SAndreas Boehler          case 'modified':
70055a741c0SAndreas Boehler              return 2;
70155a741c0SAndreas Boehler          break;
70255a741c0SAndreas Boehler          case 'deleted':
70355a741c0SAndreas Boehler              return 3;
70455a741c0SAndreas Boehler          break;
70555a741c0SAndreas Boehler      }
70655a741c0SAndreas Boehler      return false;
70755a741c0SAndreas Boehler  }
70855a741c0SAndreas Boehler
709*cb71a62aSAndreas Boehler  /**
710*cb71a62aSAndreas Boehler   * Update the sync token log based on the calendar id and the
711*cb71a62aSAndreas Boehler   * operation that was performed.
712*cb71a62aSAndreas Boehler   *
713*cb71a62aSAndreas Boehler   * @param string $calid The calendar ID that was modified
714*cb71a62aSAndreas Boehler   * @param string $uri The calendar URI that was modified
715*cb71a62aSAndreas Boehler   * @param string $operation The operation that was performed
716*cb71a62aSAndreas Boehler   *
717*cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
718*cb71a62aSAndreas Boehler   */
71955a741c0SAndreas Boehler  private function updateSyncTokenLog($calid, $uri, $operation)
72055a741c0SAndreas Boehler  {
72155a741c0SAndreas Boehler      $currentToken = $this->getSyncTokenForCalendar($calid);
72255a741c0SAndreas Boehler      $operationCode = $this->operationNameToOperation($operation);
72355a741c0SAndreas Boehler      if(($operationCode === false) || ($currentToken === false))
72455a741c0SAndreas Boehler          return false;
72555a741c0SAndreas Boehler      $values = array($uri,
72655a741c0SAndreas Boehler                      $currentToken,
72755a741c0SAndreas Boehler                      $calid,
72855a741c0SAndreas Boehler                      $operationCode
72955a741c0SAndreas Boehler      );
73055a741c0SAndreas Boehler      $query = "INSERT INTO calendarchanges (uri, synctoken, calendarid, operation) VALUES(".
73155a741c0SAndreas Boehler               $this->sqlite->quote_and_join($values, ',').")";
73255a741c0SAndreas Boehler      $res = $this->sqlite->query($query);
73355a741c0SAndreas Boehler      if($res === false)
73455a741c0SAndreas Boehler        return false;
73555a741c0SAndreas Boehler      $currentToken++;
73655a741c0SAndreas Boehler      $query = "UPDATE calendars SET synctoken=".$this->sqlite->quote_string($currentToken)." WHERE id=".
73755a741c0SAndreas Boehler               $this->sqlite->quote_string($calid);
73855a741c0SAndreas Boehler      $res = $this->sqlite->query($query);
73955a741c0SAndreas Boehler      return ($res !== false);
74055a741c0SAndreas Boehler  }
74155a741c0SAndreas Boehler
742*cb71a62aSAndreas Boehler  /**
743*cb71a62aSAndreas Boehler   * Return the sync URL for a given Page, i.e. a calendar
744*cb71a62aSAndreas Boehler   *
745*cb71a62aSAndreas Boehler   * @param string $id The page's ID
746*cb71a62aSAndreas Boehler   * @param string $user (optional) The user's ID
747*cb71a62aSAndreas Boehler   *
748*cb71a62aSAndreas Boehler   * @return mixed The sync url or false
749*cb71a62aSAndreas Boehler   */
750b269830cSAndreas Boehler  public function getSyncUrlForPage($id, $user = null)
751b269830cSAndreas Boehler  {
752b269830cSAndreas Boehler      if(is_null($user))
753b269830cSAndreas Boehler        $user = $_SERVER['REMOTE_USER'];
754b269830cSAndreas Boehler
755b269830cSAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
756b269830cSAndreas Boehler      if($calid === false)
757b269830cSAndreas Boehler        return false;
758b269830cSAndreas Boehler
759b269830cSAndreas Boehler      $calsettings = $this->getCalendarSettings($calid);
760b269830cSAndreas Boehler      if(!isset($calsettings['uri']))
761b269830cSAndreas Boehler        return false;
762b269830cSAndreas Boehler
763b269830cSAndreas Boehler      $syncurl = DOKU_URL.'lib/plugins/davcal/calendarserver.php/calendars/'.$user.'/'.$calsettings['uri'];
764b269830cSAndreas Boehler      return $syncurl;
765b269830cSAndreas Boehler  }
766b269830cSAndreas Boehler
767*cb71a62aSAndreas Boehler  /**
768*cb71a62aSAndreas Boehler   * Return the private calendar's URL for a given page
769*cb71a62aSAndreas Boehler   *
770*cb71a62aSAndreas Boehler   * @param string $id the page ID
771*cb71a62aSAndreas Boehler   *
772*cb71a62aSAndreas Boehler   * @return mixed The private URL or false
773*cb71a62aSAndreas Boehler   */
774f69bb449SAndreas Boehler  public function getPrivateURLForPage($id)
775f69bb449SAndreas Boehler  {
776f69bb449SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
777f69bb449SAndreas Boehler      if($calid === false)
778f69bb449SAndreas Boehler        return false;
779f69bb449SAndreas Boehler
780f69bb449SAndreas Boehler      return $this->getPrivateURLForCalendar($calid);
781f69bb449SAndreas Boehler  }
782f69bb449SAndreas Boehler
783*cb71a62aSAndreas Boehler  /**
784*cb71a62aSAndreas Boehler   * Return the private calendar's URL for a given calendar ID
785*cb71a62aSAndreas Boehler   *
786*cb71a62aSAndreas Boehler   * @param string $calid The calendar's ID
787*cb71a62aSAndreas Boehler   *
788*cb71a62aSAndreas Boehler   * @return mixed The private URL or false
789*cb71a62aSAndreas Boehler   */
790f69bb449SAndreas Boehler  public function getPrivateURLForCalendar($calid)
791f69bb449SAndreas Boehler  {
792f69bb449SAndreas Boehler      $query = "SELECT url FROM calendartoprivateurlmapping WHERE calid=".$this->sqlite->quote_string($calid);
793f69bb449SAndreas Boehler      $res = $this->sqlite->query($query);
794f69bb449SAndreas Boehler      $row = $this->sqlite->res2row($res);
795f69bb449SAndreas Boehler      if(!isset($row['url']))
796f69bb449SAndreas Boehler      {
797f69bb449SAndreas Boehler          $url = uniqid("dokuwiki-").".ics";
798f69bb449SAndreas Boehler          $values = array(
799f69bb449SAndreas Boehler                $url,
800f69bb449SAndreas Boehler                $calid
801f69bb449SAndreas Boehler          );
802f69bb449SAndreas Boehler          $query = "INSERT INTO calendartoprivateurlmapping (url, calid) VALUES(".
803f69bb449SAndreas Boehler                $this->sqlite->quote_and_join($values, ", ").")";
804f69bb449SAndreas Boehler          $res = $this->sqlite->query($query);
805f69bb449SAndreas Boehler          if($res === false)
806f69bb449SAndreas Boehler            return false;
807f69bb449SAndreas Boehler      }
808f69bb449SAndreas Boehler      else
809f69bb449SAndreas Boehler      {
810f69bb449SAndreas Boehler          $url = $row['url'];
811f69bb449SAndreas Boehler      }
81270d9aa2aSAndreas Boehler      return DOKU_URL.'lib/plugins/davcal/ics.php/'.$url;
813f69bb449SAndreas Boehler  }
814f69bb449SAndreas Boehler
815*cb71a62aSAndreas Boehler  /**
816*cb71a62aSAndreas Boehler   * Retrieve the calendar ID for a given private calendar URL
817*cb71a62aSAndreas Boehler   *
818*cb71a62aSAndreas Boehler   * @param string $url The private URL
819*cb71a62aSAndreas Boehler   *
820*cb71a62aSAndreas Boehler   * @return mixed The calendar ID or false
821*cb71a62aSAndreas Boehler   */
822f69bb449SAndreas Boehler  public function getCalendarForPrivateURL($url)
823f69bb449SAndreas Boehler  {
824f69bb449SAndreas Boehler      $query = "SELECT calid FROM calendartoprivateurlmapping WHERE url=".$this->sqlite->quote_string($url);
825f69bb449SAndreas Boehler      $res = $this->sqlite->query($query);
826f69bb449SAndreas Boehler      $row = $this->sqlite->res2row($res);
827f69bb449SAndreas Boehler      if(!isset($row['calid']))
828f69bb449SAndreas Boehler        return false;
829f69bb449SAndreas Boehler      return $row['calid'];
830f69bb449SAndreas Boehler  }
831f69bb449SAndreas Boehler
832*cb71a62aSAndreas Boehler  /**
833*cb71a62aSAndreas Boehler   * Return a given calendar as ICS feed, i.e. all events in one ICS file.
834*cb71a62aSAndreas Boehler   *
835*cb71a62aSAndreas Boehler   * @param string $caldi The calendar ID to retrieve
836*cb71a62aSAndreas Boehler   *
837*cb71a62aSAndreas Boehler   * @return mixed The calendar events as string or false
838*cb71a62aSAndreas Boehler   */
839f69bb449SAndreas Boehler  public function getCalendarAsICSFeed($calid)
840f69bb449SAndreas Boehler  {
841f69bb449SAndreas Boehler      $calSettings = $this->getCalendarSettings($calid);
842f69bb449SAndreas Boehler      if($calSettings === false)
843f69bb449SAndreas Boehler        return false;
844f69bb449SAndreas Boehler      $events = $this->getAllCalendarEvents($calid);
845f69bb449SAndreas Boehler      if($events === false)
846f69bb449SAndreas Boehler        return false;
847f69bb449SAndreas Boehler
848f69bb449SAndreas Boehler      $out = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//DAVCal//DAVCal for DokuWiki//EN\nCALSCALE:GREGORIAN\nX-WR-CALNAME:";
849f69bb449SAndreas Boehler      $out .= $calSettings['displayname']."\n";
850f69bb449SAndreas Boehler      foreach($events as $event)
851f69bb449SAndreas Boehler      {
852f69bb449SAndreas Boehler          $out .= rtrim($event['calendardata']);
853f69bb449SAndreas Boehler          $out .= "\n";
854f69bb449SAndreas Boehler      }
855f69bb449SAndreas Boehler      $out .= "END:VCALENDAR\n";
856f69bb449SAndreas Boehler      return $out;
857f69bb449SAndreas Boehler  }
858f69bb449SAndreas Boehler
859a1a3b679SAndreas Boehler}
860