xref: /plugin/davcal/helper.php (revision bd8837360bd1c2381d1f461eb52a81a542d2b933)
1<?php
2/**
3  * Helper Class for the tagrevisions plugin
4  * This helper does the actual work.
5  *
6  * Configurable in DokuWiki's configuration
7  */
8
9// must be run within Dokuwiki
10if(!defined('DOKU_INC')) die();
11
12class helper_plugin_davcal extends DokuWiki_Plugin {
13
14  protected $sqlite = null;
15
16  /**
17    * Constructor to load the configuration
18    */
19  public function helper_plugin_davcal() {
20    $this->sqlite =& plugin_load('helper', 'sqlite');
21    if(!$this->sqlite)
22    {
23        msg('This plugin requires the sqlite plugin. Please install it.');
24        return;
25    }
26
27    if(!$this->sqlite->init('davcal', DOKU_PLUGIN.'davcal/db/'))
28    {
29        return;
30    }
31  }
32
33  public function setCalendarNameForPage($name, $description, $id = null, $userid = null)
34  {
35      if(is_null($id))
36      {
37          global $ID;
38          $id = $ID;
39      }
40      if(is_null($userid))
41        $userid = $_SERVER['REMOTE_USER'];
42      $calid = $this->getCalendarIdForPage($id);
43      if($calid === false)
44        return $this->createCalendarForPage($name, $description, $id, $userid);
45
46      // Update the calendar name here
47
48  }
49
50  public function savePersonalSettings($settings, $userid = null)
51  {
52      if(is_null($userid))
53          $userid = $_SERVER['REMOTE_USER'];
54      $this->sqlite->query("BEGIN TRANSACTION");
55
56      $query = "DELETE FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid);
57      $this->sqlite->query($query);
58
59      foreach($settings as $key => $value)
60      {
61          $query = "INSERT INTO calendarsettings (userid, key, value) VALUES (".
62                   $this->sqlite->quote_string($userid).", ".
63                   $this->sqlite->quote_string($key).", ".
64                   $this->sqlite->quote_string($value).")";
65          $res = $this->sqlite->query($query);
66          if($res === false)
67              return false;
68      }
69      $this->sqlite->query("COMMIT TRANSACTION");
70      return true;
71  }
72
73  public function getPersonalSettings($userid = null)
74  {
75      if(is_null($userid))
76        $userid = $_SERVER['REMOTE_USER'];
77      // Some sane default settings
78      $settings = array(
79        'timezone' => 'local',
80        'weeknumbers' => '0',
81        'workweek' => '0'
82      );
83      $query = "SELECT key, value FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid);
84      $res = $this->sqlite->query($query);
85      $arr = $this->sqlite->res2arr($res);
86      foreach($arr as $row)
87      {
88          $settings[$row['key']] = $row['value'];
89      }
90      return $settings;
91  }
92
93  public function getCalendarIdForPage($id = null)
94  {
95      if(is_null($id))
96      {
97          global $ID;
98          $id = $ID;
99      }
100
101      $query = "SELECT calid FROM pagetocalendarmapping WHERE page=".$this->sqlite->quote_string($id);
102      $res = $this->sqlite->query($query);
103      $row = $this->sqlite->res2row($res);
104      if(isset($row['calid']))
105        return $row['calid'];
106      else
107        return false;
108  }
109
110  public function getCalendarIdToPageMapping()
111  {
112      $query = "SELECT calid, page FROM pagetocalendarmapping";
113      $res = $this->sqlite->query($query);
114      $arr = $this->sqlite->res2arr($res);
115      return $arr;
116  }
117
118  public function getCalendarIdsForUser($principalUri)
119  {
120      $user = explode('/', $principalUri);
121      $user = end($user);
122      $mapping = $this->getCalendarIdToPageMapping();
123      $calids = array();
124      foreach($mapping as $row)
125      {
126          $id = $row['calid'];
127          $page = $row['page'];
128          $acl = auth_quickaclcheck($page);
129          if($acl >= AUTH_READ)
130          {
131              $write = $acl > AUTH_READ;
132              $calids[$id] = array('readonly' => !$write);
133          }
134      }
135      return $calids;
136  }
137
138  public function createCalendarForPage($name, $description, $id = null, $userid = null)
139  {
140      if(is_null($id))
141      {
142          global $ID;
143          $id = $ID;
144      }
145      if(is_null($userid))
146          $userid = $_SERVER['REMOTE_USER'];
147      $values = array('principals/'.$userid,
148                      $name,
149                      str_replace(array('/', ' ', ':'), '_', $id),
150                      $description,
151                      'VEVENT,VTODO',
152                      0,
153                      1);
154      $query = "INSERT INTO calendars (principaluri, displayname, uri, description, components, transparent, synctoken) VALUES (".$this->sqlite->quote_and_join($values, ',').");";
155      $res = $this->sqlite->query($query);
156      if($res === false)
157        return false;
158      $query = "SELECT id FROM calendars WHERE principaluri=".$this->sqlite->quote_string($values[0])." AND ".
159               "displayname=".$this->sqlite->quote_string($values[1])." AND ".
160               "uri=".$this->sqlite->quote_string($values[2])." AND ".
161               "description=".$this->sqlite->quote_string($values[3]);
162      $res = $this->sqlite->query($query);
163      $row = $this->sqlite->res2row($res);
164      if(isset($row['id']))
165      {
166          $values = array($id, $row['id']);
167          $query = "INSERT INTO pagetocalendarmapping (page, calid) VALUES (".$this->sqlite->quote_and_join($values, ',').")";
168          $res = $this->sqlite->query($query);
169          return ($res !== false);
170      }
171
172      return false;
173  }
174
175  public function addCalendarEntryToCalendarForPage($id, $user, $params)
176  {
177      $settings = $this->getPersonalSettings($user);
178      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
179          $timezone = new \DateTimeZone($settings['timezone']);
180      else
181          $timezone = new \DateTimeZone('UTC');
182      require_once('vendor/autoload.php');
183      $vcalendar = new \Sabre\VObject\Component\VCalendar();
184      $event = $vcalendar->add('VEVENT');
185      $event->summary = $params['eventname'];
186      $dtStart = new \DateTime($params['eventfrom'], $timezone);
187      $dtEnd = new \DateTime($params['eventto'], $timezone);
188      $event->DTSTART = $dtStart;
189      $event->DTEND = $dtEnd;
190      $calid = $this->getCalendarIdForPage($id);
191      $uri = uniqid('dokuwiki-').'.ics';
192      $now = new DateTime();
193      $eventStr = $vcalendar->serialize();
194
195      $values = array($calid,
196                      $uri,
197                      $eventStr,
198                      $now->getTimestamp(),
199                      'VEVENT',
200                      $event->DTSTART->getDateTime()->getTimeStamp(),
201                      $event->DTEND->getDateTime()->getTimeStamp(),
202                      strlen($eventStr),
203                      md5($eventStr),
204                      uniqid()
205      );
206
207      $query = "INSERT INTO calendarobjects (calendarid, uri, calendardata, lastmodified, componenttype, firstoccurence, lastoccurence, size, etag, uid) VALUES (".$this->sqlite->quote_and_join($values, ',').")";
208      $res = $this->sqlite->query($query);
209      if($res !== false)
210      {
211          $this->updateSyncTokenLog($calid, $uri, 'added');
212          return true;
213      }
214      return false;
215  }
216
217  public function getEventsWithinDateRange($id, $user, $startDate, $endDate)
218  {
219      $settings = $this->getPersonalSettings($user);
220      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
221          $timezone = new \DateTimeZone($settings['timezone']);
222      else
223          $timezone = new \DateTimeZone('UTC');
224      $data = array();
225      require_once('vendor/autoload.php');
226      $calid = $this->getCalendarIdForPage($id);
227      $startTs = new \DateTime($startDate);
228      $endTs = new \DateTime($endDate);
229      $query = "SELECT calendardata, componenttype, uid FROM calendarobjects WHERE calendarid=".
230                $this->sqlite->quote_string($calid)." AND firstoccurence > ".
231                $this->sqlite->quote_string($startTs->getTimestamp())." AND firstoccurence < ".
232                $this->sqlite->quote_string($endTs->getTimestamp());
233      $res = $this->sqlite->query($query);
234      $arr = $this->sqlite->res2arr($res);
235      foreach($arr as $row)
236      {
237          if(isset($row['calendardata']))
238          {
239              $vcal = \Sabre\VObject\Reader::read($row['calendardata']);
240              $start = $vcal->VEVENT->DTSTART->getDateTime();
241              $end = $vcal->VEVENT->DTEND->getDateTime();
242              $start->setTimezone($timezone);
243              $end->setTimezone($timezone);
244              $summary = (string)$vcal->VEVENT->summary;
245              $data[] = array("title" => $summary, "start" => $start->format(\DateTime::ATOM),
246                              "end" => $end->format(\DateTime::ATOM),
247                              "id" => $row['uid']);
248          }
249      }
250      return $data;
251  }
252
253  public function getEventWithUid($uid)
254  {
255      $query = "SELECT calendardata, calendarid, componenttype, uri FROM calendarobjects WHERE uid=".
256                $this->sqlite->quote_string($uid);
257      $res = $this->sqlite->query($query);
258      $row = $this->sqlite->res2row($res);
259      return $row;
260  }
261
262  public function editCalendarEntryForPage($id, $user, $params)
263  {
264      $settings = $this->getPersonalSettings($user);
265      if($settings['timezone'] !== '' && $settings['timezone'] !== 'local')
266          $timezone = new \DateTimeZone($settings['timezone']);
267      else
268          $timezone = new \DateTimeZone('UTC');
269      $uid = $params['uid'];
270      $event = $this->getEventWithUid($uid);
271      require_once('vendor/autoload.php');
272      if(!isset($event['calendardata']))
273        return false;
274      $uri = $event['uri'];
275      $calid = $event['calendarid'];
276      $vcal = \Sabre\VObject\Reader::read($event['calendardata']);
277      $vcal->VEVENT->summary = $params['eventname'];
278      $dtStart = new \DateTime($params['eventfrom'], $timezone);
279      $dtEnd = new \DateTime($params['eventto'], $timezone);
280      $vcal->VEVENT->DTSTART = $dtStart;
281      $vcal->VEVENT->DTEND = $dtEnd;
282      $now = new DateTime();
283      $eventStr = $vcal->serialize();
284
285      $query = "UPDATE calendarobjects SET calendardata=".$this->sqlite->quote_string($eventStr).
286               ", lastmodified=".$this->sqlite->quote_string($now->getTimestamp()).
287               ", firstoccurence=".$this->sqlite->quote_string($dtStart->getTimestamp()).
288               ", lastoccurence=".$this->sqlite->quote_string($dtEnd->getTimestamp()).
289               ", size=".strlen($eventStr).
290               ", etag=".$this->sqlite->quote_string(md5($eventStr)).
291               " WHERE uid=".$this->sqlite->quote_string($uid);
292      $res = $this->sqlite->query($query);
293      if($res !== false)
294      {
295          $this->updateSyncTokenLog($calid, $uri, 'modified');
296          return true;
297      }
298      return false;
299  }
300
301  public function deleteCalendarEntryForPage($id, $params)
302  {
303      $uid = $params['uid'];
304      $event = $this->getEventWithUid($uid);
305      $calid = $event['calendarid'];
306      $uri = $event['uri'];
307      $query = "DELETE FROM calendarobjects WHERE uid=".$this->sqlite->quote_string($uid);
308      $res = $this->sqlite->query($query);
309      if($res !== false)
310      {
311          $this->updateSyncTokenLog($calid, $uri, 'deleted');
312      }
313      return true;
314  }
315
316  public function getSyncTokenForCalendar($calid)
317  {
318      $query = "SELECT synctoken FROM calendars WHERE id=".$this->sqlite->quote_string($calid);
319      $res = $this->sqlite->query($query);
320      $row = $this->sqlite->res2row($res);
321      if(isset($row['synctoken']))
322          return $row['synctoken'];
323      return false;
324  }
325
326  public function operationNameToOperation($operationName)
327  {
328      switch($operationName)
329      {
330          case 'added':
331              return 1;
332          break;
333          case 'modified':
334              return 2;
335          break;
336          case 'deleted':
337              return 3;
338          break;
339      }
340      return false;
341  }
342
343  private function updateSyncTokenLog($calid, $uri, $operation)
344  {
345      $currentToken = $this->getSyncTokenForCalendar($calid);
346      $operationCode = $this->operationNameToOperation($operation);
347      if(($operationCode === false) || ($currentToken === false))
348          return false;
349      $values = array($uri,
350                      $currentToken,
351                      $calid,
352                      $operationCode
353      );
354      $query = "INSERT INTO calendarchanges (uri, synctoken, calendarid, operation) VALUES(".
355               $this->sqlite->quote_and_join($values, ',').")";
356      $res = $this->sqlite->query($query);
357      if($res === false)
358        return false;
359      $currentToken++;
360      $query = "UPDATE calendars SET synctoken=".$this->sqlite->quote_string($currentToken)." WHERE id=".
361               $this->sqlite->quote_string($calid);
362      $res = $this->sqlite->query($query);
363      return ($res !== false);
364  }
365
366}
367