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; 14a1a3b679SAndreas Boehler 15a1a3b679SAndreas Boehler /** 16cb71a62aSAndreas 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 32cb71a62aSAndreas Boehler /** 33cb71a62aSAndreas Boehler * Set the calendar name and description for a given page with a given 34cb71a62aSAndreas Boehler * page id. 35cb71a62aSAndreas Boehler * If the calendar doesn't exist, the calendar is created! 36cb71a62aSAndreas Boehler * 37cb71a62aSAndreas Boehler * @param string $name The name of the new calendar 38cb71a62aSAndreas Boehler * @param string $description The description of the new calendar 39cb71a62aSAndreas Boehler * @param string $id (optional) The ID of the page 40cb71a62aSAndreas Boehler * @param string $userid The userid of the creating user 41cb71a62aSAndreas Boehler * 42cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false. 43cb71a62aSAndreas 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 66cb71a62aSAndreas Boehler /** 67cb71a62aSAndreas Boehler * Save the personal settings to the SQLite database 'calendarsettings'. 68cb71a62aSAndreas Boehler * 69cb71a62aSAndreas Boehler * @param array $settings The settings array to store 70cb71a62aSAndreas Boehler * @param string $userid (optional) The userid to store 71cb71a62aSAndreas Boehler * 72cb71a62aSAndreas Boehler * @param boolean True on success, otherwise false 73cb71a62aSAndreas 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 97cb71a62aSAndreas Boehler /** 98cb71a62aSAndreas Boehler * Retrieve the settings array for a given user id. 99cb71a62aSAndreas Boehler * Some sane defaults are returned, currently: 100cb71a62aSAndreas Boehler * 101cb71a62aSAndreas Boehler * timezone => local 102cb71a62aSAndreas Boehler * weeknumbers => 0 103cb71a62aSAndreas Boehler * workweek => 0 104cb71a62aSAndreas Boehler * 105cb71a62aSAndreas Boehler * @param string $userid (optional) The user id to retrieve 106cb71a62aSAndreas Boehler * 107cb71a62aSAndreas Boehler * @return array The settings array 108cb71a62aSAndreas 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 129cb71a62aSAndreas Boehler /** 130cb71a62aSAndreas Boehler * Retrieve the calendar ID based on a page ID from the SQLite table 131cb71a62aSAndreas Boehler * 'pagetocalendarmapping'. 132cb71a62aSAndreas Boehler * 133cb71a62aSAndreas Boehler * @param string $id (optional) The page ID to retrieve the corresponding calendar 134cb71a62aSAndreas Boehler * 135cb71a62aSAndreas Boehler * @return mixed the ID on success, otherwise false 136cb71a62aSAndreas 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 154cb71a62aSAndreas Boehler /** 155cb71a62aSAndreas Boehler * Retrieve the complete calendar id to page mapping. 156cb71a62aSAndreas Boehler * This is necessary to be able to retrieve a list of 157cb71a62aSAndreas Boehler * calendars for a given user and check the access rights. 158cb71a62aSAndreas Boehler * 159cb71a62aSAndreas Boehler * @return array The mapping array 160cb71a62aSAndreas 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 169cb71a62aSAndreas Boehler /** 170cb71a62aSAndreas Boehler * Retrieve all calendar IDs a given user has access to. 171cb71a62aSAndreas Boehler * The user is specified by the principalUri, so the 172cb71a62aSAndreas Boehler * user name is actually split from the URI component. 173cb71a62aSAndreas Boehler * 174cb71a62aSAndreas Boehler * Access rights are checked against DokuWiki's ACL 175cb71a62aSAndreas Boehler * and applied accordingly. 176cb71a62aSAndreas Boehler * 177cb71a62aSAndreas Boehler * @param string $principalUri The principal URI to work on 178cb71a62aSAndreas Boehler * 179cb71a62aSAndreas Boehler * @return array An associative array of calendar IDs 180cb71a62aSAndreas 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 201cb71a62aSAndreas Boehler /** 202cb71a62aSAndreas Boehler * Create a new calendar for a given page ID and set name and description 203cb71a62aSAndreas Boehler * accordingly. Also update the pagetocalendarmapping table on success. 204cb71a62aSAndreas Boehler * 205cb71a62aSAndreas Boehler * @param string $name The calendar's name 206cb71a62aSAndreas Boehler * @param string $description The calendar's description 207cb71a62aSAndreas Boehler * @param string $id (optional) The page ID to work on 208cb71a62aSAndreas Boehler * @param string $userid (optional) The user ID that created the calendar 209cb71a62aSAndreas Boehler * 210cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 211cb71a62aSAndreas 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; 232cb71a62aSAndreas Boehler 233cb71a62aSAndreas 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); 240cb71a62aSAndreas Boehler 241cb71a62aSAndreas 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 253cb71a62aSAndreas Boehler /** 254cb71a62aSAndreas Boehler * Add a new iCal entry for a given page, i.e. a given calendar. 255cb71a62aSAndreas Boehler * 256cb71a62aSAndreas Boehler * The parameter array needs to contain 257cb71a62aSAndreas Boehler * timezone => The timezone of the entries 258cb71a62aSAndreas Boehler * detectedtz => The timezone as detected by the browser 259cb71a62aSAndreas Boehler * eventfrom => The event's start date 260cb71a62aSAndreas Boehler * eventfromtime => The event's start time 261cb71a62aSAndreas Boehler * eventto => The event's end date 262cb71a62aSAndreas Boehler * eventtotime => The event's end time 263cb71a62aSAndreas Boehler * eventname => The event's name 264cb71a62aSAndreas Boehler * eventdescription => The event's description 265cb71a62aSAndreas Boehler * 266cb71a62aSAndreas Boehler * @param string $id The page ID to work on 267cb71a62aSAndreas Boehler * @param string $user The user who created the calendar 268cb71a62aSAndreas Boehler * @param string $params A parameter array with values to create 269cb71a62aSAndreas Boehler * 270cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 271cb71a62aSAndreas 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'); 281cb71a62aSAndreas Boehler 282cb71a62aSAndreas 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']); 287cb71a62aSAndreas Boehler 288cb71a62aSAndreas Boehler // Load SabreDAV 289a1a3b679SAndreas Boehler require_once('vendor/autoload.php'); 290a1a3b679SAndreas Boehler $vcalendar = new \Sabre\VObject\Component\VCalendar(); 291cb71a62aSAndreas Boehler 292cb71a62aSAndreas 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']; 297cb71a62aSAndreas Boehler 298cb71a62aSAndreas Boehler // Add a description if requested 2990eebc909SAndreas Boehler $description = $params['eventdescription']; 3000eebc909SAndreas Boehler if($description !== '') 3010eebc909SAndreas Boehler $event->add('DESCRIPTION', $description); 302cb71a62aSAndreas Boehler 303cb71a62aSAndreas 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); 308cb71a62aSAndreas Boehler 309cb71a62aSAndreas 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])); 313cb71a62aSAndreas Boehler 314cb71a62aSAndreas 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); 317cb71a62aSAndreas Boehler 318cb71a62aSAndreas 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])); 322cb71a62aSAndreas Boehler 323cb71a62aSAndreas 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); 326cb71a62aSAndreas 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')); 330cb71a62aSAndreas Boehler 331cb71a62aSAndreas Boehler // Really add Start and End events 332b269830cSAndreas Boehler $dtStartEv = $event->add('DTSTART', $dtStart); 333b269830cSAndreas Boehler $dtEndEv = $event->add('DTEND', $dtEnd); 334cb71a62aSAndreas Boehler 335cb71a62aSAndreas 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 } 341cb71a62aSAndreas Boehler 342cb71a62aSAndreas 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), 357cb71a62aSAndreas 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); 362cb71a62aSAndreas Boehler 363cb71a62aSAndreas 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 372cb71a62aSAndreas Boehler /** 373cb71a62aSAndreas Boehler * Retrieve the calendar settings of a given calendar id 374cb71a62aSAndreas Boehler * 375cb71a62aSAndreas Boehler * @param string $calid The calendar ID 376cb71a62aSAndreas Boehler * 377cb71a62aSAndreas Boehler * @return array The calendar settings array 378cb71a62aSAndreas 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 387cb71a62aSAndreas Boehler /** 388cb71a62aSAndreas Boehler * Retrieve all events that are within a given date range, 389cb71a62aSAndreas Boehler * based on the timezone setting. 390cb71a62aSAndreas Boehler * 391cb71a62aSAndreas Boehler * There is also support for retrieving recurring events, 392cb71a62aSAndreas Boehler * using Sabre's VObject Iterator. Recurring events are represented 393cb71a62aSAndreas Boehler * as individual calendar entries with the same UID. 394cb71a62aSAndreas Boehler * 395cb71a62aSAndreas Boehler * @param string $id The page ID to work with 396cb71a62aSAndreas Boehler * @param string $user The user ID to work with 397cb71a62aSAndreas Boehler * @param string $startDate The start date as a string 398cb71a62aSAndreas Boehler * @param string $endDate The end date as a string 399cb71a62aSAndreas Boehler * 400cb71a62aSAndreas Boehler * @return array An array containing the calendar entries. 401cb71a62aSAndreas 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(); 410cb71a62aSAndreas Boehler 411cb71a62aSAndreas 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); 416cb71a62aSAndreas Boehler 417cb71a62aSAndreas 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); 424cb71a62aSAndreas Boehler 425cb71a62aSAndreas 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; 433cb71a62aSAndreas 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(); 442cb71a62aSAndreas 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; 446cb71a62aSAndreas Boehler 447cb71a62aSAndreas 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 } 453cb71a62aSAndreas Boehler 454cb71a62aSAndreas Boehler // If we are within the given time range, parse the event 455*3c86dda8SAndreas Boehler $data[] = $this->convertIcalDataToEntry($event, $timezone, $row['uid'], true); 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 466cb71a62aSAndreas Boehler /** 467cb71a62aSAndreas Boehler * Helper function that parses the iCal data of a VEVENT to a calendar entry. 468cb71a62aSAndreas Boehler * 469cb71a62aSAndreas Boehler * @param \Sabre\VObject\VEvent $event The event to parse 470cb71a62aSAndreas Boehler * @param \DateTimeZone $timezone The timezone object 471cb71a62aSAndreas Boehler * @param string $uid The entry's UID 472*3c86dda8SAndreas Boehler * @param boolean $recurring (optional) Set to true to define a recurring event 473cb71a62aSAndreas Boehler * 474cb71a62aSAndreas Boehler * @return array The parse calendar entry 475cb71a62aSAndreas Boehler */ 476*3c86dda8SAndreas Boehler private function convertIcalDataToEntry($event, $timezone, $uid, $recurring = false) 477ebc4eb57SAndreas Boehler { 478ebc4eb57SAndreas Boehler $entry = array(); 479ebc4eb57SAndreas Boehler $start = $event->DTSTART; 480cb71a62aSAndreas Boehler // Parse only if the start date/time is present 481b269830cSAndreas Boehler if($start !== null) 482b269830cSAndreas Boehler { 483b269830cSAndreas Boehler $dtStart = $start->getDateTime(); 484b269830cSAndreas Boehler $dtStart->setTimezone($timezone); 485b269830cSAndreas Boehler $entry['start'] = $dtStart->format(\DateTime::ATOM); 486b269830cSAndreas Boehler if($start['VALUE'] == 'DATE') 487b269830cSAndreas Boehler $entry['allDay'] = true; 488b269830cSAndreas Boehler else 489b269830cSAndreas Boehler $entry['allDay'] = false; 490b269830cSAndreas Boehler } 491ebc4eb57SAndreas Boehler $end = $event->DTEND; 492cb71a62aSAndreas Boehler // Parse onlyl if the end date/time is present 493b269830cSAndreas Boehler if($end !== null) 494b269830cSAndreas Boehler { 495b269830cSAndreas Boehler $dtEnd = $end->getDateTime(); 496b269830cSAndreas Boehler $dtEnd->setTimezone($timezone); 497b269830cSAndreas Boehler $entry['end'] = $dtEnd->format(\DateTime::ATOM); 498b269830cSAndreas Boehler } 499ebc4eb57SAndreas Boehler $description = $event->DESCRIPTION; 5000eebc909SAndreas Boehler if($description !== null) 5010eebc909SAndreas Boehler $entry['description'] = (string)$description; 5020eebc909SAndreas Boehler else 5030eebc909SAndreas Boehler $entry['description'] = ''; 504ebc4eb57SAndreas Boehler $entry['title'] = (string)$event->summary; 505ebc4eb57SAndreas Boehler $entry['id'] = $uid; 506*3c86dda8SAndreas Boehler $entry['recurring'] = $recurring; 507ebc4eb57SAndreas Boehler return $entry; 508a1a3b679SAndreas Boehler } 509a1a3b679SAndreas Boehler 510cb71a62aSAndreas Boehler /** 511cb71a62aSAndreas Boehler * Retrieve an event by its UID 512cb71a62aSAndreas Boehler * 513cb71a62aSAndreas Boehler * @param string $uid The event's UID 514cb71a62aSAndreas Boehler * 515cb71a62aSAndreas Boehler * @return mixed The table row with the given event 516cb71a62aSAndreas Boehler */ 517a1a3b679SAndreas Boehler public function getEventWithUid($uid) 518a1a3b679SAndreas Boehler { 51955a741c0SAndreas Boehler $query = "SELECT calendardata, calendarid, componenttype, uri FROM calendarobjects WHERE uid=". 520a1a3b679SAndreas Boehler $this->sqlite->quote_string($uid); 521a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 522a1a3b679SAndreas Boehler $row = $this->sqlite->res2row($res); 523a1a3b679SAndreas Boehler return $row; 524a1a3b679SAndreas Boehler } 525a1a3b679SAndreas Boehler 526cb71a62aSAndreas Boehler /** 527cb71a62aSAndreas Boehler * Retrieve all calendar events for a given calendar ID 528cb71a62aSAndreas Boehler * 529cb71a62aSAndreas Boehler * @param string $calid The calendar's ID 530cb71a62aSAndreas Boehler * 531cb71a62aSAndreas Boehler * @return array An array containing all calendar data 532cb71a62aSAndreas Boehler */ 533f69bb449SAndreas Boehler public function getAllCalendarEvents($calid) 534f69bb449SAndreas Boehler { 535f69bb449SAndreas Boehler $query = "SELECT calendardata, uid, componenttype, uri FROM calendarobjects WHERE calendarid=". 536f69bb449SAndreas Boehler $this->sqlite->quote_string($calid); 537f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 538f69bb449SAndreas Boehler $arr = $this->sqlite->res2arr($res); 539f69bb449SAndreas Boehler return $arr; 540f69bb449SAndreas Boehler } 541f69bb449SAndreas Boehler 542cb71a62aSAndreas Boehler /** 543cb71a62aSAndreas Boehler * Edit a calendar entry for a page, given by its parameters. 544cb71a62aSAndreas Boehler * The params array has the same format as @see addCalendarEntryForPage 545cb71a62aSAndreas Boehler * 546cb71a62aSAndreas Boehler * @param string $id The page's ID to work on 547cb71a62aSAndreas Boehler * @param string $user The user's ID to work on 548cb71a62aSAndreas Boehler * @param array $params The parameter array for the edited calendar event 549cb71a62aSAndreas Boehler * 550cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 551cb71a62aSAndreas Boehler */ 552a1a3b679SAndreas Boehler public function editCalendarEntryForPage($id, $user, $params) 553a1a3b679SAndreas Boehler { 554bd883736SAndreas Boehler $settings = $this->getPersonalSettings($user); 555bd883736SAndreas Boehler if($settings['timezone'] !== '' && $settings['timezone'] !== 'local') 556bd883736SAndreas Boehler $timezone = new \DateTimeZone($settings['timezone']); 557a25c89eaSAndreas Boehler elseif($settings['timezone'] === 'local') 558a25c89eaSAndreas Boehler $timezone = new \DateTimeZone($params['detectedtz']); 559bd883736SAndreas Boehler else 560bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 561cb71a62aSAndreas Boehler 562cb71a62aSAndreas Boehler // Parse dates 563b269830cSAndreas Boehler $startDate = explode('-', $params['eventfrom']); 564b269830cSAndreas Boehler $startTime = explode(':', $params['eventfromtime']); 565b269830cSAndreas Boehler $endDate = explode('-', $params['eventto']); 566b269830cSAndreas Boehler $endTime = explode(':', $params['eventtotime']); 567cb71a62aSAndreas Boehler 568cb71a62aSAndreas Boehler // Retrieve the existing event based on the UID 56955a741c0SAndreas Boehler $uid = $params['uid']; 57055a741c0SAndreas Boehler $event = $this->getEventWithUid($uid); 571cb71a62aSAndreas Boehler 572cb71a62aSAndreas Boehler // Load SabreDAV 573a1a3b679SAndreas Boehler require_once('vendor/autoload.php'); 574a1a3b679SAndreas Boehler if(!isset($event['calendardata'])) 575a1a3b679SAndreas Boehler return false; 57655a741c0SAndreas Boehler $uri = $event['uri']; 57755a741c0SAndreas Boehler $calid = $event['calendarid']; 578cb71a62aSAndreas Boehler 579cb71a62aSAndreas Boehler // Parse the existing event 580a1a3b679SAndreas Boehler $vcal = \Sabre\VObject\Reader::read($event['calendardata']); 581b269830cSAndreas Boehler $vevent = $vcal->VEVENT; 582cb71a62aSAndreas Boehler 583cb71a62aSAndreas Boehler // Set the new event values 584b269830cSAndreas Boehler $vevent->summary = $params['eventname']; 585b269830cSAndreas Boehler $dtStamp = new \DateTime(null, new \DateTimeZone('UTC')); 5860eebc909SAndreas Boehler $description = $params['eventdescription']; 587cb71a62aSAndreas Boehler 588cb71a62aSAndreas Boehler // Remove existing timestamps to overwrite them 5890eebc909SAndreas Boehler $vevent->remove('DESCRIPTION'); 590b269830cSAndreas Boehler $vevent->remove('DTSTAMP'); 591b269830cSAndreas Boehler $vevent->remove('LAST-MODIFIED'); 592cb71a62aSAndreas Boehler 593cb71a62aSAndreas Boehler // Add new time stamps and description 594b269830cSAndreas Boehler $vevent->add('DTSTAMP', $dtStamp); 595b269830cSAndreas Boehler $vevent->add('LAST-MODIFIED', $dtStamp); 5960eebc909SAndreas Boehler if($description !== '') 5970eebc909SAndreas Boehler $vevent->add('DESCRIPTION', $description); 598cb71a62aSAndreas Boehler 599cb71a62aSAndreas Boehler // Setup DTSTART 600b269830cSAndreas Boehler $dtStart = new \DateTime(); 601a25c89eaSAndreas Boehler $dtStart->setTimezone($timezone); 602b269830cSAndreas Boehler $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2])); 603b269830cSAndreas Boehler if($params['allday'] != '1') 604b269830cSAndreas Boehler $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0); 605cb71a62aSAndreas Boehler 606cb71a62aSAndreas Boehler // Setup DETEND 607b269830cSAndreas Boehler $dtEnd = new \DateTime(); 608a25c89eaSAndreas Boehler $dtEnd->setTimezone($timezone); 609b269830cSAndreas Boehler $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2])); 610b269830cSAndreas Boehler if($params['allday'] != '1') 611b269830cSAndreas Boehler $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0); 612cb71a62aSAndreas Boehler 613b269830cSAndreas Boehler // According to the VCal spec, we need to add a whole day here 614b269830cSAndreas Boehler if($params['allday'] == '1') 615b269830cSAndreas Boehler $dtEnd->add(new \DateInterval('P1D')); 616b269830cSAndreas Boehler $vevent->remove('DTSTART'); 617b269830cSAndreas Boehler $vevent->remove('DTEND'); 618b269830cSAndreas Boehler $dtStartEv = $vevent->add('DTSTART', $dtStart); 619b269830cSAndreas Boehler $dtEndEv = $vevent->add('DTEND', $dtEnd); 620cb71a62aSAndreas Boehler 621cb71a62aSAndreas Boehler // Remove the time for allday events 622b269830cSAndreas Boehler if($params['allday'] == '1') 623b269830cSAndreas Boehler { 624b269830cSAndreas Boehler $dtStartEv['VALUE'] = 'DATE'; 625b269830cSAndreas Boehler $dtEndEv['VALUE'] = 'DATE'; 626b269830cSAndreas Boehler } 627a1a3b679SAndreas Boehler $now = new DateTime(); 628a1a3b679SAndreas Boehler $eventStr = $vcal->serialize(); 629a1a3b679SAndreas Boehler 630cb71a62aSAndreas Boehler // Actually write to the database 631a1a3b679SAndreas Boehler $query = "UPDATE calendarobjects SET calendardata=".$this->sqlite->quote_string($eventStr). 632a1a3b679SAndreas Boehler ", lastmodified=".$this->sqlite->quote_string($now->getTimestamp()). 633a1a3b679SAndreas Boehler ", firstoccurence=".$this->sqlite->quote_string($dtStart->getTimestamp()). 634a1a3b679SAndreas Boehler ", lastoccurence=".$this->sqlite->quote_string($dtEnd->getTimestamp()). 635a1a3b679SAndreas Boehler ", size=".strlen($eventStr). 636a1a3b679SAndreas Boehler ", etag=".$this->sqlite->quote_string(md5($eventStr)). 63755a741c0SAndreas Boehler " WHERE uid=".$this->sqlite->quote_string($uid); 638a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 63955a741c0SAndreas Boehler if($res !== false) 64055a741c0SAndreas Boehler { 64155a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'modified'); 642a1a3b679SAndreas Boehler return true; 643a1a3b679SAndreas Boehler } 64455a741c0SAndreas Boehler return false; 64555a741c0SAndreas Boehler } 646a1a3b679SAndreas Boehler 647cb71a62aSAndreas Boehler /** 648cb71a62aSAndreas Boehler * Delete a calendar entry for a given page. Actually, the event is removed 649cb71a62aSAndreas Boehler * based on the entry's UID, so that page ID is no used. 650cb71a62aSAndreas Boehler * 651cb71a62aSAndreas Boehler * @param string $id The page's ID (unused) 652cb71a62aSAndreas Boehler * @param array $params The parameter array to work with 653cb71a62aSAndreas Boehler * 654cb71a62aSAndreas Boehler * @return boolean True 655cb71a62aSAndreas Boehler */ 656a1a3b679SAndreas Boehler public function deleteCalendarEntryForPage($id, $params) 657a1a3b679SAndreas Boehler { 658a1a3b679SAndreas Boehler $uid = $params['uid']; 65955a741c0SAndreas Boehler $event = $this->getEventWithUid($uid); 6602c14b82bSAndreas Boehler $calid = $event['calendarid']; 66155a741c0SAndreas Boehler $uri = $event['uri']; 662a1a3b679SAndreas Boehler $query = "DELETE FROM calendarobjects WHERE uid=".$this->sqlite->quote_string($uid); 663a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 66455a741c0SAndreas Boehler if($res !== false) 66555a741c0SAndreas Boehler { 66655a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'deleted'); 66755a741c0SAndreas Boehler } 668a1a3b679SAndreas Boehler return true; 669a1a3b679SAndreas Boehler } 670a1a3b679SAndreas Boehler 671cb71a62aSAndreas Boehler /** 672cb71a62aSAndreas Boehler * Retrieve the current sync token for a calendar 673cb71a62aSAndreas Boehler * 674cb71a62aSAndreas Boehler * @param string $calid The calendar id 675cb71a62aSAndreas Boehler * 676cb71a62aSAndreas Boehler * @return mixed The synctoken or false 677cb71a62aSAndreas Boehler */ 67855a741c0SAndreas Boehler public function getSyncTokenForCalendar($calid) 67955a741c0SAndreas Boehler { 680b269830cSAndreas Boehler $row = $this->getCalendarSettings($calid); 68155a741c0SAndreas Boehler if(isset($row['synctoken'])) 68255a741c0SAndreas Boehler return $row['synctoken']; 68355a741c0SAndreas Boehler return false; 68455a741c0SAndreas Boehler } 68555a741c0SAndreas Boehler 686cb71a62aSAndreas Boehler /** 687cb71a62aSAndreas Boehler * Helper function to convert the operation name to 688cb71a62aSAndreas Boehler * an operation code as stored in the database 689cb71a62aSAndreas Boehler * 690cb71a62aSAndreas Boehler * @param string $operationName The operation name 691cb71a62aSAndreas Boehler * 692cb71a62aSAndreas Boehler * @return mixed The operation code or false 693cb71a62aSAndreas Boehler */ 69455a741c0SAndreas Boehler public function operationNameToOperation($operationName) 69555a741c0SAndreas Boehler { 69655a741c0SAndreas Boehler switch($operationName) 69755a741c0SAndreas Boehler { 69855a741c0SAndreas Boehler case 'added': 69955a741c0SAndreas Boehler return 1; 70055a741c0SAndreas Boehler break; 70155a741c0SAndreas Boehler case 'modified': 70255a741c0SAndreas Boehler return 2; 70355a741c0SAndreas Boehler break; 70455a741c0SAndreas Boehler case 'deleted': 70555a741c0SAndreas Boehler return 3; 70655a741c0SAndreas Boehler break; 70755a741c0SAndreas Boehler } 70855a741c0SAndreas Boehler return false; 70955a741c0SAndreas Boehler } 71055a741c0SAndreas Boehler 711cb71a62aSAndreas Boehler /** 712cb71a62aSAndreas Boehler * Update the sync token log based on the calendar id and the 713cb71a62aSAndreas Boehler * operation that was performed. 714cb71a62aSAndreas Boehler * 715cb71a62aSAndreas Boehler * @param string $calid The calendar ID that was modified 716cb71a62aSAndreas Boehler * @param string $uri The calendar URI that was modified 717cb71a62aSAndreas Boehler * @param string $operation The operation that was performed 718cb71a62aSAndreas Boehler * 719cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 720cb71a62aSAndreas Boehler */ 72155a741c0SAndreas Boehler private function updateSyncTokenLog($calid, $uri, $operation) 72255a741c0SAndreas Boehler { 72355a741c0SAndreas Boehler $currentToken = $this->getSyncTokenForCalendar($calid); 72455a741c0SAndreas Boehler $operationCode = $this->operationNameToOperation($operation); 72555a741c0SAndreas Boehler if(($operationCode === false) || ($currentToken === false)) 72655a741c0SAndreas Boehler return false; 72755a741c0SAndreas Boehler $values = array($uri, 72855a741c0SAndreas Boehler $currentToken, 72955a741c0SAndreas Boehler $calid, 73055a741c0SAndreas Boehler $operationCode 73155a741c0SAndreas Boehler ); 73255a741c0SAndreas Boehler $query = "INSERT INTO calendarchanges (uri, synctoken, calendarid, operation) VALUES(". 73355a741c0SAndreas Boehler $this->sqlite->quote_and_join($values, ',').")"; 73455a741c0SAndreas Boehler $res = $this->sqlite->query($query); 73555a741c0SAndreas Boehler if($res === false) 73655a741c0SAndreas Boehler return false; 73755a741c0SAndreas Boehler $currentToken++; 73855a741c0SAndreas Boehler $query = "UPDATE calendars SET synctoken=".$this->sqlite->quote_string($currentToken)." WHERE id=". 73955a741c0SAndreas Boehler $this->sqlite->quote_string($calid); 74055a741c0SAndreas Boehler $res = $this->sqlite->query($query); 74155a741c0SAndreas Boehler return ($res !== false); 74255a741c0SAndreas Boehler } 74355a741c0SAndreas Boehler 744cb71a62aSAndreas Boehler /** 745cb71a62aSAndreas Boehler * Return the sync URL for a given Page, i.e. a calendar 746cb71a62aSAndreas Boehler * 747cb71a62aSAndreas Boehler * @param string $id The page's ID 748cb71a62aSAndreas Boehler * @param string $user (optional) The user's ID 749cb71a62aSAndreas Boehler * 750cb71a62aSAndreas Boehler * @return mixed The sync url or false 751cb71a62aSAndreas Boehler */ 752b269830cSAndreas Boehler public function getSyncUrlForPage($id, $user = null) 753b269830cSAndreas Boehler { 754b269830cSAndreas Boehler if(is_null($user)) 755b269830cSAndreas Boehler $user = $_SERVER['REMOTE_USER']; 756b269830cSAndreas Boehler 757b269830cSAndreas Boehler $calid = $this->getCalendarIdForPage($id); 758b269830cSAndreas Boehler if($calid === false) 759b269830cSAndreas Boehler return false; 760b269830cSAndreas Boehler 761b269830cSAndreas Boehler $calsettings = $this->getCalendarSettings($calid); 762b269830cSAndreas Boehler if(!isset($calsettings['uri'])) 763b269830cSAndreas Boehler return false; 764b269830cSAndreas Boehler 765b269830cSAndreas Boehler $syncurl = DOKU_URL.'lib/plugins/davcal/calendarserver.php/calendars/'.$user.'/'.$calsettings['uri']; 766b269830cSAndreas Boehler return $syncurl; 767b269830cSAndreas Boehler } 768b269830cSAndreas Boehler 769cb71a62aSAndreas Boehler /** 770cb71a62aSAndreas Boehler * Return the private calendar's URL for a given page 771cb71a62aSAndreas Boehler * 772cb71a62aSAndreas Boehler * @param string $id the page ID 773cb71a62aSAndreas Boehler * 774cb71a62aSAndreas Boehler * @return mixed The private URL or false 775cb71a62aSAndreas Boehler */ 776f69bb449SAndreas Boehler public function getPrivateURLForPage($id) 777f69bb449SAndreas Boehler { 778f69bb449SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 779f69bb449SAndreas Boehler if($calid === false) 780f69bb449SAndreas Boehler return false; 781f69bb449SAndreas Boehler 782f69bb449SAndreas Boehler return $this->getPrivateURLForCalendar($calid); 783f69bb449SAndreas Boehler } 784f69bb449SAndreas Boehler 785cb71a62aSAndreas Boehler /** 786cb71a62aSAndreas Boehler * Return the private calendar's URL for a given calendar ID 787cb71a62aSAndreas Boehler * 788cb71a62aSAndreas Boehler * @param string $calid The calendar's ID 789cb71a62aSAndreas Boehler * 790cb71a62aSAndreas Boehler * @return mixed The private URL or false 791cb71a62aSAndreas Boehler */ 792f69bb449SAndreas Boehler public function getPrivateURLForCalendar($calid) 793f69bb449SAndreas Boehler { 794f69bb449SAndreas Boehler $query = "SELECT url FROM calendartoprivateurlmapping WHERE calid=".$this->sqlite->quote_string($calid); 795f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 796f69bb449SAndreas Boehler $row = $this->sqlite->res2row($res); 797f69bb449SAndreas Boehler if(!isset($row['url'])) 798f69bb449SAndreas Boehler { 799f69bb449SAndreas Boehler $url = uniqid("dokuwiki-").".ics"; 800f69bb449SAndreas Boehler $values = array( 801f69bb449SAndreas Boehler $url, 802f69bb449SAndreas Boehler $calid 803f69bb449SAndreas Boehler ); 804f69bb449SAndreas Boehler $query = "INSERT INTO calendartoprivateurlmapping (url, calid) VALUES(". 805f69bb449SAndreas Boehler $this->sqlite->quote_and_join($values, ", ").")"; 806f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 807f69bb449SAndreas Boehler if($res === false) 808f69bb449SAndreas Boehler return false; 809f69bb449SAndreas Boehler } 810f69bb449SAndreas Boehler else 811f69bb449SAndreas Boehler { 812f69bb449SAndreas Boehler $url = $row['url']; 813f69bb449SAndreas Boehler } 81470d9aa2aSAndreas Boehler return DOKU_URL.'lib/plugins/davcal/ics.php/'.$url; 815f69bb449SAndreas Boehler } 816f69bb449SAndreas Boehler 817cb71a62aSAndreas Boehler /** 818cb71a62aSAndreas Boehler * Retrieve the calendar ID for a given private calendar URL 819cb71a62aSAndreas Boehler * 820cb71a62aSAndreas Boehler * @param string $url The private URL 821cb71a62aSAndreas Boehler * 822cb71a62aSAndreas Boehler * @return mixed The calendar ID or false 823cb71a62aSAndreas Boehler */ 824f69bb449SAndreas Boehler public function getCalendarForPrivateURL($url) 825f69bb449SAndreas Boehler { 826f69bb449SAndreas Boehler $query = "SELECT calid FROM calendartoprivateurlmapping WHERE url=".$this->sqlite->quote_string($url); 827f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 828f69bb449SAndreas Boehler $row = $this->sqlite->res2row($res); 829f69bb449SAndreas Boehler if(!isset($row['calid'])) 830f69bb449SAndreas Boehler return false; 831f69bb449SAndreas Boehler return $row['calid']; 832f69bb449SAndreas Boehler } 833f69bb449SAndreas Boehler 834cb71a62aSAndreas Boehler /** 835cb71a62aSAndreas Boehler * Return a given calendar as ICS feed, i.e. all events in one ICS file. 836cb71a62aSAndreas Boehler * 837cb71a62aSAndreas Boehler * @param string $caldi The calendar ID to retrieve 838cb71a62aSAndreas Boehler * 839cb71a62aSAndreas Boehler * @return mixed The calendar events as string or false 840cb71a62aSAndreas Boehler */ 841f69bb449SAndreas Boehler public function getCalendarAsICSFeed($calid) 842f69bb449SAndreas Boehler { 843f69bb449SAndreas Boehler $calSettings = $this->getCalendarSettings($calid); 844f69bb449SAndreas Boehler if($calSettings === false) 845f69bb449SAndreas Boehler return false; 846f69bb449SAndreas Boehler $events = $this->getAllCalendarEvents($calid); 847f69bb449SAndreas Boehler if($events === false) 848f69bb449SAndreas Boehler return false; 849f69bb449SAndreas Boehler 850f69bb449SAndreas Boehler $out = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//DAVCal//DAVCal for DokuWiki//EN\nCALSCALE:GREGORIAN\nX-WR-CALNAME:"; 851f69bb449SAndreas Boehler $out .= $calSettings['displayname']."\n"; 852f69bb449SAndreas Boehler foreach($events as $event) 853f69bb449SAndreas Boehler { 854f69bb449SAndreas Boehler $out .= rtrim($event['calendardata']); 855f69bb449SAndreas Boehler $out .= "\n"; 856f69bb449SAndreas Boehler } 857f69bb449SAndreas Boehler $out .= "END:VCALENDAR\n"; 858f69bb449SAndreas Boehler return $out; 859f69bb449SAndreas Boehler } 860f69bb449SAndreas Boehler 861a1a3b679SAndreas Boehler} 862