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