xref: /plugin/davcal/helper.php (revision 185e2535914616e98630b0777145a3e6d5c8d81b)
1a1a3b679SAndreas Boehler<?php
2a1a3b679SAndreas Boehler/**
3cb71a62aSAndreas 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;
14*185e2535SAndreas Boehler  protected $cachedValues = array();
15a1a3b679SAndreas Boehler
16a1a3b679SAndreas Boehler  /**
17cb71a62aSAndreas Boehler    * Constructor to load the configuration and the SQLite plugin
18a1a3b679SAndreas Boehler    */
19a1a3b679SAndreas Boehler  public function helper_plugin_davcal() {
20a1a3b679SAndreas Boehler    $this->sqlite =& plugin_load('helper', 'sqlite');
21a1a3b679SAndreas Boehler    if(!$this->sqlite)
22a1a3b679SAndreas Boehler    {
23a1a3b679SAndreas Boehler        msg('This plugin requires the sqlite plugin. Please install it.');
24a1a3b679SAndreas Boehler        return;
25a1a3b679SAndreas Boehler    }
26a1a3b679SAndreas Boehler
27a1a3b679SAndreas Boehler    if(!$this->sqlite->init('davcal', DOKU_PLUGIN.'davcal/db/'))
28a1a3b679SAndreas Boehler    {
29a1a3b679SAndreas Boehler        return;
30a1a3b679SAndreas Boehler    }
31a1a3b679SAndreas Boehler  }
32a1a3b679SAndreas Boehler
33cb71a62aSAndreas Boehler  /**
34*185e2535SAndreas Boehler   * Retrieve meta data for a given page
35*185e2535SAndreas Boehler   *
36*185e2535SAndreas Boehler   * @param string $id optional The page ID
37*185e2535SAndreas Boehler   * @return array The metadata
38*185e2535SAndreas Boehler   */
39*185e2535SAndreas Boehler  private function getMeta($id = null) {
40*185e2535SAndreas Boehler    global $ID;
41*185e2535SAndreas Boehler    global $INFO;
42*185e2535SAndreas Boehler
43*185e2535SAndreas Boehler    if ($id === null) $id = $ID;
44*185e2535SAndreas Boehler
45*185e2535SAndreas Boehler    if($ID === $id && $INFO['meta']) {
46*185e2535SAndreas Boehler        $meta = $INFO['meta'];
47*185e2535SAndreas Boehler    } else {
48*185e2535SAndreas Boehler        $meta = p_get_metadata($id);
49*185e2535SAndreas Boehler    }
50*185e2535SAndreas Boehler
51*185e2535SAndreas Boehler    return $meta;
52*185e2535SAndreas Boehler  }
53*185e2535SAndreas Boehler
54*185e2535SAndreas Boehler  /**
55*185e2535SAndreas Boehler   * Retrieve the meta data for a given page
56*185e2535SAndreas Boehler   *
57*185e2535SAndreas Boehler   * @param string $id optional The page ID
58*185e2535SAndreas Boehler   * @return array with meta data
59*185e2535SAndreas Boehler   */
60*185e2535SAndreas Boehler  public function getCalendarMetaForPage($id = null)
61*185e2535SAndreas Boehler  {
62*185e2535SAndreas Boehler      if(is_null($id))
63*185e2535SAndreas Boehler      {
64*185e2535SAndreas Boehler          global $ID;
65*185e2535SAndreas Boehler          $id = $ID;
66*185e2535SAndreas Boehler      }
67*185e2535SAndreas Boehler
68*185e2535SAndreas Boehler      $meta = $this->getMeta($id);
69*185e2535SAndreas Boehler      if(isset($meta['plugin_davcal']))
70*185e2535SAndreas Boehler        return $meta['plugin_davcal'];
71*185e2535SAndreas Boehler      else
72*185e2535SAndreas Boehler        return array();
73*185e2535SAndreas Boehler  }
74*185e2535SAndreas Boehler
75*185e2535SAndreas Boehler  /**
76*185e2535SAndreas Boehler   * Get all calendar pages used by a given page
77*185e2535SAndreas Boehler   * based on the stored metadata
78*185e2535SAndreas Boehler   *
79*185e2535SAndreas Boehler   * @param string $id optional The page id
80*185e2535SAndreas Boehler   * @return mixed The pages as array or false
81*185e2535SAndreas Boehler   */
82*185e2535SAndreas Boehler  public function getCalendarPagesByMeta($id = null)
83*185e2535SAndreas Boehler  {
84*185e2535SAndreas Boehler      if(is_null($id))
85*185e2535SAndreas Boehler      {
86*185e2535SAndreas Boehler          global $ID;
87*185e2535SAndreas Boehler          $id = $ID;
88*185e2535SAndreas Boehler      }
89*185e2535SAndreas Boehler
90*185e2535SAndreas Boehler      $meta = $this->getCalendarMetaForPage($id);
91*185e2535SAndreas Boehler      if(isset($meta['id']))
92*185e2535SAndreas Boehler      {
93*185e2535SAndreas Boehler          return array_keys($meta['id']);
94*185e2535SAndreas Boehler      }
95*185e2535SAndreas Boehler      return false;
96*185e2535SAndreas Boehler  }
97*185e2535SAndreas Boehler
98*185e2535SAndreas Boehler  /**
99*185e2535SAndreas Boehler   * Get a list of calendar names/pages/ids/colors
100*185e2535SAndreas Boehler   * for an array of page ids
101*185e2535SAndreas Boehler   *
102*185e2535SAndreas Boehler   * @param array $calendarPages The calendar pages to retrieve
103*185e2535SAndreas Boehler   * @return array The list
104*185e2535SAndreas Boehler   */
105*185e2535SAndreas Boehler  public function getCalendarMapForIDs($calendarPages)
106*185e2535SAndreas Boehler  {
107*185e2535SAndreas Boehler      $data = array();
108*185e2535SAndreas Boehler      foreach($calendarPages as $page)
109*185e2535SAndreas Boehler      {
110*185e2535SAndreas Boehler          $calid = $this->getCalendarIdForPage($page);
111*185e2535SAndreas Boehler          if($calid !== false)
112*185e2535SAndreas Boehler          {
113*185e2535SAndreas Boehler            $settings = $this->getCalendarSettings($calid);
114*185e2535SAndreas Boehler            $name = $settings['displayname'];
115*185e2535SAndreas Boehler            $color = $settings['calendarcolor'];
116*185e2535SAndreas Boehler            $data[] = array('name' => $name, 'page' => $page, 'calid' => $calid,
117*185e2535SAndreas Boehler                            'color' => $color);
118*185e2535SAndreas Boehler          }
119*185e2535SAndreas Boehler      }
120*185e2535SAndreas Boehler      return $data;
121*185e2535SAndreas Boehler  }
122*185e2535SAndreas Boehler
123*185e2535SAndreas Boehler  /**
124*185e2535SAndreas Boehler   * Get the saved calendar color for a given page.
125*185e2535SAndreas Boehler   *
126*185e2535SAndreas Boehler   * @param string $id optional The page ID
127*185e2535SAndreas Boehler   * @return mixed The color on success, otherwise false
128*185e2535SAndreas Boehler   */
129*185e2535SAndreas Boehler  public function getCalendarColorForPage($id = null)
130*185e2535SAndreas Boehler  {
131*185e2535SAndreas Boehler      if(is_null($id))
132*185e2535SAndreas Boehler      {
133*185e2535SAndreas Boehler          global $ID;
134*185e2535SAndreas Boehler          $id = $ID;
135*185e2535SAndreas Boehler      }
136*185e2535SAndreas Boehler
137*185e2535SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
138*185e2535SAndreas Boehler      if($calid === false)
139*185e2535SAndreas Boehler        return false;
140*185e2535SAndreas Boehler
141*185e2535SAndreas Boehler      return $this->getCalendarColorForCalendar($calid);
142*185e2535SAndreas Boehler  }
143*185e2535SAndreas Boehler
144*185e2535SAndreas Boehler  /**
145*185e2535SAndreas Boehler   * Get the saved calendar color for a given calendar ID.
146*185e2535SAndreas Boehler   *
147*185e2535SAndreas Boehler   * @param string $id optional The calendar ID
148*185e2535SAndreas Boehler   * @return mixed The color on success, otherwise false
149*185e2535SAndreas Boehler   */
150*185e2535SAndreas Boehler  public function getCalendarColorForCalendar($calid)
151*185e2535SAndreas Boehler  {
152*185e2535SAndreas Boehler      if(isset($this->cachedValues['calendarcolor'][$calid]))
153*185e2535SAndreas Boehler        return $this->cachedValues['calendarcolor'][$calid];
154*185e2535SAndreas Boehler
155*185e2535SAndreas Boehler      $row = $this->getCalendarSettings($calid);
156*185e2535SAndreas Boehler
157*185e2535SAndreas Boehler      if(!isset($row['calendarcolor']))
158*185e2535SAndreas Boehler        return false;
159*185e2535SAndreas Boehler
160*185e2535SAndreas Boehler      $color = $row['calendarcolor'];
161*185e2535SAndreas Boehler      $this->cachedValues['calendarcolor'][$calid] = $color;
162*185e2535SAndreas Boehler      return $color;
163*185e2535SAndreas Boehler  }
164*185e2535SAndreas Boehler
165*185e2535SAndreas Boehler  /**
166*185e2535SAndreas Boehler   * Set the calendar color for a given page.
167*185e2535SAndreas Boehler   *
168*185e2535SAndreas Boehler   * @param string $color The color definition
169*185e2535SAndreas Boehler   * @param string $id optional The page ID
170*185e2535SAndreas Boehler   * @return boolean True on success, otherwise false
171*185e2535SAndreas Boehler   */
172*185e2535SAndreas Boehler  public function setCalendarColorForPage($color, $id = null)
173*185e2535SAndreas Boehler  {
174*185e2535SAndreas Boehler      if(is_null($id))
175*185e2535SAndreas Boehler      {
176*185e2535SAndreas Boehler          global $ID;
177*185e2535SAndreas Boehler          $id = $ID;
178*185e2535SAndreas Boehler      }
179*185e2535SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
180*185e2535SAndreas Boehler      if($calid === false)
181*185e2535SAndreas Boehler        return false;
182*185e2535SAndreas Boehler
183*185e2535SAndreas Boehler      $query = "UPDATE calendars SET calendarcolor=".$this->sqlite->quote_string($color).
184*185e2535SAndreas Boehler               " WHERE id=".$this->sqlite->quote_string($calid);
185*185e2535SAndreas Boehler      $res = $this->sqlite->query($query);
186*185e2535SAndreas Boehler      if($res !== false)
187*185e2535SAndreas Boehler      {
188*185e2535SAndreas Boehler        $this->cachedValues['calendarcolor'][$calid] = $color;
189*185e2535SAndreas Boehler        return true;
190*185e2535SAndreas Boehler      }
191*185e2535SAndreas Boehler      return false;
192*185e2535SAndreas Boehler  }
193*185e2535SAndreas Boehler
194*185e2535SAndreas Boehler  /**
195cb71a62aSAndreas Boehler   * Set the calendar name and description for a given page with a given
196cb71a62aSAndreas Boehler   * page id.
197cb71a62aSAndreas Boehler   * If the calendar doesn't exist, the calendar is created!
198cb71a62aSAndreas Boehler   *
199cb71a62aSAndreas Boehler   * @param string  $name The name of the new calendar
200cb71a62aSAndreas Boehler   * @param string  $description The description of the new calendar
201cb71a62aSAndreas Boehler   * @param string  $id (optional) The ID of the page
202cb71a62aSAndreas Boehler   * @param string  $userid The userid of the creating user
203cb71a62aSAndreas Boehler   *
204cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false.
205cb71a62aSAndreas Boehler   */
206a1a3b679SAndreas Boehler  public function setCalendarNameForPage($name, $description, $id = null, $userid = null)
207a1a3b679SAndreas Boehler  {
208a1a3b679SAndreas Boehler      if(is_null($id))
209a1a3b679SAndreas Boehler      {
210a1a3b679SAndreas Boehler          global $ID;
211a1a3b679SAndreas Boehler          $id = $ID;
212a1a3b679SAndreas Boehler      }
213a1a3b679SAndreas Boehler      if(is_null($userid))
214a1a3b679SAndreas Boehler        $userid = $_SERVER['REMOTE_USER'];
215a1a3b679SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
216a1a3b679SAndreas Boehler      if($calid === false)
217a1a3b679SAndreas Boehler        return $this->createCalendarForPage($name, $description, $id, $userid);
218a1a3b679SAndreas Boehler
219b269830cSAndreas Boehler      $query = "UPDATE calendars SET displayname=".$this->sqlite->quote_string($name).", ".
220b269830cSAndreas Boehler               "description=".$this->sqlite->quote_string($description)." WHERE ".
221b269830cSAndreas Boehler               "id=".$this->sqlite->quote_string($calid);
222b269830cSAndreas Boehler      $res = $this->sqlite->query($query);
223b269830cSAndreas Boehler      if($res !== false)
224b269830cSAndreas Boehler        return true;
225b269830cSAndreas Boehler      return false;
226a1a3b679SAndreas Boehler  }
227a1a3b679SAndreas Boehler
228cb71a62aSAndreas Boehler  /**
229cb71a62aSAndreas Boehler   * Save the personal settings to the SQLite database 'calendarsettings'.
230cb71a62aSAndreas Boehler   *
231cb71a62aSAndreas Boehler   * @param array  $settings The settings array to store
232cb71a62aSAndreas Boehler   * @param string $userid (optional) The userid to store
233cb71a62aSAndreas Boehler   *
234cb71a62aSAndreas Boehler   * @param boolean True on success, otherwise false
235cb71a62aSAndreas Boehler   */
236a495d34cSAndreas Boehler  public function savePersonalSettings($settings, $userid = null)
237a495d34cSAndreas Boehler  {
238a495d34cSAndreas Boehler      if(is_null($userid))
239a495d34cSAndreas Boehler          $userid = $_SERVER['REMOTE_USER'];
240a495d34cSAndreas Boehler      $this->sqlite->query("BEGIN TRANSACTION");
241a495d34cSAndreas Boehler
242bd883736SAndreas Boehler      $query = "DELETE FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid);
243bd883736SAndreas Boehler      $this->sqlite->query($query);
244bd883736SAndreas Boehler
245a495d34cSAndreas Boehler      foreach($settings as $key => $value)
246a495d34cSAndreas Boehler      {
247bd883736SAndreas Boehler          $query = "INSERT INTO calendarsettings (userid, key, value) VALUES (".
248a495d34cSAndreas Boehler                   $this->sqlite->quote_string($userid).", ".
249a495d34cSAndreas Boehler                   $this->sqlite->quote_string($key).", ".
250a495d34cSAndreas Boehler                   $this->sqlite->quote_string($value).")";
251a495d34cSAndreas Boehler          $res = $this->sqlite->query($query);
252a495d34cSAndreas Boehler          if($res === false)
253a495d34cSAndreas Boehler              return false;
254a495d34cSAndreas Boehler      }
255a495d34cSAndreas Boehler      $this->sqlite->query("COMMIT TRANSACTION");
256*185e2535SAndreas Boehler      $this->cachedValues['settings'][$userid] = $settings;
257a495d34cSAndreas Boehler      return true;
258a495d34cSAndreas Boehler  }
259a495d34cSAndreas Boehler
260cb71a62aSAndreas Boehler  /**
261cb71a62aSAndreas Boehler   * Retrieve the settings array for a given user id.
262cb71a62aSAndreas Boehler   * Some sane defaults are returned, currently:
263cb71a62aSAndreas Boehler   *
264cb71a62aSAndreas Boehler   *    timezone    => local
265cb71a62aSAndreas Boehler   *    weeknumbers => 0
266cb71a62aSAndreas Boehler   *    workweek    => 0
267cb71a62aSAndreas Boehler   *
268cb71a62aSAndreas Boehler   * @param string $userid (optional) The user id to retrieve
269cb71a62aSAndreas Boehler   *
270cb71a62aSAndreas Boehler   * @return array The settings array
271cb71a62aSAndreas Boehler   */
272a495d34cSAndreas Boehler  public function getPersonalSettings($userid = null)
273a495d34cSAndreas Boehler  {
274a495d34cSAndreas Boehler      if(is_null($userid))
275a495d34cSAndreas Boehler        $userid = $_SERVER['REMOTE_USER'];
276*185e2535SAndreas Boehler
277*185e2535SAndreas Boehler      if(isset($this->cachedValues['settings'][$userid]))
278*185e2535SAndreas Boehler        return $this->cachedValues['settings'][$userid];
279bd883736SAndreas Boehler      // Some sane default settings
280bd883736SAndreas Boehler      $settings = array(
281bd883736SAndreas Boehler        'timezone' => 'local',
282bd883736SAndreas Boehler        'weeknumbers' => '0',
283*185e2535SAndreas Boehler        'workweek' => '0',
284*185e2535SAndreas Boehler        'monday' => '0'
285bd883736SAndreas Boehler      );
286a495d34cSAndreas Boehler      $query = "SELECT key, value FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid);
287a495d34cSAndreas Boehler      $res = $this->sqlite->query($query);
288a495d34cSAndreas Boehler      $arr = $this->sqlite->res2arr($res);
289a495d34cSAndreas Boehler      foreach($arr as $row)
290a495d34cSAndreas Boehler      {
291a495d34cSAndreas Boehler          $settings[$row['key']] = $row['value'];
292a495d34cSAndreas Boehler      }
293*185e2535SAndreas Boehler      $this->cachedValues['settings'][$userid] = $settings;
294a495d34cSAndreas Boehler      return $settings;
295a495d34cSAndreas Boehler  }
296a495d34cSAndreas Boehler
297cb71a62aSAndreas Boehler  /**
298cb71a62aSAndreas Boehler   * Retrieve the calendar ID based on a page ID from the SQLite table
299cb71a62aSAndreas Boehler   * 'pagetocalendarmapping'.
300cb71a62aSAndreas Boehler   *
301cb71a62aSAndreas Boehler   * @param string $id (optional) The page ID to retrieve the corresponding calendar
302cb71a62aSAndreas Boehler   *
303cb71a62aSAndreas Boehler   * @return mixed the ID on success, otherwise false
304cb71a62aSAndreas Boehler   */
305a1a3b679SAndreas Boehler  public function getCalendarIdForPage($id = null)
306a1a3b679SAndreas Boehler  {
307a1a3b679SAndreas Boehler      if(is_null($id))
308a1a3b679SAndreas Boehler      {
309a1a3b679SAndreas Boehler          global $ID;
310a1a3b679SAndreas Boehler          $id = $ID;
311a1a3b679SAndreas Boehler      }
312a1a3b679SAndreas Boehler
313*185e2535SAndreas Boehler      if(isset($this->cachedValues['calid'][$id]))
314*185e2535SAndreas Boehler        return $this->cachedValues['calid'][$id];
315*185e2535SAndreas Boehler
316a1a3b679SAndreas Boehler      $query = "SELECT calid FROM pagetocalendarmapping WHERE page=".$this->sqlite->quote_string($id);
317a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
318a1a3b679SAndreas Boehler      $row = $this->sqlite->res2row($res);
319a1a3b679SAndreas Boehler      if(isset($row['calid']))
320*185e2535SAndreas Boehler      {
321*185e2535SAndreas Boehler        $calid = $row['calid'];
322*185e2535SAndreas Boehler        $this->cachedValues['calid'] = $calid;
323*185e2535SAndreas Boehler        return $calid;
324*185e2535SAndreas Boehler      }
325a1a3b679SAndreas Boehler      return false;
326a1a3b679SAndreas Boehler  }
327a1a3b679SAndreas Boehler
328cb71a62aSAndreas Boehler  /**
329cb71a62aSAndreas Boehler   * Retrieve the complete calendar id to page mapping.
330cb71a62aSAndreas Boehler   * This is necessary to be able to retrieve a list of
331cb71a62aSAndreas Boehler   * calendars for a given user and check the access rights.
332cb71a62aSAndreas Boehler   *
333cb71a62aSAndreas Boehler   * @return array The mapping array
334cb71a62aSAndreas Boehler   */
335a1a3b679SAndreas Boehler  public function getCalendarIdToPageMapping()
336a1a3b679SAndreas Boehler  {
337a1a3b679SAndreas Boehler      $query = "SELECT calid, page FROM pagetocalendarmapping";
338a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
339a1a3b679SAndreas Boehler      $arr = $this->sqlite->res2arr($res);
340a1a3b679SAndreas Boehler      return $arr;
341a1a3b679SAndreas Boehler  }
342a1a3b679SAndreas Boehler
343cb71a62aSAndreas Boehler  /**
344cb71a62aSAndreas Boehler   * Retrieve all calendar IDs a given user has access to.
345cb71a62aSAndreas Boehler   * The user is specified by the principalUri, so the
346cb71a62aSAndreas Boehler   * user name is actually split from the URI component.
347cb71a62aSAndreas Boehler   *
348cb71a62aSAndreas Boehler   * Access rights are checked against DokuWiki's ACL
349cb71a62aSAndreas Boehler   * and applied accordingly.
350cb71a62aSAndreas Boehler   *
351cb71a62aSAndreas Boehler   * @param string $principalUri The principal URI to work on
352cb71a62aSAndreas Boehler   *
353cb71a62aSAndreas Boehler   * @return array An associative array of calendar IDs
354cb71a62aSAndreas Boehler   */
355a1a3b679SAndreas Boehler  public function getCalendarIdsForUser($principalUri)
356a1a3b679SAndreas Boehler  {
357a1a3b679SAndreas Boehler      $user = explode('/', $principalUri);
358a1a3b679SAndreas Boehler      $user = end($user);
359a1a3b679SAndreas Boehler      $mapping = $this->getCalendarIdToPageMapping();
360a1a3b679SAndreas Boehler      $calids = array();
361a1a3b679SAndreas Boehler      foreach($mapping as $row)
362a1a3b679SAndreas Boehler      {
363a1a3b679SAndreas Boehler          $id = $row['calid'];
364a1a3b679SAndreas Boehler          $page = $row['page'];
365a1a3b679SAndreas Boehler          $acl = auth_quickaclcheck($page);
366a1a3b679SAndreas Boehler          if($acl >= AUTH_READ)
367a1a3b679SAndreas Boehler          {
368a1a3b679SAndreas Boehler              $write = $acl > AUTH_READ;
369a1a3b679SAndreas Boehler              $calids[$id] = array('readonly' => !$write);
370a1a3b679SAndreas Boehler          }
371a1a3b679SAndreas Boehler      }
372a1a3b679SAndreas Boehler      return $calids;
373a1a3b679SAndreas Boehler  }
374a1a3b679SAndreas Boehler
375cb71a62aSAndreas Boehler  /**
376cb71a62aSAndreas Boehler   * Create a new calendar for a given page ID and set name and description
377cb71a62aSAndreas Boehler   * accordingly. Also update the pagetocalendarmapping table on success.
378cb71a62aSAndreas Boehler   *
379cb71a62aSAndreas Boehler   * @param string $name The calendar's name
380cb71a62aSAndreas Boehler   * @param string $description The calendar's description
381cb71a62aSAndreas Boehler   * @param string $id (optional) The page ID to work on
382cb71a62aSAndreas Boehler   * @param string $userid (optional) The user ID that created the calendar
383cb71a62aSAndreas Boehler   *
384cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
385cb71a62aSAndreas Boehler   */
386a1a3b679SAndreas Boehler  public function createCalendarForPage($name, $description, $id = null, $userid = null)
387a1a3b679SAndreas Boehler  {
388a1a3b679SAndreas Boehler      if(is_null($id))
389a1a3b679SAndreas Boehler      {
390a1a3b679SAndreas Boehler          global $ID;
391a1a3b679SAndreas Boehler          $id = $ID;
392a1a3b679SAndreas Boehler      }
393a1a3b679SAndreas Boehler      if(is_null($userid))
394a1a3b679SAndreas Boehler          $userid = $_SERVER['REMOTE_USER'];
395a1a3b679SAndreas Boehler      $values = array('principals/'.$userid,
396a1a3b679SAndreas Boehler                      $name,
397a1a3b679SAndreas Boehler                      str_replace(array('/', ' ', ':'), '_', $id),
398a1a3b679SAndreas Boehler                      $description,
399a1a3b679SAndreas Boehler                      'VEVENT,VTODO',
40055a741c0SAndreas Boehler                      0,
40155a741c0SAndreas Boehler                      1);
40255a741c0SAndreas Boehler      $query = "INSERT INTO calendars (principaluri, displayname, uri, description, components, transparent, synctoken) VALUES (".$this->sqlite->quote_and_join($values, ',').");";
403a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
40455a741c0SAndreas Boehler      if($res === false)
40555a741c0SAndreas Boehler        return false;
406cb71a62aSAndreas Boehler
407cb71a62aSAndreas Boehler      // Get the new calendar ID
408a1a3b679SAndreas Boehler      $query = "SELECT id FROM calendars WHERE principaluri=".$this->sqlite->quote_string($values[0])." AND ".
409a1a3b679SAndreas Boehler               "displayname=".$this->sqlite->quote_string($values[1])." AND ".
410a1a3b679SAndreas Boehler               "uri=".$this->sqlite->quote_string($values[2])." AND ".
411a1a3b679SAndreas Boehler               "description=".$this->sqlite->quote_string($values[3]);
412a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
413a1a3b679SAndreas Boehler      $row = $this->sqlite->res2row($res);
414cb71a62aSAndreas Boehler
415cb71a62aSAndreas Boehler      // Update the pagetocalendarmapping table with the new calendar ID
416a1a3b679SAndreas Boehler      if(isset($row['id']))
417a1a3b679SAndreas Boehler      {
418a1a3b679SAndreas Boehler          $values = array($id, $row['id']);
419a1a3b679SAndreas Boehler          $query = "INSERT INTO pagetocalendarmapping (page, calid) VALUES (".$this->sqlite->quote_and_join($values, ',').")";
420a1a3b679SAndreas Boehler          $res = $this->sqlite->query($query);
42155a741c0SAndreas Boehler          return ($res !== false);
422a1a3b679SAndreas Boehler      }
423a1a3b679SAndreas Boehler
424a1a3b679SAndreas Boehler      return false;
425a1a3b679SAndreas Boehler  }
426a1a3b679SAndreas Boehler
427cb71a62aSAndreas Boehler  /**
428cb71a62aSAndreas Boehler   * Add a new iCal entry for a given page, i.e. a given calendar.
429cb71a62aSAndreas Boehler   *
430cb71a62aSAndreas Boehler   * The parameter array needs to contain
431cb71a62aSAndreas Boehler   *   timezone         => The timezone of the entries
432cb71a62aSAndreas Boehler   *   detectedtz       => The timezone as detected by the browser
433cb71a62aSAndreas Boehler   *   eventfrom        => The event's start date
434cb71a62aSAndreas Boehler   *   eventfromtime    => The event's start time
435cb71a62aSAndreas Boehler   *   eventto          => The event's end date
436cb71a62aSAndreas Boehler   *   eventtotime      => The event's end time
437cb71a62aSAndreas Boehler   *   eventname        => The event's name
438cb71a62aSAndreas Boehler   *   eventdescription => The event's description
439cb71a62aSAndreas Boehler   *
440cb71a62aSAndreas Boehler   * @param string $id The page ID to work on
441cb71a62aSAndreas Boehler   * @param string $user The user who created the calendar
442cb71a62aSAndreas Boehler   * @param string $params A parameter array with values to create
443cb71a62aSAndreas Boehler   *
444cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
445cb71a62aSAndreas Boehler   */
446a1a3b679SAndreas Boehler  public function addCalendarEntryToCalendarForPage($id, $user, $params)
447a1a3b679SAndreas Boehler  {
448bd883736SAndreas Boehler      $settings = $this->getPersonalSettings($user);
449bd883736SAndreas Boehler      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
450bd883736SAndreas Boehler          $timezone = new \DateTimeZone($settings['timezone']);
451a25c89eaSAndreas Boehler      elseif($settings['timezone'] === 'local')
452a25c89eaSAndreas Boehler          $timezone = new \DateTimeZone($params['detectedtz']);
453bd883736SAndreas Boehler      else
454bd883736SAndreas Boehler          $timezone = new \DateTimeZone('UTC');
455cb71a62aSAndreas Boehler
456cb71a62aSAndreas Boehler      // Retrieve dates from settings
457b269830cSAndreas Boehler      $startDate = explode('-', $params['eventfrom']);
458b269830cSAndreas Boehler      $startTime = explode(':', $params['eventfromtime']);
459b269830cSAndreas Boehler      $endDate = explode('-', $params['eventto']);
460b269830cSAndreas Boehler      $endTime = explode(':', $params['eventtotime']);
461cb71a62aSAndreas Boehler
462cb71a62aSAndreas Boehler      // Load SabreDAV
463a1a3b679SAndreas Boehler      require_once('vendor/autoload.php');
464a1a3b679SAndreas Boehler      $vcalendar = new \Sabre\VObject\Component\VCalendar();
465cb71a62aSAndreas Boehler
466cb71a62aSAndreas Boehler      // Add VCalendar, UID and Event Name
467a1a3b679SAndreas Boehler      $event = $vcalendar->add('VEVENT');
468b269830cSAndreas Boehler      $uuid = \Sabre\VObject\UUIDUtil::getUUID();
469b269830cSAndreas Boehler      $event->add('UID', $uuid);
470a1a3b679SAndreas Boehler      $event->summary = $params['eventname'];
471cb71a62aSAndreas Boehler
472cb71a62aSAndreas Boehler      // Add a description if requested
4730eebc909SAndreas Boehler      $description = $params['eventdescription'];
4740eebc909SAndreas Boehler      if($description !== '')
4750eebc909SAndreas Boehler        $event->add('DESCRIPTION', $description);
476cb71a62aSAndreas Boehler
477cb71a62aSAndreas Boehler      // Create a timestamp for last modified, created and dtstamp values in UTC
478b269830cSAndreas Boehler      $dtStamp = new \DateTime(null, new \DateTimeZone('UTC'));
479b269830cSAndreas Boehler      $event->add('DTSTAMP', $dtStamp);
480b269830cSAndreas Boehler      $event->add('CREATED', $dtStamp);
481b269830cSAndreas Boehler      $event->add('LAST-MODIFIED', $dtStamp);
482cb71a62aSAndreas Boehler
483cb71a62aSAndreas Boehler      // Adjust the start date, based on the given timezone information
484b269830cSAndreas Boehler      $dtStart = new \DateTime();
485a25c89eaSAndreas Boehler      $dtStart->setTimezone($timezone);
486b269830cSAndreas Boehler      $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2]));
487cb71a62aSAndreas Boehler
488cb71a62aSAndreas Boehler      // Only add the time values if it's not an allday event
489b269830cSAndreas Boehler      if($params['allday'] != '1')
490b269830cSAndreas Boehler        $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0);
491cb71a62aSAndreas Boehler
492cb71a62aSAndreas Boehler      // Adjust the end date, based on the given timezone information
493b269830cSAndreas Boehler      $dtEnd = new \DateTime();
494a25c89eaSAndreas Boehler      $dtEnd->setTimezone($timezone);
495b269830cSAndreas Boehler      $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2]));
496cb71a62aSAndreas Boehler
497cb71a62aSAndreas Boehler      // Only add the time values if it's not an allday event
498b269830cSAndreas Boehler      if($params['allday'] != '1')
499b269830cSAndreas Boehler        $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0);
500cb71a62aSAndreas Boehler
501b269830cSAndreas Boehler      // According to the VCal spec, we need to add a whole day here
502b269830cSAndreas Boehler      if($params['allday'] == '1')
503b269830cSAndreas Boehler          $dtEnd->add(new \DateInterval('P1D'));
504cb71a62aSAndreas Boehler
505cb71a62aSAndreas Boehler      // Really add Start and End events
506b269830cSAndreas Boehler      $dtStartEv = $event->add('DTSTART', $dtStart);
507b269830cSAndreas Boehler      $dtEndEv = $event->add('DTEND', $dtEnd);
508cb71a62aSAndreas Boehler
509cb71a62aSAndreas Boehler      // Adjust the DATE format for allday events
510b269830cSAndreas Boehler      if($params['allday'] == '1')
511b269830cSAndreas Boehler      {
512b269830cSAndreas Boehler          $dtStartEv['VALUE'] = 'DATE';
513b269830cSAndreas Boehler          $dtEndEv['VALUE'] = 'DATE';
514b269830cSAndreas Boehler      }
515cb71a62aSAndreas Boehler
516cb71a62aSAndreas Boehler      // Actually add the values to the database
517a1a3b679SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
518a1a3b679SAndreas Boehler      $uri = uniqid('dokuwiki-').'.ics';
519a1a3b679SAndreas Boehler      $now = new DateTime();
520a1a3b679SAndreas Boehler      $eventStr = $vcalendar->serialize();
521a1a3b679SAndreas Boehler
522a1a3b679SAndreas Boehler      $values = array($calid,
523a1a3b679SAndreas Boehler                      $uri,
524a1a3b679SAndreas Boehler                      $eventStr,
525a1a3b679SAndreas Boehler                      $now->getTimestamp(),
526a1a3b679SAndreas Boehler                      'VEVENT',
527a1a3b679SAndreas Boehler                      $event->DTSTART->getDateTime()->getTimeStamp(),
528a1a3b679SAndreas Boehler                      $event->DTEND->getDateTime()->getTimeStamp(),
529a1a3b679SAndreas Boehler                      strlen($eventStr),
530a1a3b679SAndreas Boehler                      md5($eventStr),
531cb71a62aSAndreas Boehler                      $uuid
532a1a3b679SAndreas Boehler      );
533a1a3b679SAndreas Boehler
534a1a3b679SAndreas Boehler      $query = "INSERT INTO calendarobjects (calendarid, uri, calendardata, lastmodified, componenttype, firstoccurence, lastoccurence, size, etag, uid) VALUES (".$this->sqlite->quote_and_join($values, ',').")";
535a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
536cb71a62aSAndreas Boehler
537cb71a62aSAndreas Boehler      // If successfully, update the sync token database
53855a741c0SAndreas Boehler      if($res !== false)
53955a741c0SAndreas Boehler      {
54055a741c0SAndreas Boehler          $this->updateSyncTokenLog($calid, $uri, 'added');
541a1a3b679SAndreas Boehler          return true;
542a1a3b679SAndreas Boehler      }
54355a741c0SAndreas Boehler      return false;
54455a741c0SAndreas Boehler  }
545a1a3b679SAndreas Boehler
546cb71a62aSAndreas Boehler  /**
547cb71a62aSAndreas Boehler   * Retrieve the calendar settings of a given calendar id
548cb71a62aSAndreas Boehler   *
549cb71a62aSAndreas Boehler   * @param string $calid The calendar ID
550cb71a62aSAndreas Boehler   *
551cb71a62aSAndreas Boehler   * @return array The calendar settings array
552cb71a62aSAndreas Boehler   */
553b269830cSAndreas Boehler  public function getCalendarSettings($calid)
554b269830cSAndreas Boehler  {
555*185e2535SAndreas Boehler      $query = "SELECT principaluri, calendarcolor, displayname, uri, description, components, transparent, synctoken FROM calendars WHERE id=".$this->sqlite->quote_string($calid);
556b269830cSAndreas Boehler      $res = $this->sqlite->query($query);
557b269830cSAndreas Boehler      $row = $this->sqlite->res2row($res);
558b269830cSAndreas Boehler      return $row;
559b269830cSAndreas Boehler  }
560b269830cSAndreas Boehler
561cb71a62aSAndreas Boehler  /**
562cb71a62aSAndreas Boehler   * Retrieve all events that are within a given date range,
563cb71a62aSAndreas Boehler   * based on the timezone setting.
564cb71a62aSAndreas Boehler   *
565cb71a62aSAndreas Boehler   * There is also support for retrieving recurring events,
566cb71a62aSAndreas Boehler   * using Sabre's VObject Iterator. Recurring events are represented
567cb71a62aSAndreas Boehler   * as individual calendar entries with the same UID.
568cb71a62aSAndreas Boehler   *
569cb71a62aSAndreas Boehler   * @param string $id The page ID to work with
570cb71a62aSAndreas Boehler   * @param string $user The user ID to work with
571cb71a62aSAndreas Boehler   * @param string $startDate The start date as a string
572cb71a62aSAndreas Boehler   * @param string $endDate The end date as a string
573cb71a62aSAndreas Boehler   *
574cb71a62aSAndreas Boehler   * @return array An array containing the calendar entries.
575cb71a62aSAndreas Boehler   */
576a1a3b679SAndreas Boehler  public function getEventsWithinDateRange($id, $user, $startDate, $endDate)
577a1a3b679SAndreas Boehler  {
578bd883736SAndreas Boehler      $settings = $this->getPersonalSettings($user);
579bd883736SAndreas Boehler      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
580bd883736SAndreas Boehler          $timezone = new \DateTimeZone($settings['timezone']);
581bd883736SAndreas Boehler      else
582bd883736SAndreas Boehler          $timezone = new \DateTimeZone('UTC');
583a1a3b679SAndreas Boehler      $data = array();
584cb71a62aSAndreas Boehler
585cb71a62aSAndreas Boehler      // Load SabreDAV
586a1a3b679SAndreas Boehler      require_once('vendor/autoload.php');
587a1a3b679SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
588*185e2535SAndreas Boehler      $color = $this->getCalendarColorForCalendar($calid);
589a1a3b679SAndreas Boehler      $startTs = new \DateTime($startDate);
590a1a3b679SAndreas Boehler      $endTs = new \DateTime($endDate);
591cb71a62aSAndreas Boehler
592cb71a62aSAndreas Boehler      // Retrieve matching calendar objects
593ebc4eb57SAndreas Boehler      $query = "SELECT calendardata, componenttype, uid FROM calendarobjects WHERE calendarid=".
594ebc4eb57SAndreas Boehler                $this->sqlite->quote_string($calid)." AND firstoccurence < ".
595ebc4eb57SAndreas Boehler                $this->sqlite->quote_string($endTs->getTimestamp())." AND lastoccurence > ".
596ebc4eb57SAndreas Boehler                $this->sqlite->quote_string($startTs->getTimestamp());
597a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
598a1a3b679SAndreas Boehler      $arr = $this->sqlite->res2arr($res);
599cb71a62aSAndreas Boehler
600cb71a62aSAndreas Boehler      // Parse individual calendar entries
601a1a3b679SAndreas Boehler      foreach($arr as $row)
602a1a3b679SAndreas Boehler      {
603a1a3b679SAndreas Boehler          if(isset($row['calendardata']))
604a1a3b679SAndreas Boehler          {
605b269830cSAndreas Boehler              $entry = array();
606a1a3b679SAndreas Boehler              $vcal = \Sabre\VObject\Reader::read($row['calendardata']);
607ebc4eb57SAndreas Boehler              $recurrence = $vcal->VEVENT->RRULE;
608cb71a62aSAndreas Boehler              // If it is a recurring event, pass it through Sabre's EventIterator
609ebc4eb57SAndreas Boehler              if($recurrence != null)
610ebc4eb57SAndreas Boehler              {
611ebc4eb57SAndreas Boehler                  $rEvents = new \Sabre\VObject\Recur\EventIterator(array($vcal->VEVENT));
612ebc4eb57SAndreas Boehler                  $rEvents->rewind();
613ebc4eb57SAndreas Boehler                  $done = false;
614ebc4eb57SAndreas Boehler                  while($rEvents->valid() && !$done)
615ebc4eb57SAndreas Boehler                  {
616ebc4eb57SAndreas Boehler                      $event = $rEvents->getEventObject();
617cb71a62aSAndreas Boehler                      // If we are after the given time range, exit
618ebc4eb57SAndreas Boehler                      if(($rEvents->getDtStart()->getTimestamp() > $endTs->getTimestamp()) &&
619ebc4eb57SAndreas Boehler                         ($rEvents->getDtEnd()->getTimestamp() > $endTs->getTimestamp()))
620ebc4eb57SAndreas Boehler                        $done = true;
621cb71a62aSAndreas Boehler
622cb71a62aSAndreas Boehler                      // If we are before the given time range, continue
623ebc4eb57SAndreas Boehler                      if($rEvents->getDtEnd()->getTimestamp() < $startTs->getTimestamp())
624ebc4eb57SAndreas Boehler                      {
625ebc4eb57SAndreas Boehler                          $rEvents->next();
626ebc4eb57SAndreas Boehler                          continue;
627ebc4eb57SAndreas Boehler                      }
628cb71a62aSAndreas Boehler
629cb71a62aSAndreas Boehler                      // If we are within the given time range, parse the event
630*185e2535SAndreas Boehler                      $data[] = $this->convertIcalDataToEntry($event, $id, $timezone, $row['uid'], $color, true);
631ebc4eb57SAndreas Boehler                      $rEvents->next();
632ebc4eb57SAndreas Boehler                  }
633ebc4eb57SAndreas Boehler              }
634ebc4eb57SAndreas Boehler              else
635*185e2535SAndreas Boehler                $data[] = $this->convertIcalDataToEntry($vcal->VEVENT, $id, $timezone, $row['uid'], $color);
636ebc4eb57SAndreas Boehler          }
637ebc4eb57SAndreas Boehler      }
638ebc4eb57SAndreas Boehler      return $data;
639ebc4eb57SAndreas Boehler  }
640ebc4eb57SAndreas Boehler
641cb71a62aSAndreas Boehler  /**
642cb71a62aSAndreas Boehler   * Helper function that parses the iCal data of a VEVENT to a calendar entry.
643cb71a62aSAndreas Boehler   *
644cb71a62aSAndreas Boehler   * @param \Sabre\VObject\VEvent $event The event to parse
645cb71a62aSAndreas Boehler   * @param \DateTimeZone $timezone The timezone object
646cb71a62aSAndreas Boehler   * @param string $uid The entry's UID
6473c86dda8SAndreas Boehler   * @param boolean $recurring (optional) Set to true to define a recurring event
648cb71a62aSAndreas Boehler   *
649cb71a62aSAndreas Boehler   * @return array The parse calendar entry
650cb71a62aSAndreas Boehler   */
651*185e2535SAndreas Boehler  private function convertIcalDataToEntry($event, $page, $timezone, $uid, $color, $recurring = false)
652ebc4eb57SAndreas Boehler  {
653ebc4eb57SAndreas Boehler      $entry = array();
654ebc4eb57SAndreas Boehler      $start = $event->DTSTART;
655cb71a62aSAndreas Boehler      // Parse only if the start date/time is present
656b269830cSAndreas Boehler      if($start !== null)
657b269830cSAndreas Boehler      {
658b269830cSAndreas Boehler        $dtStart = $start->getDateTime();
659b269830cSAndreas Boehler        $dtStart->setTimezone($timezone);
660b269830cSAndreas Boehler        $entry['start'] = $dtStart->format(\DateTime::ATOM);
661b269830cSAndreas Boehler        if($start['VALUE'] == 'DATE')
662b269830cSAndreas Boehler          $entry['allDay'] = true;
663b269830cSAndreas Boehler        else
664b269830cSAndreas Boehler          $entry['allDay'] = false;
665b269830cSAndreas Boehler      }
666ebc4eb57SAndreas Boehler      $end = $event->DTEND;
667cb71a62aSAndreas Boehler      // Parse onlyl if the end date/time is present
668b269830cSAndreas Boehler      if($end !== null)
669b269830cSAndreas Boehler      {
670b269830cSAndreas Boehler        $dtEnd = $end->getDateTime();
671b269830cSAndreas Boehler        $dtEnd->setTimezone($timezone);
672b269830cSAndreas Boehler        $entry['end'] = $dtEnd->format(\DateTime::ATOM);
673b269830cSAndreas Boehler      }
674ebc4eb57SAndreas Boehler      $description = $event->DESCRIPTION;
6750eebc909SAndreas Boehler      if($description !== null)
6760eebc909SAndreas Boehler        $entry['description'] = (string)$description;
6770eebc909SAndreas Boehler      else
6780eebc909SAndreas Boehler        $entry['description'] = '';
679ebc4eb57SAndreas Boehler      $entry['title'] = (string)$event->summary;
680ebc4eb57SAndreas Boehler      $entry['id'] = $uid;
681*185e2535SAndreas Boehler      $entry['page'] = $page;
682*185e2535SAndreas Boehler      $entry['color'] = $color;
6833c86dda8SAndreas Boehler      $entry['recurring'] = $recurring;
684*185e2535SAndreas Boehler
685ebc4eb57SAndreas Boehler      return $entry;
686a1a3b679SAndreas Boehler  }
687a1a3b679SAndreas Boehler
688cb71a62aSAndreas Boehler  /**
689cb71a62aSAndreas Boehler   * Retrieve an event by its UID
690cb71a62aSAndreas Boehler   *
691cb71a62aSAndreas Boehler   * @param string $uid The event's UID
692cb71a62aSAndreas Boehler   *
693cb71a62aSAndreas Boehler   * @return mixed The table row with the given event
694cb71a62aSAndreas Boehler   */
695a1a3b679SAndreas Boehler  public function getEventWithUid($uid)
696a1a3b679SAndreas Boehler  {
69755a741c0SAndreas Boehler      $query = "SELECT calendardata, calendarid, componenttype, uri FROM calendarobjects WHERE uid=".
698a1a3b679SAndreas Boehler                $this->sqlite->quote_string($uid);
699a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
700a1a3b679SAndreas Boehler      $row = $this->sqlite->res2row($res);
701a1a3b679SAndreas Boehler      return $row;
702a1a3b679SAndreas Boehler  }
703a1a3b679SAndreas Boehler
704cb71a62aSAndreas Boehler  /**
705cb71a62aSAndreas Boehler   * Retrieve all calendar events for a given calendar ID
706cb71a62aSAndreas Boehler   *
707cb71a62aSAndreas Boehler   * @param string $calid The calendar's ID
708cb71a62aSAndreas Boehler   *
709cb71a62aSAndreas Boehler   * @return array An array containing all calendar data
710cb71a62aSAndreas Boehler   */
711f69bb449SAndreas Boehler  public function getAllCalendarEvents($calid)
712f69bb449SAndreas Boehler  {
713f69bb449SAndreas Boehler      $query = "SELECT calendardata, uid, componenttype, uri FROM calendarobjects WHERE calendarid=".
714f69bb449SAndreas Boehler               $this->sqlite->quote_string($calid);
715f69bb449SAndreas Boehler      $res = $this->sqlite->query($query);
716f69bb449SAndreas Boehler      $arr = $this->sqlite->res2arr($res);
717f69bb449SAndreas Boehler      return $arr;
718f69bb449SAndreas Boehler  }
719f69bb449SAndreas Boehler
720cb71a62aSAndreas Boehler  /**
721cb71a62aSAndreas Boehler   * Edit a calendar entry for a page, given by its parameters.
722cb71a62aSAndreas Boehler   * The params array has the same format as @see addCalendarEntryForPage
723cb71a62aSAndreas Boehler   *
724cb71a62aSAndreas Boehler   * @param string $id The page's ID to work on
725cb71a62aSAndreas Boehler   * @param string $user The user's ID to work on
726cb71a62aSAndreas Boehler   * @param array $params The parameter array for the edited calendar event
727cb71a62aSAndreas Boehler   *
728cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
729cb71a62aSAndreas Boehler   */
730a1a3b679SAndreas Boehler  public function editCalendarEntryForPage($id, $user, $params)
731a1a3b679SAndreas Boehler  {
732bd883736SAndreas Boehler      $settings = $this->getPersonalSettings($user);
733bd883736SAndreas Boehler      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
734bd883736SAndreas Boehler          $timezone = new \DateTimeZone($settings['timezone']);
735a25c89eaSAndreas Boehler      elseif($settings['timezone'] === 'local')
736a25c89eaSAndreas Boehler          $timezone = new \DateTimeZone($params['detectedtz']);
737bd883736SAndreas Boehler      else
738bd883736SAndreas Boehler          $timezone = new \DateTimeZone('UTC');
739cb71a62aSAndreas Boehler
740cb71a62aSAndreas Boehler      // Parse dates
741b269830cSAndreas Boehler      $startDate = explode('-', $params['eventfrom']);
742b269830cSAndreas Boehler      $startTime = explode(':', $params['eventfromtime']);
743b269830cSAndreas Boehler      $endDate = explode('-', $params['eventto']);
744b269830cSAndreas Boehler      $endTime = explode(':', $params['eventtotime']);
745cb71a62aSAndreas Boehler
746cb71a62aSAndreas Boehler      // Retrieve the existing event based on the UID
74755a741c0SAndreas Boehler      $uid = $params['uid'];
74855a741c0SAndreas Boehler      $event = $this->getEventWithUid($uid);
749cb71a62aSAndreas Boehler
750cb71a62aSAndreas Boehler      // Load SabreDAV
751a1a3b679SAndreas Boehler      require_once('vendor/autoload.php');
752a1a3b679SAndreas Boehler      if(!isset($event['calendardata']))
753a1a3b679SAndreas Boehler        return false;
75455a741c0SAndreas Boehler      $uri = $event['uri'];
75555a741c0SAndreas Boehler      $calid = $event['calendarid'];
756cb71a62aSAndreas Boehler
757cb71a62aSAndreas Boehler      // Parse the existing event
758a1a3b679SAndreas Boehler      $vcal = \Sabre\VObject\Reader::read($event['calendardata']);
759b269830cSAndreas Boehler      $vevent = $vcal->VEVENT;
760cb71a62aSAndreas Boehler
761cb71a62aSAndreas Boehler      // Set the new event values
762b269830cSAndreas Boehler      $vevent->summary = $params['eventname'];
763b269830cSAndreas Boehler      $dtStamp = new \DateTime(null, new \DateTimeZone('UTC'));
7640eebc909SAndreas Boehler      $description = $params['eventdescription'];
765cb71a62aSAndreas Boehler
766cb71a62aSAndreas Boehler      // Remove existing timestamps to overwrite them
7670eebc909SAndreas Boehler      $vevent->remove('DESCRIPTION');
768b269830cSAndreas Boehler      $vevent->remove('DTSTAMP');
769b269830cSAndreas Boehler      $vevent->remove('LAST-MODIFIED');
770cb71a62aSAndreas Boehler
771cb71a62aSAndreas Boehler      // Add new time stamps and description
772b269830cSAndreas Boehler      $vevent->add('DTSTAMP', $dtStamp);
773b269830cSAndreas Boehler      $vevent->add('LAST-MODIFIED', $dtStamp);
7740eebc909SAndreas Boehler      if($description !== '')
7750eebc909SAndreas Boehler        $vevent->add('DESCRIPTION', $description);
776cb71a62aSAndreas Boehler
777cb71a62aSAndreas Boehler      // Setup DTSTART
778b269830cSAndreas Boehler      $dtStart = new \DateTime();
779a25c89eaSAndreas Boehler      $dtStart->setTimezone($timezone);
780b269830cSAndreas Boehler      $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2]));
781b269830cSAndreas Boehler      if($params['allday'] != '1')
782b269830cSAndreas Boehler        $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0);
783cb71a62aSAndreas Boehler
784cb71a62aSAndreas Boehler      // Setup DETEND
785b269830cSAndreas Boehler      $dtEnd = new \DateTime();
786a25c89eaSAndreas Boehler      $dtEnd->setTimezone($timezone);
787b269830cSAndreas Boehler      $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2]));
788b269830cSAndreas Boehler      if($params['allday'] != '1')
789b269830cSAndreas Boehler        $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0);
790cb71a62aSAndreas Boehler
791b269830cSAndreas Boehler      // According to the VCal spec, we need to add a whole day here
792b269830cSAndreas Boehler      if($params['allday'] == '1')
793b269830cSAndreas Boehler          $dtEnd->add(new \DateInterval('P1D'));
794b269830cSAndreas Boehler      $vevent->remove('DTSTART');
795b269830cSAndreas Boehler      $vevent->remove('DTEND');
796b269830cSAndreas Boehler      $dtStartEv = $vevent->add('DTSTART', $dtStart);
797b269830cSAndreas Boehler      $dtEndEv = $vevent->add('DTEND', $dtEnd);
798cb71a62aSAndreas Boehler
799cb71a62aSAndreas Boehler      // Remove the time for allday events
800b269830cSAndreas Boehler      if($params['allday'] == '1')
801b269830cSAndreas Boehler      {
802b269830cSAndreas Boehler          $dtStartEv['VALUE'] = 'DATE';
803b269830cSAndreas Boehler          $dtEndEv['VALUE'] = 'DATE';
804b269830cSAndreas Boehler      }
805a1a3b679SAndreas Boehler      $now = new DateTime();
806a1a3b679SAndreas Boehler      $eventStr = $vcal->serialize();
807a1a3b679SAndreas Boehler
808cb71a62aSAndreas Boehler      // Actually write to the database
809a1a3b679SAndreas Boehler      $query = "UPDATE calendarobjects SET calendardata=".$this->sqlite->quote_string($eventStr).
810a1a3b679SAndreas Boehler               ", lastmodified=".$this->sqlite->quote_string($now->getTimestamp()).
811a1a3b679SAndreas Boehler               ", firstoccurence=".$this->sqlite->quote_string($dtStart->getTimestamp()).
812a1a3b679SAndreas Boehler               ", lastoccurence=".$this->sqlite->quote_string($dtEnd->getTimestamp()).
813a1a3b679SAndreas Boehler               ", size=".strlen($eventStr).
814a1a3b679SAndreas Boehler               ", etag=".$this->sqlite->quote_string(md5($eventStr)).
81555a741c0SAndreas Boehler               " WHERE uid=".$this->sqlite->quote_string($uid);
816a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
81755a741c0SAndreas Boehler      if($res !== false)
81855a741c0SAndreas Boehler      {
81955a741c0SAndreas Boehler          $this->updateSyncTokenLog($calid, $uri, 'modified');
820a1a3b679SAndreas Boehler          return true;
821a1a3b679SAndreas Boehler      }
82255a741c0SAndreas Boehler      return false;
82355a741c0SAndreas Boehler  }
824a1a3b679SAndreas Boehler
825cb71a62aSAndreas Boehler  /**
826cb71a62aSAndreas Boehler   * Delete a calendar entry for a given page. Actually, the event is removed
827cb71a62aSAndreas Boehler   * based on the entry's UID, so that page ID is no used.
828cb71a62aSAndreas Boehler   *
829cb71a62aSAndreas Boehler   * @param string $id The page's ID (unused)
830cb71a62aSAndreas Boehler   * @param array $params The parameter array to work with
831cb71a62aSAndreas Boehler   *
832cb71a62aSAndreas Boehler   * @return boolean True
833cb71a62aSAndreas Boehler   */
834a1a3b679SAndreas Boehler  public function deleteCalendarEntryForPage($id, $params)
835a1a3b679SAndreas Boehler  {
836a1a3b679SAndreas Boehler      $uid = $params['uid'];
83755a741c0SAndreas Boehler      $event = $this->getEventWithUid($uid);
8382c14b82bSAndreas Boehler      $calid = $event['calendarid'];
83955a741c0SAndreas Boehler      $uri = $event['uri'];
840a1a3b679SAndreas Boehler      $query = "DELETE FROM calendarobjects WHERE uid=".$this->sqlite->quote_string($uid);
841a1a3b679SAndreas Boehler      $res = $this->sqlite->query($query);
84255a741c0SAndreas Boehler      if($res !== false)
84355a741c0SAndreas Boehler      {
84455a741c0SAndreas Boehler          $this->updateSyncTokenLog($calid, $uri, 'deleted');
84555a741c0SAndreas Boehler      }
846a1a3b679SAndreas Boehler      return true;
847a1a3b679SAndreas Boehler  }
848a1a3b679SAndreas Boehler
849cb71a62aSAndreas Boehler  /**
850cb71a62aSAndreas Boehler   * Retrieve the current sync token for a calendar
851cb71a62aSAndreas Boehler   *
852cb71a62aSAndreas Boehler   * @param string $calid The calendar id
853cb71a62aSAndreas Boehler   *
854cb71a62aSAndreas Boehler   * @return mixed The synctoken or false
855cb71a62aSAndreas Boehler   */
85655a741c0SAndreas Boehler  public function getSyncTokenForCalendar($calid)
85755a741c0SAndreas Boehler  {
858b269830cSAndreas Boehler      $row = $this->getCalendarSettings($calid);
85955a741c0SAndreas Boehler      if(isset($row['synctoken']))
86055a741c0SAndreas Boehler          return $row['synctoken'];
86155a741c0SAndreas Boehler      return false;
86255a741c0SAndreas Boehler  }
86355a741c0SAndreas Boehler
864cb71a62aSAndreas Boehler  /**
865cb71a62aSAndreas Boehler   * Helper function to convert the operation name to
866cb71a62aSAndreas Boehler   * an operation code as stored in the database
867cb71a62aSAndreas Boehler   *
868cb71a62aSAndreas Boehler   * @param string $operationName The operation name
869cb71a62aSAndreas Boehler   *
870cb71a62aSAndreas Boehler   * @return mixed The operation code or false
871cb71a62aSAndreas Boehler   */
87255a741c0SAndreas Boehler  public function operationNameToOperation($operationName)
87355a741c0SAndreas Boehler  {
87455a741c0SAndreas Boehler      switch($operationName)
87555a741c0SAndreas Boehler      {
87655a741c0SAndreas Boehler          case 'added':
87755a741c0SAndreas Boehler              return 1;
87855a741c0SAndreas Boehler          break;
87955a741c0SAndreas Boehler          case 'modified':
88055a741c0SAndreas Boehler              return 2;
88155a741c0SAndreas Boehler          break;
88255a741c0SAndreas Boehler          case 'deleted':
88355a741c0SAndreas Boehler              return 3;
88455a741c0SAndreas Boehler          break;
88555a741c0SAndreas Boehler      }
88655a741c0SAndreas Boehler      return false;
88755a741c0SAndreas Boehler  }
88855a741c0SAndreas Boehler
889cb71a62aSAndreas Boehler  /**
890cb71a62aSAndreas Boehler   * Update the sync token log based on the calendar id and the
891cb71a62aSAndreas Boehler   * operation that was performed.
892cb71a62aSAndreas Boehler   *
893cb71a62aSAndreas Boehler   * @param string $calid The calendar ID that was modified
894cb71a62aSAndreas Boehler   * @param string $uri The calendar URI that was modified
895cb71a62aSAndreas Boehler   * @param string $operation The operation that was performed
896cb71a62aSAndreas Boehler   *
897cb71a62aSAndreas Boehler   * @return boolean True on success, otherwise false
898cb71a62aSAndreas Boehler   */
89955a741c0SAndreas Boehler  private function updateSyncTokenLog($calid, $uri, $operation)
90055a741c0SAndreas Boehler  {
90155a741c0SAndreas Boehler      $currentToken = $this->getSyncTokenForCalendar($calid);
90255a741c0SAndreas Boehler      $operationCode = $this->operationNameToOperation($operation);
90355a741c0SAndreas Boehler      if(($operationCode === false) || ($currentToken === false))
90455a741c0SAndreas Boehler          return false;
90555a741c0SAndreas Boehler      $values = array($uri,
90655a741c0SAndreas Boehler                      $currentToken,
90755a741c0SAndreas Boehler                      $calid,
90855a741c0SAndreas Boehler                      $operationCode
90955a741c0SAndreas Boehler      );
91055a741c0SAndreas Boehler      $query = "INSERT INTO calendarchanges (uri, synctoken, calendarid, operation) VALUES(".
91155a741c0SAndreas Boehler               $this->sqlite->quote_and_join($values, ',').")";
91255a741c0SAndreas Boehler      $res = $this->sqlite->query($query);
91355a741c0SAndreas Boehler      if($res === false)
91455a741c0SAndreas Boehler        return false;
91555a741c0SAndreas Boehler      $currentToken++;
91655a741c0SAndreas Boehler      $query = "UPDATE calendars SET synctoken=".$this->sqlite->quote_string($currentToken)." WHERE id=".
91755a741c0SAndreas Boehler               $this->sqlite->quote_string($calid);
91855a741c0SAndreas Boehler      $res = $this->sqlite->query($query);
91955a741c0SAndreas Boehler      return ($res !== false);
92055a741c0SAndreas Boehler  }
92155a741c0SAndreas Boehler
922cb71a62aSAndreas Boehler  /**
923cb71a62aSAndreas Boehler   * Return the sync URL for a given Page, i.e. a calendar
924cb71a62aSAndreas Boehler   *
925cb71a62aSAndreas Boehler   * @param string $id The page's ID
926cb71a62aSAndreas Boehler   * @param string $user (optional) The user's ID
927cb71a62aSAndreas Boehler   *
928cb71a62aSAndreas Boehler   * @return mixed The sync url or false
929cb71a62aSAndreas Boehler   */
930b269830cSAndreas Boehler  public function getSyncUrlForPage($id, $user = null)
931b269830cSAndreas Boehler  {
932b269830cSAndreas Boehler      if(is_null($user))
933b269830cSAndreas Boehler        $user = $_SERVER['REMOTE_USER'];
934b269830cSAndreas Boehler
935b269830cSAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
936b269830cSAndreas Boehler      if($calid === false)
937b269830cSAndreas Boehler        return false;
938b269830cSAndreas Boehler
939b269830cSAndreas Boehler      $calsettings = $this->getCalendarSettings($calid);
940b269830cSAndreas Boehler      if(!isset($calsettings['uri']))
941b269830cSAndreas Boehler        return false;
942b269830cSAndreas Boehler
943b269830cSAndreas Boehler      $syncurl = DOKU_URL.'lib/plugins/davcal/calendarserver.php/calendars/'.$user.'/'.$calsettings['uri'];
944b269830cSAndreas Boehler      return $syncurl;
945b269830cSAndreas Boehler  }
946b269830cSAndreas Boehler
947cb71a62aSAndreas Boehler  /**
948cb71a62aSAndreas Boehler   * Return the private calendar's URL for a given page
949cb71a62aSAndreas Boehler   *
950cb71a62aSAndreas Boehler   * @param string $id the page ID
951cb71a62aSAndreas Boehler   *
952cb71a62aSAndreas Boehler   * @return mixed The private URL or false
953cb71a62aSAndreas Boehler   */
954f69bb449SAndreas Boehler  public function getPrivateURLForPage($id)
955f69bb449SAndreas Boehler  {
956f69bb449SAndreas Boehler      $calid = $this->getCalendarIdForPage($id);
957f69bb449SAndreas Boehler      if($calid === false)
958f69bb449SAndreas Boehler        return false;
959f69bb449SAndreas Boehler
960f69bb449SAndreas Boehler      return $this->getPrivateURLForCalendar($calid);
961f69bb449SAndreas Boehler  }
962f69bb449SAndreas Boehler
963cb71a62aSAndreas Boehler  /**
964cb71a62aSAndreas Boehler   * Return the private calendar's URL for a given calendar ID
965cb71a62aSAndreas Boehler   *
966cb71a62aSAndreas Boehler   * @param string $calid The calendar's ID
967cb71a62aSAndreas Boehler   *
968cb71a62aSAndreas Boehler   * @return mixed The private URL or false
969cb71a62aSAndreas Boehler   */
970f69bb449SAndreas Boehler  public function getPrivateURLForCalendar($calid)
971f69bb449SAndreas Boehler  {
972*185e2535SAndreas Boehler      if(isset($this->cachedValues['privateurl'][$calid]))
973*185e2535SAndreas Boehler        return $this->cachedValues['privateurl'][$calid];
974f69bb449SAndreas Boehler      $query = "SELECT url FROM calendartoprivateurlmapping WHERE calid=".$this->sqlite->quote_string($calid);
975f69bb449SAndreas Boehler      $res = $this->sqlite->query($query);
976f69bb449SAndreas Boehler      $row = $this->sqlite->res2row($res);
977f69bb449SAndreas Boehler      if(!isset($row['url']))
978f69bb449SAndreas Boehler      {
979f69bb449SAndreas Boehler          $url = uniqid("dokuwiki-").".ics";
980f69bb449SAndreas Boehler          $values = array(
981f69bb449SAndreas Boehler                $url,
982f69bb449SAndreas Boehler                $calid
983f69bb449SAndreas Boehler          );
984f69bb449SAndreas Boehler          $query = "INSERT INTO calendartoprivateurlmapping (url, calid) VALUES(".
985f69bb449SAndreas Boehler                $this->sqlite->quote_and_join($values, ", ").")";
986f69bb449SAndreas Boehler          $res = $this->sqlite->query($query);
987f69bb449SAndreas Boehler          if($res === false)
988f69bb449SAndreas Boehler            return false;
989f69bb449SAndreas Boehler      }
990f69bb449SAndreas Boehler      else
991f69bb449SAndreas Boehler      {
992f69bb449SAndreas Boehler          $url = $row['url'];
993f69bb449SAndreas Boehler      }
994*185e2535SAndreas Boehler
995*185e2535SAndreas Boehler      $url = DOKU_URL.'lib/plugins/davcal/ics.php/'.$url;
996*185e2535SAndreas Boehler      $this->cachedValues['privateurl'][$calid] = $url;
997*185e2535SAndreas Boehler      return $url;
998f69bb449SAndreas Boehler  }
999f69bb449SAndreas Boehler
1000cb71a62aSAndreas Boehler  /**
1001cb71a62aSAndreas Boehler   * Retrieve the calendar ID for a given private calendar URL
1002cb71a62aSAndreas Boehler   *
1003cb71a62aSAndreas Boehler   * @param string $url The private URL
1004cb71a62aSAndreas Boehler   *
1005cb71a62aSAndreas Boehler   * @return mixed The calendar ID or false
1006cb71a62aSAndreas Boehler   */
1007f69bb449SAndreas Boehler  public function getCalendarForPrivateURL($url)
1008f69bb449SAndreas Boehler  {
1009f69bb449SAndreas Boehler      $query = "SELECT calid FROM calendartoprivateurlmapping WHERE url=".$this->sqlite->quote_string($url);
1010f69bb449SAndreas Boehler      $res = $this->sqlite->query($query);
1011f69bb449SAndreas Boehler      $row = $this->sqlite->res2row($res);
1012f69bb449SAndreas Boehler      if(!isset($row['calid']))
1013f69bb449SAndreas Boehler        return false;
1014f69bb449SAndreas Boehler      return $row['calid'];
1015f69bb449SAndreas Boehler  }
1016f69bb449SAndreas Boehler
1017cb71a62aSAndreas Boehler  /**
1018cb71a62aSAndreas Boehler   * Return a given calendar as ICS feed, i.e. all events in one ICS file.
1019cb71a62aSAndreas Boehler   *
1020cb71a62aSAndreas Boehler   * @param string $caldi The calendar ID to retrieve
1021cb71a62aSAndreas Boehler   *
1022cb71a62aSAndreas Boehler   * @return mixed The calendar events as string or false
1023cb71a62aSAndreas Boehler   */
1024f69bb449SAndreas Boehler  public function getCalendarAsICSFeed($calid)
1025f69bb449SAndreas Boehler  {
1026f69bb449SAndreas Boehler      $calSettings = $this->getCalendarSettings($calid);
1027f69bb449SAndreas Boehler      if($calSettings === false)
1028f69bb449SAndreas Boehler        return false;
1029f69bb449SAndreas Boehler      $events = $this->getAllCalendarEvents($calid);
1030f69bb449SAndreas Boehler      if($events === false)
1031f69bb449SAndreas Boehler        return false;
1032f69bb449SAndreas Boehler
1033f69bb449SAndreas Boehler      $out = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//DAVCal//DAVCal for DokuWiki//EN\nCALSCALE:GREGORIAN\nX-WR-CALNAME:";
1034f69bb449SAndreas Boehler      $out .= $calSettings['displayname']."\n";
1035f69bb449SAndreas Boehler      foreach($events as $event)
1036f69bb449SAndreas Boehler      {
1037f69bb449SAndreas Boehler          $out .= rtrim($event['calendardata']);
1038f69bb449SAndreas Boehler          $out .= "\n";
1039f69bb449SAndreas Boehler      }
1040f69bb449SAndreas Boehler      $out .= "END:VCALENDAR\n";
1041f69bb449SAndreas Boehler      return $out;
1042f69bb449SAndreas Boehler  }
1043f69bb449SAndreas Boehler
1044a1a3b679SAndreas Boehler}
1045