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