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; 14185e2535SAndreas Boehler protected $cachedValues = array(); 15a1a3b679SAndreas Boehler 16a1a3b679SAndreas Boehler /** 17cb71a62aSAndreas Boehler * Constructor to load the configuration and the SQLite plugin 18a1a3b679SAndreas Boehler */ 19a1a3b679SAndreas Boehler public function helper_plugin_davcal() { 20a1a3b679SAndreas Boehler $this->sqlite =& plugin_load('helper', 'sqlite'); 2121d04f73SAndreas Boehler global $conf; 2221d04f73SAndreas Boehler if($conf['allowdebug']) 2321d04f73SAndreas Boehler dbglog('---- DAVCAL helper.php init'); 24a1a3b679SAndreas Boehler if(!$this->sqlite) 25a1a3b679SAndreas Boehler { 2621d04f73SAndreas Boehler if($conf['allowdebug']) 2721d04f73SAndreas Boehler dbglog('This plugin requires the sqlite plugin. Please install it.'); 28a1a3b679SAndreas Boehler msg('This plugin requires the sqlite plugin. Please install it.'); 29a1a3b679SAndreas Boehler return; 30a1a3b679SAndreas Boehler } 31a1a3b679SAndreas Boehler 32a1a3b679SAndreas Boehler if(!$this->sqlite->init('davcal', DOKU_PLUGIN.'davcal/db/')) 33a1a3b679SAndreas Boehler { 3421d04f73SAndreas Boehler if($conf['allowdebug']) 3521d04f73SAndreas Boehler dbglog('Error initialising the SQLite DB for DAVCal'); 36a1a3b679SAndreas Boehler return; 37a1a3b679SAndreas Boehler } 38a1a3b679SAndreas Boehler } 39a1a3b679SAndreas Boehler 40cb71a62aSAndreas Boehler /** 41185e2535SAndreas Boehler * Retrieve meta data for a given page 42185e2535SAndreas Boehler * 43185e2535SAndreas Boehler * @param string $id optional The page ID 44185e2535SAndreas Boehler * @return array The metadata 45185e2535SAndreas Boehler */ 46185e2535SAndreas Boehler private function getMeta($id = null) { 47185e2535SAndreas Boehler global $ID; 48185e2535SAndreas Boehler global $INFO; 49185e2535SAndreas Boehler 50185e2535SAndreas Boehler if ($id === null) $id = $ID; 51185e2535SAndreas Boehler 52185e2535SAndreas Boehler if($ID === $id && $INFO['meta']) { 53185e2535SAndreas Boehler $meta = $INFO['meta']; 54185e2535SAndreas Boehler } else { 55185e2535SAndreas Boehler $meta = p_get_metadata($id); 56185e2535SAndreas Boehler } 57185e2535SAndreas Boehler 58185e2535SAndreas Boehler return $meta; 59185e2535SAndreas Boehler } 60185e2535SAndreas Boehler 61185e2535SAndreas Boehler /** 62185e2535SAndreas Boehler * Retrieve the meta data for a given page 63185e2535SAndreas Boehler * 64185e2535SAndreas Boehler * @param string $id optional The page ID 65185e2535SAndreas Boehler * @return array with meta data 66185e2535SAndreas Boehler */ 67185e2535SAndreas Boehler public function getCalendarMetaForPage($id = null) 68185e2535SAndreas Boehler { 69185e2535SAndreas Boehler if(is_null($id)) 70185e2535SAndreas Boehler { 71185e2535SAndreas Boehler global $ID; 72185e2535SAndreas Boehler $id = $ID; 73185e2535SAndreas Boehler } 74185e2535SAndreas Boehler 75185e2535SAndreas Boehler $meta = $this->getMeta($id); 76185e2535SAndreas Boehler if(isset($meta['plugin_davcal'])) 77185e2535SAndreas Boehler return $meta['plugin_davcal']; 78185e2535SAndreas Boehler else 79185e2535SAndreas Boehler return array(); 80185e2535SAndreas Boehler } 81185e2535SAndreas Boehler 82185e2535SAndreas Boehler /** 83185e2535SAndreas Boehler * Get all calendar pages used by a given page 84185e2535SAndreas Boehler * based on the stored metadata 85185e2535SAndreas Boehler * 86185e2535SAndreas Boehler * @param string $id optional The page id 87185e2535SAndreas Boehler * @return mixed The pages as array or false 88185e2535SAndreas Boehler */ 89185e2535SAndreas Boehler public function getCalendarPagesByMeta($id = null) 90185e2535SAndreas Boehler { 91185e2535SAndreas Boehler if(is_null($id)) 92185e2535SAndreas Boehler { 93185e2535SAndreas Boehler global $ID; 94185e2535SAndreas Boehler $id = $ID; 95185e2535SAndreas Boehler } 96185e2535SAndreas Boehler 97185e2535SAndreas Boehler $meta = $this->getCalendarMetaForPage($id); 98185e2535SAndreas Boehler if(isset($meta['id'])) 99185e2535SAndreas Boehler { 100185e2535SAndreas Boehler return array_keys($meta['id']); 101185e2535SAndreas Boehler } 102185e2535SAndreas Boehler return false; 103185e2535SAndreas Boehler } 104185e2535SAndreas Boehler 105185e2535SAndreas Boehler /** 106185e2535SAndreas Boehler * Get a list of calendar names/pages/ids/colors 107185e2535SAndreas Boehler * for an array of page ids 108185e2535SAndreas Boehler * 109185e2535SAndreas Boehler * @param array $calendarPages The calendar pages to retrieve 110185e2535SAndreas Boehler * @return array The list 111185e2535SAndreas Boehler */ 112185e2535SAndreas Boehler public function getCalendarMapForIDs($calendarPages) 113185e2535SAndreas Boehler { 114185e2535SAndreas Boehler $data = array(); 115185e2535SAndreas Boehler foreach($calendarPages as $page) 116185e2535SAndreas Boehler { 117185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($page); 118185e2535SAndreas Boehler if($calid !== false) 119185e2535SAndreas Boehler { 120185e2535SAndreas Boehler $settings = $this->getCalendarSettings($calid); 121185e2535SAndreas Boehler $name = $settings['displayname']; 122185e2535SAndreas Boehler $color = $settings['calendarcolor']; 123185e2535SAndreas Boehler $data[] = array('name' => $name, 'page' => $page, 'calid' => $calid, 124185e2535SAndreas Boehler 'color' => $color); 125185e2535SAndreas Boehler } 126185e2535SAndreas Boehler } 127185e2535SAndreas Boehler return $data; 128185e2535SAndreas Boehler } 129185e2535SAndreas Boehler 130185e2535SAndreas Boehler /** 131185e2535SAndreas Boehler * Get the saved calendar color for a given page. 132185e2535SAndreas Boehler * 133185e2535SAndreas Boehler * @param string $id optional The page ID 134185e2535SAndreas Boehler * @return mixed The color on success, otherwise false 135185e2535SAndreas Boehler */ 136185e2535SAndreas Boehler public function getCalendarColorForPage($id = null) 137185e2535SAndreas Boehler { 138185e2535SAndreas Boehler if(is_null($id)) 139185e2535SAndreas Boehler { 140185e2535SAndreas Boehler global $ID; 141185e2535SAndreas Boehler $id = $ID; 142185e2535SAndreas Boehler } 143185e2535SAndreas Boehler 144185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 145185e2535SAndreas Boehler if($calid === false) 146185e2535SAndreas Boehler return false; 147185e2535SAndreas Boehler 148185e2535SAndreas Boehler return $this->getCalendarColorForCalendar($calid); 149185e2535SAndreas Boehler } 150185e2535SAndreas Boehler 151185e2535SAndreas Boehler /** 152185e2535SAndreas Boehler * Get the saved calendar color for a given calendar ID. 153185e2535SAndreas Boehler * 154185e2535SAndreas Boehler * @param string $id optional The calendar ID 155185e2535SAndreas Boehler * @return mixed The color on success, otherwise false 156185e2535SAndreas Boehler */ 157185e2535SAndreas Boehler public function getCalendarColorForCalendar($calid) 158185e2535SAndreas Boehler { 159185e2535SAndreas Boehler if(isset($this->cachedValues['calendarcolor'][$calid])) 160185e2535SAndreas Boehler return $this->cachedValues['calendarcolor'][$calid]; 161185e2535SAndreas Boehler 162185e2535SAndreas Boehler $row = $this->getCalendarSettings($calid); 163185e2535SAndreas Boehler 164185e2535SAndreas Boehler if(!isset($row['calendarcolor'])) 165185e2535SAndreas Boehler return false; 166185e2535SAndreas Boehler 167185e2535SAndreas Boehler $color = $row['calendarcolor']; 168185e2535SAndreas Boehler $this->cachedValues['calendarcolor'][$calid] = $color; 169185e2535SAndreas Boehler return $color; 170185e2535SAndreas Boehler } 171185e2535SAndreas Boehler 172185e2535SAndreas Boehler /** 173185e2535SAndreas Boehler * Set the calendar color for a given page. 174185e2535SAndreas Boehler * 175185e2535SAndreas Boehler * @param string $color The color definition 176185e2535SAndreas Boehler * @param string $id optional The page ID 177185e2535SAndreas Boehler * @return boolean True on success, otherwise false 178185e2535SAndreas Boehler */ 179185e2535SAndreas Boehler public function setCalendarColorForPage($color, $id = null) 180185e2535SAndreas Boehler { 181185e2535SAndreas Boehler if(is_null($id)) 182185e2535SAndreas Boehler { 183185e2535SAndreas Boehler global $ID; 184185e2535SAndreas Boehler $id = $ID; 185185e2535SAndreas Boehler } 186185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 187185e2535SAndreas Boehler if($calid === false) 188185e2535SAndreas Boehler return false; 189185e2535SAndreas Boehler 190185e2535SAndreas Boehler $query = "UPDATE calendars SET calendarcolor=".$this->sqlite->quote_string($color). 191185e2535SAndreas Boehler " WHERE id=".$this->sqlite->quote_string($calid); 192185e2535SAndreas Boehler $res = $this->sqlite->query($query); 193185e2535SAndreas Boehler if($res !== false) 194185e2535SAndreas Boehler { 195185e2535SAndreas Boehler $this->cachedValues['calendarcolor'][$calid] = $color; 196185e2535SAndreas Boehler return true; 197185e2535SAndreas Boehler } 198185e2535SAndreas Boehler return false; 199185e2535SAndreas Boehler } 200185e2535SAndreas Boehler 201185e2535SAndreas Boehler /** 202cb71a62aSAndreas Boehler * Set the calendar name and description for a given page with a given 203cb71a62aSAndreas Boehler * page id. 204cb71a62aSAndreas Boehler * If the calendar doesn't exist, the calendar is created! 205cb71a62aSAndreas Boehler * 206cb71a62aSAndreas Boehler * @param string $name The name of the new calendar 207cb71a62aSAndreas Boehler * @param string $description The description of the new calendar 208cb71a62aSAndreas Boehler * @param string $id (optional) The ID of the page 209cb71a62aSAndreas Boehler * @param string $userid The userid of the creating user 210cb71a62aSAndreas Boehler * 211cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false. 212cb71a62aSAndreas Boehler */ 213a1a3b679SAndreas Boehler public function setCalendarNameForPage($name, $description, $id = null, $userid = null) 214a1a3b679SAndreas Boehler { 215a1a3b679SAndreas Boehler if(is_null($id)) 216a1a3b679SAndreas Boehler { 217a1a3b679SAndreas Boehler global $ID; 218a1a3b679SAndreas Boehler $id = $ID; 219a1a3b679SAndreas Boehler } 220a1a3b679SAndreas Boehler if(is_null($userid)) 22134a47953SAndreas Boehler { 22234a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 22334a47953SAndreas Boehler { 224a1a3b679SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 22534a47953SAndreas Boehler } 22634a47953SAndreas Boehler else 22734a47953SAndreas Boehler { 22834a47953SAndreas Boehler $userid = uniqid('davcal-'); 22934a47953SAndreas Boehler } 23034a47953SAndreas Boehler } 231a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 232a1a3b679SAndreas Boehler if($calid === false) 233a1a3b679SAndreas Boehler return $this->createCalendarForPage($name, $description, $id, $userid); 234a1a3b679SAndreas Boehler 235b269830cSAndreas Boehler $query = "UPDATE calendars SET displayname=".$this->sqlite->quote_string($name).", ". 236b269830cSAndreas Boehler "description=".$this->sqlite->quote_string($description)." WHERE ". 237b269830cSAndreas Boehler "id=".$this->sqlite->quote_string($calid); 238b269830cSAndreas Boehler $res = $this->sqlite->query($query); 239b269830cSAndreas Boehler if($res !== false) 240b269830cSAndreas Boehler return true; 241b269830cSAndreas Boehler return false; 242a1a3b679SAndreas Boehler } 243a1a3b679SAndreas Boehler 244cb71a62aSAndreas Boehler /** 245cb71a62aSAndreas Boehler * Save the personal settings to the SQLite database 'calendarsettings'. 246cb71a62aSAndreas Boehler * 247cb71a62aSAndreas Boehler * @param array $settings The settings array to store 248cb71a62aSAndreas Boehler * @param string $userid (optional) The userid to store 249cb71a62aSAndreas Boehler * 250cb71a62aSAndreas Boehler * @param boolean True on success, otherwise false 251cb71a62aSAndreas Boehler */ 252a495d34cSAndreas Boehler public function savePersonalSettings($settings, $userid = null) 253a495d34cSAndreas Boehler { 254a495d34cSAndreas Boehler if(is_null($userid)) 25534a47953SAndreas Boehler { 25634a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 25734a47953SAndreas Boehler { 258a495d34cSAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 25934a47953SAndreas Boehler } 26034a47953SAndreas Boehler else 26134a47953SAndreas Boehler { 26234a47953SAndreas Boehler return false; 26334a47953SAndreas Boehler } 26434a47953SAndreas Boehler } 265a495d34cSAndreas Boehler $this->sqlite->query("BEGIN TRANSACTION"); 266a495d34cSAndreas Boehler 267bd883736SAndreas Boehler $query = "DELETE FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid); 268bd883736SAndreas Boehler $this->sqlite->query($query); 269bd883736SAndreas Boehler 270a495d34cSAndreas Boehler foreach($settings as $key => $value) 271a495d34cSAndreas Boehler { 272bd883736SAndreas Boehler $query = "INSERT INTO calendarsettings (userid, key, value) VALUES (". 273a495d34cSAndreas Boehler $this->sqlite->quote_string($userid).", ". 274a495d34cSAndreas Boehler $this->sqlite->quote_string($key).", ". 275a495d34cSAndreas Boehler $this->sqlite->quote_string($value).")"; 276a495d34cSAndreas Boehler $res = $this->sqlite->query($query); 277a495d34cSAndreas Boehler if($res === false) 278a495d34cSAndreas Boehler return false; 279a495d34cSAndreas Boehler } 280a495d34cSAndreas Boehler $this->sqlite->query("COMMIT TRANSACTION"); 281185e2535SAndreas Boehler $this->cachedValues['settings'][$userid] = $settings; 282a495d34cSAndreas Boehler return true; 283a495d34cSAndreas Boehler } 284a495d34cSAndreas Boehler 285cb71a62aSAndreas Boehler /** 286cb71a62aSAndreas Boehler * Retrieve the settings array for a given user id. 287cb71a62aSAndreas Boehler * Some sane defaults are returned, currently: 288cb71a62aSAndreas Boehler * 289cb71a62aSAndreas Boehler * timezone => local 290cb71a62aSAndreas Boehler * weeknumbers => 0 291cb71a62aSAndreas Boehler * workweek => 0 292cb71a62aSAndreas Boehler * 293cb71a62aSAndreas Boehler * @param string $userid (optional) The user id to retrieve 294cb71a62aSAndreas Boehler * 295cb71a62aSAndreas Boehler * @return array The settings array 296cb71a62aSAndreas Boehler */ 297a495d34cSAndreas Boehler public function getPersonalSettings($userid = null) 298a495d34cSAndreas Boehler { 299bd883736SAndreas Boehler // Some sane default settings 300bd883736SAndreas Boehler $settings = array( 301fb813b30SAndreas Boehler 'timezone' => $this->getConf('timezone'), 302fb813b30SAndreas Boehler 'weeknumbers' => $this->getConf('weeknumbers'), 303fb813b30SAndreas Boehler 'workweek' => $this->getConf('workweek'), 304fb813b30SAndreas Boehler 'monday' => $this->getConf('monday') 305bd883736SAndreas Boehler ); 30634a47953SAndreas Boehler if(is_null($userid)) 30734a47953SAndreas Boehler { 30834a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 30934a47953SAndreas Boehler { 31034a47953SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 31134a47953SAndreas Boehler } 31234a47953SAndreas Boehler else 31334a47953SAndreas Boehler { 31434a47953SAndreas Boehler return $settings; 31534a47953SAndreas Boehler } 31634a47953SAndreas Boehler } 31734a47953SAndreas Boehler 31834a47953SAndreas Boehler if(isset($this->cachedValues['settings'][$userid])) 31934a47953SAndreas Boehler return $this->cachedValues['settings'][$userid]; 320a495d34cSAndreas Boehler $query = "SELECT key, value FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid); 321a495d34cSAndreas Boehler $res = $this->sqlite->query($query); 322a495d34cSAndreas Boehler $arr = $this->sqlite->res2arr($res); 323a495d34cSAndreas Boehler foreach($arr as $row) 324a495d34cSAndreas Boehler { 325a495d34cSAndreas Boehler $settings[$row['key']] = $row['value']; 326a495d34cSAndreas Boehler } 327185e2535SAndreas Boehler $this->cachedValues['settings'][$userid] = $settings; 328a495d34cSAndreas Boehler return $settings; 329a495d34cSAndreas Boehler } 330a495d34cSAndreas Boehler 331cb71a62aSAndreas Boehler /** 332cb71a62aSAndreas Boehler * Retrieve the calendar ID based on a page ID from the SQLite table 333cb71a62aSAndreas Boehler * 'pagetocalendarmapping'. 334cb71a62aSAndreas Boehler * 335cb71a62aSAndreas Boehler * @param string $id (optional) The page ID to retrieve the corresponding calendar 336cb71a62aSAndreas Boehler * 337cb71a62aSAndreas Boehler * @return mixed the ID on success, otherwise false 338cb71a62aSAndreas Boehler */ 339a1a3b679SAndreas Boehler public function getCalendarIdForPage($id = null) 340a1a3b679SAndreas Boehler { 341a1a3b679SAndreas Boehler if(is_null($id)) 342a1a3b679SAndreas Boehler { 343a1a3b679SAndreas Boehler global $ID; 344a1a3b679SAndreas Boehler $id = $ID; 345a1a3b679SAndreas Boehler } 346a1a3b679SAndreas Boehler 347185e2535SAndreas Boehler if(isset($this->cachedValues['calid'][$id])) 348185e2535SAndreas Boehler return $this->cachedValues['calid'][$id]; 349185e2535SAndreas Boehler 350a1a3b679SAndreas Boehler $query = "SELECT calid FROM pagetocalendarmapping WHERE page=".$this->sqlite->quote_string($id); 351a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 352a1a3b679SAndreas Boehler $row = $this->sqlite->res2row($res); 353a1a3b679SAndreas Boehler if(isset($row['calid'])) 354185e2535SAndreas Boehler { 355185e2535SAndreas Boehler $calid = $row['calid']; 356185e2535SAndreas Boehler $this->cachedValues['calid'] = $calid; 357185e2535SAndreas Boehler return $calid; 358185e2535SAndreas Boehler } 359a1a3b679SAndreas Boehler return false; 360a1a3b679SAndreas Boehler } 361a1a3b679SAndreas Boehler 362cb71a62aSAndreas Boehler /** 363cb71a62aSAndreas Boehler * Retrieve the complete calendar id to page mapping. 364cb71a62aSAndreas Boehler * This is necessary to be able to retrieve a list of 365cb71a62aSAndreas Boehler * calendars for a given user and check the access rights. 366cb71a62aSAndreas Boehler * 367cb71a62aSAndreas Boehler * @return array The mapping array 368cb71a62aSAndreas Boehler */ 369a1a3b679SAndreas Boehler public function getCalendarIdToPageMapping() 370a1a3b679SAndreas Boehler { 371a1a3b679SAndreas Boehler $query = "SELECT calid, page FROM pagetocalendarmapping"; 372a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 373a1a3b679SAndreas Boehler $arr = $this->sqlite->res2arr($res); 374a1a3b679SAndreas Boehler return $arr; 375a1a3b679SAndreas Boehler } 376a1a3b679SAndreas Boehler 377cb71a62aSAndreas Boehler /** 378cb71a62aSAndreas Boehler * Retrieve all calendar IDs a given user has access to. 379cb71a62aSAndreas Boehler * The user is specified by the principalUri, so the 380cb71a62aSAndreas Boehler * user name is actually split from the URI component. 381cb71a62aSAndreas Boehler * 382cb71a62aSAndreas Boehler * Access rights are checked against DokuWiki's ACL 383cb71a62aSAndreas Boehler * and applied accordingly. 384cb71a62aSAndreas Boehler * 385cb71a62aSAndreas Boehler * @param string $principalUri The principal URI to work on 386cb71a62aSAndreas Boehler * 387cb71a62aSAndreas Boehler * @return array An associative array of calendar IDs 388cb71a62aSAndreas Boehler */ 389a1a3b679SAndreas Boehler public function getCalendarIdsForUser($principalUri) 390a1a3b679SAndreas Boehler { 39134a47953SAndreas Boehler global $auth; 392a1a3b679SAndreas Boehler $user = explode('/', $principalUri); 393a1a3b679SAndreas Boehler $user = end($user); 394a1a3b679SAndreas Boehler $mapping = $this->getCalendarIdToPageMapping(); 395a1a3b679SAndreas Boehler $calids = array(); 39634a47953SAndreas Boehler $ud = $auth->getUserData($user); 39734a47953SAndreas Boehler $groups = $ud['grps']; 398a1a3b679SAndreas Boehler foreach($mapping as $row) 399a1a3b679SAndreas Boehler { 400a1a3b679SAndreas Boehler $id = $row['calid']; 401a1a3b679SAndreas Boehler $page = $row['page']; 40234a47953SAndreas Boehler $acl = auth_aclcheck($page, $user, $groups); 403a1a3b679SAndreas Boehler if($acl >= AUTH_READ) 404a1a3b679SAndreas Boehler { 405a1a3b679SAndreas Boehler $write = $acl > AUTH_READ; 406a1a3b679SAndreas Boehler $calids[$id] = array('readonly' => !$write); 407a1a3b679SAndreas Boehler } 408a1a3b679SAndreas Boehler } 409a1a3b679SAndreas Boehler return $calids; 410a1a3b679SAndreas Boehler } 411a1a3b679SAndreas Boehler 412cb71a62aSAndreas Boehler /** 413cb71a62aSAndreas Boehler * Create a new calendar for a given page ID and set name and description 414cb71a62aSAndreas Boehler * accordingly. Also update the pagetocalendarmapping table on success. 415cb71a62aSAndreas Boehler * 416cb71a62aSAndreas Boehler * @param string $name The calendar's name 417cb71a62aSAndreas Boehler * @param string $description The calendar's description 418cb71a62aSAndreas Boehler * @param string $id (optional) The page ID to work on 419cb71a62aSAndreas Boehler * @param string $userid (optional) The user ID that created the calendar 420cb71a62aSAndreas Boehler * 421cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 422cb71a62aSAndreas Boehler */ 423a1a3b679SAndreas Boehler public function createCalendarForPage($name, $description, $id = null, $userid = null) 424a1a3b679SAndreas Boehler { 425a1a3b679SAndreas Boehler if(is_null($id)) 426a1a3b679SAndreas Boehler { 427a1a3b679SAndreas Boehler global $ID; 428a1a3b679SAndreas Boehler $id = $ID; 429a1a3b679SAndreas Boehler } 430a1a3b679SAndreas Boehler if(is_null($userid)) 43134a47953SAndreas Boehler { 43234a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 43334a47953SAndreas Boehler { 434a1a3b679SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 43534a47953SAndreas Boehler } 43634a47953SAndreas Boehler else 43734a47953SAndreas Boehler { 43834a47953SAndreas Boehler $userid = uniqid('davcal-'); 43934a47953SAndreas Boehler } 44034a47953SAndreas Boehler } 441a1a3b679SAndreas Boehler $values = array('principals/'.$userid, 442a1a3b679SAndreas Boehler $name, 443a1a3b679SAndreas Boehler str_replace(array('/', ' ', ':'), '_', $id), 444a1a3b679SAndreas Boehler $description, 445a1a3b679SAndreas Boehler 'VEVENT,VTODO', 44655a741c0SAndreas Boehler 0, 44755a741c0SAndreas Boehler 1); 44855a741c0SAndreas Boehler $query = "INSERT INTO calendars (principaluri, displayname, uri, description, components, transparent, synctoken) VALUES (".$this->sqlite->quote_and_join($values, ',').");"; 449a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 45055a741c0SAndreas Boehler if($res === false) 45155a741c0SAndreas Boehler return false; 452cb71a62aSAndreas Boehler 453cb71a62aSAndreas Boehler // Get the new calendar ID 454a1a3b679SAndreas Boehler $query = "SELECT id FROM calendars WHERE principaluri=".$this->sqlite->quote_string($values[0])." AND ". 455a1a3b679SAndreas Boehler "displayname=".$this->sqlite->quote_string($values[1])." AND ". 456a1a3b679SAndreas Boehler "uri=".$this->sqlite->quote_string($values[2])." AND ". 457a1a3b679SAndreas Boehler "description=".$this->sqlite->quote_string($values[3]); 458a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 459a1a3b679SAndreas Boehler $row = $this->sqlite->res2row($res); 460cb71a62aSAndreas Boehler 461cb71a62aSAndreas Boehler // Update the pagetocalendarmapping table with the new calendar ID 462a1a3b679SAndreas Boehler if(isset($row['id'])) 463a1a3b679SAndreas Boehler { 464a1a3b679SAndreas Boehler $values = array($id, $row['id']); 465a1a3b679SAndreas Boehler $query = "INSERT INTO pagetocalendarmapping (page, calid) VALUES (".$this->sqlite->quote_and_join($values, ',').")"; 466a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 46755a741c0SAndreas Boehler return ($res !== false); 468a1a3b679SAndreas Boehler } 469a1a3b679SAndreas Boehler 470a1a3b679SAndreas Boehler return false; 471a1a3b679SAndreas Boehler } 472a1a3b679SAndreas Boehler 473cb71a62aSAndreas Boehler /** 474cb71a62aSAndreas Boehler * Add a new iCal entry for a given page, i.e. a given calendar. 475cb71a62aSAndreas Boehler * 476cb71a62aSAndreas Boehler * The parameter array needs to contain 477cb71a62aSAndreas Boehler * timezone => The timezone of the entries 478cb71a62aSAndreas Boehler * detectedtz => The timezone as detected by the browser 479cb71a62aSAndreas Boehler * eventfrom => The event's start date 480cb71a62aSAndreas Boehler * eventfromtime => The event's start time 481cb71a62aSAndreas Boehler * eventto => The event's end date 482cb71a62aSAndreas Boehler * eventtotime => The event's end time 483cb71a62aSAndreas Boehler * eventname => The event's name 484cb71a62aSAndreas Boehler * eventdescription => The event's description 485cb71a62aSAndreas Boehler * 486cb71a62aSAndreas Boehler * @param string $id The page ID to work on 487cb71a62aSAndreas Boehler * @param string $user The user who created the calendar 488cb71a62aSAndreas Boehler * @param string $params A parameter array with values to create 489cb71a62aSAndreas Boehler * 490cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 491cb71a62aSAndreas Boehler */ 492a1a3b679SAndreas Boehler public function addCalendarEntryToCalendarForPage($id, $user, $params) 493a1a3b679SAndreas Boehler { 494bd883736SAndreas Boehler $settings = $this->getPersonalSettings($user); 495bd883736SAndreas Boehler if($settings['timezone'] !== '' && $settings['timezone'] !== 'local') 496bd883736SAndreas Boehler $timezone = new \DateTimeZone($settings['timezone']); 497a25c89eaSAndreas Boehler elseif($settings['timezone'] === 'local') 498a25c89eaSAndreas Boehler $timezone = new \DateTimeZone($params['detectedtz']); 499bd883736SAndreas Boehler else 500bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 501cb71a62aSAndreas Boehler 502cb71a62aSAndreas Boehler // Retrieve dates from settings 503b269830cSAndreas Boehler $startDate = explode('-', $params['eventfrom']); 504b269830cSAndreas Boehler $startTime = explode(':', $params['eventfromtime']); 505b269830cSAndreas Boehler $endDate = explode('-', $params['eventto']); 506b269830cSAndreas Boehler $endTime = explode(':', $params['eventtotime']); 507cb71a62aSAndreas Boehler 508cb71a62aSAndreas Boehler // Load SabreDAV 5099bef4ad8SAndreas Boehler require_once(DOKU_PLUGIN.'davcal/vendor/autoload.php'); 510a1a3b679SAndreas Boehler $vcalendar = new \Sabre\VObject\Component\VCalendar(); 511cb71a62aSAndreas Boehler 512cb71a62aSAndreas Boehler // Add VCalendar, UID and Event Name 513a1a3b679SAndreas Boehler $event = $vcalendar->add('VEVENT'); 514b269830cSAndreas Boehler $uuid = \Sabre\VObject\UUIDUtil::getUUID(); 515b269830cSAndreas Boehler $event->add('UID', $uuid); 516a1a3b679SAndreas Boehler $event->summary = $params['eventname']; 517cb71a62aSAndreas Boehler 518cb71a62aSAndreas Boehler // Add a description if requested 5190eebc909SAndreas Boehler $description = $params['eventdescription']; 5200eebc909SAndreas Boehler if($description !== '') 5210eebc909SAndreas Boehler $event->add('DESCRIPTION', $description); 522cb71a62aSAndreas Boehler 523*4ecb526cSAndreas Boehler // Add attachments 524*4ecb526cSAndreas Boehler $attachments = $params['attachments']; 525*4ecb526cSAndreas Boehler foreach($attachments as $attachment) 526*4ecb526cSAndreas Boehler $event->add('ATTACH', $attachment); 527*4ecb526cSAndreas Boehler 528cb71a62aSAndreas Boehler // Create a timestamp for last modified, created and dtstamp values in UTC 529b269830cSAndreas Boehler $dtStamp = new \DateTime(null, new \DateTimeZone('UTC')); 530b269830cSAndreas Boehler $event->add('DTSTAMP', $dtStamp); 531b269830cSAndreas Boehler $event->add('CREATED', $dtStamp); 532b269830cSAndreas Boehler $event->add('LAST-MODIFIED', $dtStamp); 533cb71a62aSAndreas Boehler 534cb71a62aSAndreas Boehler // Adjust the start date, based on the given timezone information 535b269830cSAndreas Boehler $dtStart = new \DateTime(); 536a25c89eaSAndreas Boehler $dtStart->setTimezone($timezone); 537b269830cSAndreas Boehler $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2])); 538cb71a62aSAndreas Boehler 539cb71a62aSAndreas Boehler // Only add the time values if it's not an allday event 540b269830cSAndreas Boehler if($params['allday'] != '1') 541b269830cSAndreas Boehler $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0); 542cb71a62aSAndreas Boehler 543cb71a62aSAndreas Boehler // Adjust the end date, based on the given timezone information 544b269830cSAndreas Boehler $dtEnd = new \DateTime(); 545a25c89eaSAndreas Boehler $dtEnd->setTimezone($timezone); 546b269830cSAndreas Boehler $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2])); 547cb71a62aSAndreas Boehler 548cb71a62aSAndreas Boehler // Only add the time values if it's not an allday event 549b269830cSAndreas Boehler if($params['allday'] != '1') 550b269830cSAndreas Boehler $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0); 551cb71a62aSAndreas Boehler 552b269830cSAndreas Boehler // According to the VCal spec, we need to add a whole day here 553b269830cSAndreas Boehler if($params['allday'] == '1') 554b269830cSAndreas Boehler $dtEnd->add(new \DateInterval('P1D')); 555cb71a62aSAndreas Boehler 556cb71a62aSAndreas Boehler // Really add Start and End events 557b269830cSAndreas Boehler $dtStartEv = $event->add('DTSTART', $dtStart); 558b269830cSAndreas Boehler $dtEndEv = $event->add('DTEND', $dtEnd); 559cb71a62aSAndreas Boehler 560cb71a62aSAndreas Boehler // Adjust the DATE format for allday events 561b269830cSAndreas Boehler if($params['allday'] == '1') 562b269830cSAndreas Boehler { 563b269830cSAndreas Boehler $dtStartEv['VALUE'] = 'DATE'; 564b269830cSAndreas Boehler $dtEndEv['VALUE'] = 'DATE'; 565b269830cSAndreas Boehler } 566cb71a62aSAndreas Boehler 567cb71a62aSAndreas Boehler // Actually add the values to the database 568a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 569a1a3b679SAndreas Boehler $uri = uniqid('dokuwiki-').'.ics'; 570a1a3b679SAndreas Boehler $now = new DateTime(); 571a1a3b679SAndreas Boehler $eventStr = $vcalendar->serialize(); 572a1a3b679SAndreas Boehler 573a1a3b679SAndreas Boehler $values = array($calid, 574a1a3b679SAndreas Boehler $uri, 575a1a3b679SAndreas Boehler $eventStr, 576a1a3b679SAndreas Boehler $now->getTimestamp(), 577a1a3b679SAndreas Boehler 'VEVENT', 578a1a3b679SAndreas Boehler $event->DTSTART->getDateTime()->getTimeStamp(), 579a1a3b679SAndreas Boehler $event->DTEND->getDateTime()->getTimeStamp(), 580a1a3b679SAndreas Boehler strlen($eventStr), 581a1a3b679SAndreas Boehler md5($eventStr), 582cb71a62aSAndreas Boehler $uuid 583a1a3b679SAndreas Boehler ); 584a1a3b679SAndreas Boehler 585a1a3b679SAndreas Boehler $query = "INSERT INTO calendarobjects (calendarid, uri, calendardata, lastmodified, componenttype, firstoccurence, lastoccurence, size, etag, uid) VALUES (".$this->sqlite->quote_and_join($values, ',').")"; 586a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 587cb71a62aSAndreas Boehler 588cb71a62aSAndreas Boehler // If successfully, update the sync token database 58955a741c0SAndreas Boehler if($res !== false) 59055a741c0SAndreas Boehler { 59155a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'added'); 592a1a3b679SAndreas Boehler return true; 593a1a3b679SAndreas Boehler } 59455a741c0SAndreas Boehler return false; 59555a741c0SAndreas Boehler } 596a1a3b679SAndreas Boehler 597cb71a62aSAndreas Boehler /** 598cb71a62aSAndreas Boehler * Retrieve the calendar settings of a given calendar id 599cb71a62aSAndreas Boehler * 600cb71a62aSAndreas Boehler * @param string $calid The calendar ID 601cb71a62aSAndreas Boehler * 602cb71a62aSAndreas Boehler * @return array The calendar settings array 603cb71a62aSAndreas Boehler */ 604b269830cSAndreas Boehler public function getCalendarSettings($calid) 605b269830cSAndreas Boehler { 606185e2535SAndreas Boehler $query = "SELECT principaluri, calendarcolor, displayname, uri, description, components, transparent, synctoken FROM calendars WHERE id=".$this->sqlite->quote_string($calid); 607b269830cSAndreas Boehler $res = $this->sqlite->query($query); 608b269830cSAndreas Boehler $row = $this->sqlite->res2row($res); 609b269830cSAndreas Boehler return $row; 610b269830cSAndreas Boehler } 611b269830cSAndreas Boehler 612cb71a62aSAndreas Boehler /** 613cb71a62aSAndreas Boehler * Retrieve all events that are within a given date range, 614cb71a62aSAndreas Boehler * based on the timezone setting. 615cb71a62aSAndreas Boehler * 616cb71a62aSAndreas Boehler * There is also support for retrieving recurring events, 617cb71a62aSAndreas Boehler * using Sabre's VObject Iterator. Recurring events are represented 618cb71a62aSAndreas Boehler * as individual calendar entries with the same UID. 619cb71a62aSAndreas Boehler * 620cb71a62aSAndreas Boehler * @param string $id The page ID to work with 621cb71a62aSAndreas Boehler * @param string $user The user ID to work with 622cb71a62aSAndreas Boehler * @param string $startDate The start date as a string 623cb71a62aSAndreas Boehler * @param string $endDate The end date as a string 624cb71a62aSAndreas Boehler * 625cb71a62aSAndreas Boehler * @return array An array containing the calendar entries. 626cb71a62aSAndreas Boehler */ 627a1a3b679SAndreas Boehler public function getEventsWithinDateRange($id, $user, $startDate, $endDate) 628a1a3b679SAndreas Boehler { 629bd883736SAndreas Boehler $settings = $this->getPersonalSettings($user); 630bd883736SAndreas Boehler if($settings['timezone'] !== '' && $settings['timezone'] !== 'local') 631bd883736SAndreas Boehler $timezone = new \DateTimeZone($settings['timezone']); 632bd883736SAndreas Boehler else 633bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 634a1a3b679SAndreas Boehler $data = array(); 635cb71a62aSAndreas Boehler 636cb71a62aSAndreas Boehler // Load SabreDAV 6379bef4ad8SAndreas Boehler require_once(DOKU_PLUGIN.'davcal/vendor/autoload.php'); 638a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 639185e2535SAndreas Boehler $color = $this->getCalendarColorForCalendar($calid); 640a1a3b679SAndreas Boehler $startTs = new \DateTime($startDate); 641a1a3b679SAndreas Boehler $endTs = new \DateTime($endDate); 642cb71a62aSAndreas Boehler 643cb71a62aSAndreas Boehler // Retrieve matching calendar objects 644ebc4eb57SAndreas Boehler $query = "SELECT calendardata, componenttype, uid FROM calendarobjects WHERE calendarid=". 645ebc4eb57SAndreas Boehler $this->sqlite->quote_string($calid)." AND firstoccurence < ". 646ebc4eb57SAndreas Boehler $this->sqlite->quote_string($endTs->getTimestamp())." AND lastoccurence > ". 647ebc4eb57SAndreas Boehler $this->sqlite->quote_string($startTs->getTimestamp()); 648a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 649a1a3b679SAndreas Boehler $arr = $this->sqlite->res2arr($res); 650cb71a62aSAndreas Boehler 651cb71a62aSAndreas Boehler // Parse individual calendar entries 652a1a3b679SAndreas Boehler foreach($arr as $row) 653a1a3b679SAndreas Boehler { 654a1a3b679SAndreas Boehler if(isset($row['calendardata'])) 655a1a3b679SAndreas Boehler { 656b269830cSAndreas Boehler $entry = array(); 657a1a3b679SAndreas Boehler $vcal = \Sabre\VObject\Reader::read($row['calendardata']); 658ebc4eb57SAndreas Boehler $recurrence = $vcal->VEVENT->RRULE; 659cb71a62aSAndreas Boehler // If it is a recurring event, pass it through Sabre's EventIterator 660ebc4eb57SAndreas Boehler if($recurrence != null) 661ebc4eb57SAndreas Boehler { 662ebc4eb57SAndreas Boehler $rEvents = new \Sabre\VObject\Recur\EventIterator(array($vcal->VEVENT)); 663ebc4eb57SAndreas Boehler $rEvents->rewind(); 664ebc4eb57SAndreas Boehler $done = false; 665ebc4eb57SAndreas Boehler while($rEvents->valid() && !$done) 666ebc4eb57SAndreas Boehler { 667ebc4eb57SAndreas Boehler $event = $rEvents->getEventObject(); 668cb71a62aSAndreas Boehler // If we are after the given time range, exit 669ebc4eb57SAndreas Boehler if(($rEvents->getDtStart()->getTimestamp() > $endTs->getTimestamp()) && 670ebc4eb57SAndreas Boehler ($rEvents->getDtEnd()->getTimestamp() > $endTs->getTimestamp())) 671ebc4eb57SAndreas Boehler $done = true; 672cb71a62aSAndreas Boehler 673cb71a62aSAndreas Boehler // If we are before the given time range, continue 674ebc4eb57SAndreas Boehler if($rEvents->getDtEnd()->getTimestamp() < $startTs->getTimestamp()) 675ebc4eb57SAndreas Boehler { 676ebc4eb57SAndreas Boehler $rEvents->next(); 677ebc4eb57SAndreas Boehler continue; 678ebc4eb57SAndreas Boehler } 679cb71a62aSAndreas Boehler 680cb71a62aSAndreas Boehler // If we are within the given time range, parse the event 681185e2535SAndreas Boehler $data[] = $this->convertIcalDataToEntry($event, $id, $timezone, $row['uid'], $color, true); 682ebc4eb57SAndreas Boehler $rEvents->next(); 683ebc4eb57SAndreas Boehler } 684ebc4eb57SAndreas Boehler } 685ebc4eb57SAndreas Boehler else 686185e2535SAndreas Boehler $data[] = $this->convertIcalDataToEntry($vcal->VEVENT, $id, $timezone, $row['uid'], $color); 687ebc4eb57SAndreas Boehler } 688ebc4eb57SAndreas Boehler } 689ebc4eb57SAndreas Boehler return $data; 690ebc4eb57SAndreas Boehler } 691ebc4eb57SAndreas Boehler 692cb71a62aSAndreas Boehler /** 693cb71a62aSAndreas Boehler * Helper function that parses the iCal data of a VEVENT to a calendar entry. 694cb71a62aSAndreas Boehler * 695cb71a62aSAndreas Boehler * @param \Sabre\VObject\VEvent $event The event to parse 696cb71a62aSAndreas Boehler * @param \DateTimeZone $timezone The timezone object 697cb71a62aSAndreas Boehler * @param string $uid The entry's UID 6983c86dda8SAndreas Boehler * @param boolean $recurring (optional) Set to true to define a recurring event 699cb71a62aSAndreas Boehler * 700cb71a62aSAndreas Boehler * @return array The parse calendar entry 701cb71a62aSAndreas Boehler */ 702185e2535SAndreas Boehler private function convertIcalDataToEntry($event, $page, $timezone, $uid, $color, $recurring = false) 703ebc4eb57SAndreas Boehler { 704ebc4eb57SAndreas Boehler $entry = array(); 705ebc4eb57SAndreas Boehler $start = $event->DTSTART; 706cb71a62aSAndreas Boehler // Parse only if the start date/time is present 707b269830cSAndreas Boehler if($start !== null) 708b269830cSAndreas Boehler { 709b269830cSAndreas Boehler $dtStart = $start->getDateTime(); 710b269830cSAndreas Boehler $dtStart->setTimezone($timezone); 711b269830cSAndreas Boehler $entry['start'] = $dtStart->format(\DateTime::ATOM); 712b269830cSAndreas Boehler if($start['VALUE'] == 'DATE') 713b269830cSAndreas Boehler $entry['allDay'] = true; 714b269830cSAndreas Boehler else 715b269830cSAndreas Boehler $entry['allDay'] = false; 716b269830cSAndreas Boehler } 717ebc4eb57SAndreas Boehler $end = $event->DTEND; 718cb71a62aSAndreas Boehler // Parse onlyl if the end date/time is present 719b269830cSAndreas Boehler if($end !== null) 720b269830cSAndreas Boehler { 721b269830cSAndreas Boehler $dtEnd = $end->getDateTime(); 722b269830cSAndreas Boehler $dtEnd->setTimezone($timezone); 723b269830cSAndreas Boehler $entry['end'] = $dtEnd->format(\DateTime::ATOM); 724b269830cSAndreas Boehler } 725ebc4eb57SAndreas Boehler $description = $event->DESCRIPTION; 7260eebc909SAndreas Boehler if($description !== null) 7270eebc909SAndreas Boehler $entry['description'] = (string)$description; 7280eebc909SAndreas Boehler else 7290eebc909SAndreas Boehler $entry['description'] = ''; 730*4ecb526cSAndreas Boehler $attachments = $event->ATTACH; 731*4ecb526cSAndreas Boehler if($attachments !== null) 732*4ecb526cSAndreas Boehler { 733*4ecb526cSAndreas Boehler $entry['attachments'] = array(); 734*4ecb526cSAndreas Boehler foreach($attachments as $attachment) 735*4ecb526cSAndreas Boehler $entry['attachments'][] = (string)$attachment; 736*4ecb526cSAndreas Boehler } 737ebc4eb57SAndreas Boehler $entry['title'] = (string)$event->summary; 738ebc4eb57SAndreas Boehler $entry['id'] = $uid; 739185e2535SAndreas Boehler $entry['page'] = $page; 740185e2535SAndreas Boehler $entry['color'] = $color; 7413c86dda8SAndreas Boehler $entry['recurring'] = $recurring; 742185e2535SAndreas Boehler 743ebc4eb57SAndreas Boehler return $entry; 744a1a3b679SAndreas Boehler } 745a1a3b679SAndreas Boehler 746cb71a62aSAndreas Boehler /** 747cb71a62aSAndreas Boehler * Retrieve an event by its UID 748cb71a62aSAndreas Boehler * 749cb71a62aSAndreas Boehler * @param string $uid The event's UID 750cb71a62aSAndreas Boehler * 751cb71a62aSAndreas Boehler * @return mixed The table row with the given event 752cb71a62aSAndreas Boehler */ 753a1a3b679SAndreas Boehler public function getEventWithUid($uid) 754a1a3b679SAndreas Boehler { 75555a741c0SAndreas Boehler $query = "SELECT calendardata, calendarid, componenttype, uri FROM calendarobjects WHERE uid=". 756a1a3b679SAndreas Boehler $this->sqlite->quote_string($uid); 757a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 758a1a3b679SAndreas Boehler $row = $this->sqlite->res2row($res); 759a1a3b679SAndreas Boehler return $row; 760a1a3b679SAndreas Boehler } 761a1a3b679SAndreas Boehler 762cb71a62aSAndreas Boehler /** 763cb71a62aSAndreas Boehler * Retrieve all calendar events for a given calendar ID 764cb71a62aSAndreas Boehler * 765cb71a62aSAndreas Boehler * @param string $calid The calendar's ID 766cb71a62aSAndreas Boehler * 767cb71a62aSAndreas Boehler * @return array An array containing all calendar data 768cb71a62aSAndreas Boehler */ 769f69bb449SAndreas Boehler public function getAllCalendarEvents($calid) 770f69bb449SAndreas Boehler { 771f69bb449SAndreas Boehler $query = "SELECT calendardata, uid, componenttype, uri FROM calendarobjects WHERE calendarid=". 772f69bb449SAndreas Boehler $this->sqlite->quote_string($calid); 773f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 774f69bb449SAndreas Boehler $arr = $this->sqlite->res2arr($res); 775f69bb449SAndreas Boehler return $arr; 776f69bb449SAndreas Boehler } 777f69bb449SAndreas Boehler 778cb71a62aSAndreas Boehler /** 779cb71a62aSAndreas Boehler * Edit a calendar entry for a page, given by its parameters. 780cb71a62aSAndreas Boehler * The params array has the same format as @see addCalendarEntryForPage 781cb71a62aSAndreas Boehler * 782cb71a62aSAndreas Boehler * @param string $id The page's ID to work on 783cb71a62aSAndreas Boehler * @param string $user The user's ID to work on 784cb71a62aSAndreas Boehler * @param array $params The parameter array for the edited calendar event 785cb71a62aSAndreas Boehler * 786cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 787cb71a62aSAndreas Boehler */ 788a1a3b679SAndreas Boehler public function editCalendarEntryForPage($id, $user, $params) 789a1a3b679SAndreas Boehler { 790bd883736SAndreas Boehler $settings = $this->getPersonalSettings($user); 791bd883736SAndreas Boehler if($settings['timezone'] !== '' && $settings['timezone'] !== 'local') 792bd883736SAndreas Boehler $timezone = new \DateTimeZone($settings['timezone']); 793a25c89eaSAndreas Boehler elseif($settings['timezone'] === 'local') 794a25c89eaSAndreas Boehler $timezone = new \DateTimeZone($params['detectedtz']); 795bd883736SAndreas Boehler else 796bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 797cb71a62aSAndreas Boehler 798cb71a62aSAndreas Boehler // Parse dates 799b269830cSAndreas Boehler $startDate = explode('-', $params['eventfrom']); 800b269830cSAndreas Boehler $startTime = explode(':', $params['eventfromtime']); 801b269830cSAndreas Boehler $endDate = explode('-', $params['eventto']); 802b269830cSAndreas Boehler $endTime = explode(':', $params['eventtotime']); 803cb71a62aSAndreas Boehler 804cb71a62aSAndreas Boehler // Retrieve the existing event based on the UID 80555a741c0SAndreas Boehler $uid = $params['uid']; 80655a741c0SAndreas Boehler $event = $this->getEventWithUid($uid); 807cb71a62aSAndreas Boehler 808cb71a62aSAndreas Boehler // Load SabreDAV 8099bef4ad8SAndreas Boehler require_once(DOKU_PLUGIN.'davcal/vendor/autoload.php'); 810a1a3b679SAndreas Boehler if(!isset($event['calendardata'])) 811a1a3b679SAndreas Boehler return false; 81255a741c0SAndreas Boehler $uri = $event['uri']; 81355a741c0SAndreas Boehler $calid = $event['calendarid']; 814cb71a62aSAndreas Boehler 815cb71a62aSAndreas Boehler // Parse the existing event 816a1a3b679SAndreas Boehler $vcal = \Sabre\VObject\Reader::read($event['calendardata']); 817b269830cSAndreas Boehler $vevent = $vcal->VEVENT; 818cb71a62aSAndreas Boehler 819cb71a62aSAndreas Boehler // Set the new event values 820b269830cSAndreas Boehler $vevent->summary = $params['eventname']; 821b269830cSAndreas Boehler $dtStamp = new \DateTime(null, new \DateTimeZone('UTC')); 8220eebc909SAndreas Boehler $description = $params['eventdescription']; 823cb71a62aSAndreas Boehler 824cb71a62aSAndreas Boehler // Remove existing timestamps to overwrite them 8250eebc909SAndreas Boehler $vevent->remove('DESCRIPTION'); 826b269830cSAndreas Boehler $vevent->remove('DTSTAMP'); 827b269830cSAndreas Boehler $vevent->remove('LAST-MODIFIED'); 828*4ecb526cSAndreas Boehler $vevent->remove('ATTACH'); 829cb71a62aSAndreas Boehler 830cb71a62aSAndreas Boehler // Add new time stamps and description 831b269830cSAndreas Boehler $vevent->add('DTSTAMP', $dtStamp); 832b269830cSAndreas Boehler $vevent->add('LAST-MODIFIED', $dtStamp); 8330eebc909SAndreas Boehler if($description !== '') 8340eebc909SAndreas Boehler $vevent->add('DESCRIPTION', $description); 835cb71a62aSAndreas Boehler 836*4ecb526cSAndreas Boehler // Add attachments 837*4ecb526cSAndreas Boehler $attachments = $params['attachments']; 838*4ecb526cSAndreas Boehler foreach($attachments as $attachment) 839*4ecb526cSAndreas Boehler $vevent->add('ATTACH', $attachment); 840*4ecb526cSAndreas Boehler 841cb71a62aSAndreas Boehler // Setup DTSTART 842b269830cSAndreas Boehler $dtStart = new \DateTime(); 843a25c89eaSAndreas Boehler $dtStart->setTimezone($timezone); 844b269830cSAndreas Boehler $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2])); 845b269830cSAndreas Boehler if($params['allday'] != '1') 846b269830cSAndreas Boehler $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0); 847cb71a62aSAndreas Boehler 848*4ecb526cSAndreas Boehler // Setup DTEND 849b269830cSAndreas Boehler $dtEnd = new \DateTime(); 850a25c89eaSAndreas Boehler $dtEnd->setTimezone($timezone); 851b269830cSAndreas Boehler $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2])); 852b269830cSAndreas Boehler if($params['allday'] != '1') 853b269830cSAndreas Boehler $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0); 854cb71a62aSAndreas Boehler 855b269830cSAndreas Boehler // According to the VCal spec, we need to add a whole day here 856b269830cSAndreas Boehler if($params['allday'] == '1') 857b269830cSAndreas Boehler $dtEnd->add(new \DateInterval('P1D')); 858b269830cSAndreas Boehler $vevent->remove('DTSTART'); 859b269830cSAndreas Boehler $vevent->remove('DTEND'); 860b269830cSAndreas Boehler $dtStartEv = $vevent->add('DTSTART', $dtStart); 861b269830cSAndreas Boehler $dtEndEv = $vevent->add('DTEND', $dtEnd); 862cb71a62aSAndreas Boehler 863cb71a62aSAndreas Boehler // Remove the time for allday events 864b269830cSAndreas Boehler if($params['allday'] == '1') 865b269830cSAndreas Boehler { 866b269830cSAndreas Boehler $dtStartEv['VALUE'] = 'DATE'; 867b269830cSAndreas Boehler $dtEndEv['VALUE'] = 'DATE'; 868b269830cSAndreas Boehler } 869a1a3b679SAndreas Boehler $now = new DateTime(); 870a1a3b679SAndreas Boehler $eventStr = $vcal->serialize(); 871a1a3b679SAndreas Boehler 872cb71a62aSAndreas Boehler // Actually write to the database 873a1a3b679SAndreas Boehler $query = "UPDATE calendarobjects SET calendardata=".$this->sqlite->quote_string($eventStr). 874a1a3b679SAndreas Boehler ", lastmodified=".$this->sqlite->quote_string($now->getTimestamp()). 875a1a3b679SAndreas Boehler ", firstoccurence=".$this->sqlite->quote_string($dtStart->getTimestamp()). 876a1a3b679SAndreas Boehler ", lastoccurence=".$this->sqlite->quote_string($dtEnd->getTimestamp()). 877a1a3b679SAndreas Boehler ", size=".strlen($eventStr). 878a1a3b679SAndreas Boehler ", etag=".$this->sqlite->quote_string(md5($eventStr)). 87955a741c0SAndreas Boehler " WHERE uid=".$this->sqlite->quote_string($uid); 880a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 88155a741c0SAndreas Boehler if($res !== false) 88255a741c0SAndreas Boehler { 88355a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'modified'); 884a1a3b679SAndreas Boehler return true; 885a1a3b679SAndreas Boehler } 88655a741c0SAndreas Boehler return false; 88755a741c0SAndreas Boehler } 888a1a3b679SAndreas Boehler 889cb71a62aSAndreas Boehler /** 890cb71a62aSAndreas Boehler * Delete a calendar entry for a given page. Actually, the event is removed 891cb71a62aSAndreas Boehler * based on the entry's UID, so that page ID is no used. 892cb71a62aSAndreas Boehler * 893cb71a62aSAndreas Boehler * @param string $id The page's ID (unused) 894cb71a62aSAndreas Boehler * @param array $params The parameter array to work with 895cb71a62aSAndreas Boehler * 896cb71a62aSAndreas Boehler * @return boolean True 897cb71a62aSAndreas Boehler */ 898a1a3b679SAndreas Boehler public function deleteCalendarEntryForPage($id, $params) 899a1a3b679SAndreas Boehler { 900a1a3b679SAndreas Boehler $uid = $params['uid']; 90155a741c0SAndreas Boehler $event = $this->getEventWithUid($uid); 9022c14b82bSAndreas Boehler $calid = $event['calendarid']; 90355a741c0SAndreas Boehler $uri = $event['uri']; 904a1a3b679SAndreas Boehler $query = "DELETE FROM calendarobjects WHERE uid=".$this->sqlite->quote_string($uid); 905a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 90655a741c0SAndreas Boehler if($res !== false) 90755a741c0SAndreas Boehler { 90855a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'deleted'); 90955a741c0SAndreas Boehler } 910a1a3b679SAndreas Boehler return true; 911a1a3b679SAndreas Boehler } 912a1a3b679SAndreas Boehler 913cb71a62aSAndreas Boehler /** 914cb71a62aSAndreas Boehler * Retrieve the current sync token for a calendar 915cb71a62aSAndreas Boehler * 916cb71a62aSAndreas Boehler * @param string $calid The calendar id 917cb71a62aSAndreas Boehler * 918cb71a62aSAndreas Boehler * @return mixed The synctoken or false 919cb71a62aSAndreas Boehler */ 92055a741c0SAndreas Boehler public function getSyncTokenForCalendar($calid) 92155a741c0SAndreas Boehler { 922b269830cSAndreas Boehler $row = $this->getCalendarSettings($calid); 92355a741c0SAndreas Boehler if(isset($row['synctoken'])) 92455a741c0SAndreas Boehler return $row['synctoken']; 92555a741c0SAndreas Boehler return false; 92655a741c0SAndreas Boehler } 92755a741c0SAndreas Boehler 928cb71a62aSAndreas Boehler /** 929cb71a62aSAndreas Boehler * Helper function to convert the operation name to 930cb71a62aSAndreas Boehler * an operation code as stored in the database 931cb71a62aSAndreas Boehler * 932cb71a62aSAndreas Boehler * @param string $operationName The operation name 933cb71a62aSAndreas Boehler * 934cb71a62aSAndreas Boehler * @return mixed The operation code or false 935cb71a62aSAndreas Boehler */ 93655a741c0SAndreas Boehler public function operationNameToOperation($operationName) 93755a741c0SAndreas Boehler { 93855a741c0SAndreas Boehler switch($operationName) 93955a741c0SAndreas Boehler { 94055a741c0SAndreas Boehler case 'added': 94155a741c0SAndreas Boehler return 1; 94255a741c0SAndreas Boehler break; 94355a741c0SAndreas Boehler case 'modified': 94455a741c0SAndreas Boehler return 2; 94555a741c0SAndreas Boehler break; 94655a741c0SAndreas Boehler case 'deleted': 94755a741c0SAndreas Boehler return 3; 94855a741c0SAndreas Boehler break; 94955a741c0SAndreas Boehler } 95055a741c0SAndreas Boehler return false; 95155a741c0SAndreas Boehler } 95255a741c0SAndreas Boehler 953cb71a62aSAndreas Boehler /** 954cb71a62aSAndreas Boehler * Update the sync token log based on the calendar id and the 955cb71a62aSAndreas Boehler * operation that was performed. 956cb71a62aSAndreas Boehler * 957cb71a62aSAndreas Boehler * @param string $calid The calendar ID that was modified 958cb71a62aSAndreas Boehler * @param string $uri The calendar URI that was modified 959cb71a62aSAndreas Boehler * @param string $operation The operation that was performed 960cb71a62aSAndreas Boehler * 961cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 962cb71a62aSAndreas Boehler */ 96355a741c0SAndreas Boehler private function updateSyncTokenLog($calid, $uri, $operation) 96455a741c0SAndreas Boehler { 96555a741c0SAndreas Boehler $currentToken = $this->getSyncTokenForCalendar($calid); 96655a741c0SAndreas Boehler $operationCode = $this->operationNameToOperation($operation); 96755a741c0SAndreas Boehler if(($operationCode === false) || ($currentToken === false)) 96855a741c0SAndreas Boehler return false; 96955a741c0SAndreas Boehler $values = array($uri, 97055a741c0SAndreas Boehler $currentToken, 97155a741c0SAndreas Boehler $calid, 97255a741c0SAndreas Boehler $operationCode 97355a741c0SAndreas Boehler ); 97455a741c0SAndreas Boehler $query = "INSERT INTO calendarchanges (uri, synctoken, calendarid, operation) VALUES(". 97555a741c0SAndreas Boehler $this->sqlite->quote_and_join($values, ',').")"; 97655a741c0SAndreas Boehler $res = $this->sqlite->query($query); 97755a741c0SAndreas Boehler if($res === false) 97855a741c0SAndreas Boehler return false; 97955a741c0SAndreas Boehler $currentToken++; 98055a741c0SAndreas Boehler $query = "UPDATE calendars SET synctoken=".$this->sqlite->quote_string($currentToken)." WHERE id=". 98155a741c0SAndreas Boehler $this->sqlite->quote_string($calid); 98255a741c0SAndreas Boehler $res = $this->sqlite->query($query); 98355a741c0SAndreas Boehler return ($res !== false); 98455a741c0SAndreas Boehler } 98555a741c0SAndreas Boehler 986cb71a62aSAndreas Boehler /** 987cb71a62aSAndreas Boehler * Return the sync URL for a given Page, i.e. a calendar 988cb71a62aSAndreas Boehler * 989cb71a62aSAndreas Boehler * @param string $id The page's ID 990cb71a62aSAndreas Boehler * @param string $user (optional) The user's ID 991cb71a62aSAndreas Boehler * 992cb71a62aSAndreas Boehler * @return mixed The sync url or false 993cb71a62aSAndreas Boehler */ 994b269830cSAndreas Boehler public function getSyncUrlForPage($id, $user = null) 995b269830cSAndreas Boehler { 99634a47953SAndreas Boehler if(is_null($userid)) 99734a47953SAndreas Boehler { 99834a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 99934a47953SAndreas Boehler { 100034a47953SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 100134a47953SAndreas Boehler } 100234a47953SAndreas Boehler else 100334a47953SAndreas Boehler { 100434a47953SAndreas Boehler return false; 100534a47953SAndreas Boehler } 100634a47953SAndreas Boehler } 1007b269830cSAndreas Boehler 1008b269830cSAndreas Boehler $calid = $this->getCalendarIdForPage($id); 1009b269830cSAndreas Boehler if($calid === false) 1010b269830cSAndreas Boehler return false; 1011b269830cSAndreas Boehler 1012b269830cSAndreas Boehler $calsettings = $this->getCalendarSettings($calid); 1013b269830cSAndreas Boehler if(!isset($calsettings['uri'])) 1014b269830cSAndreas Boehler return false; 1015b269830cSAndreas Boehler 1016b269830cSAndreas Boehler $syncurl = DOKU_URL.'lib/plugins/davcal/calendarserver.php/calendars/'.$user.'/'.$calsettings['uri']; 1017b269830cSAndreas Boehler return $syncurl; 1018b269830cSAndreas Boehler } 1019b269830cSAndreas Boehler 1020cb71a62aSAndreas Boehler /** 1021cb71a62aSAndreas Boehler * Return the private calendar's URL for a given page 1022cb71a62aSAndreas Boehler * 1023cb71a62aSAndreas Boehler * @param string $id the page ID 1024cb71a62aSAndreas Boehler * 1025cb71a62aSAndreas Boehler * @return mixed The private URL or false 1026cb71a62aSAndreas Boehler */ 1027f69bb449SAndreas Boehler public function getPrivateURLForPage($id) 1028f69bb449SAndreas Boehler { 1029f69bb449SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 1030f69bb449SAndreas Boehler if($calid === false) 1031f69bb449SAndreas Boehler return false; 1032f69bb449SAndreas Boehler 1033f69bb449SAndreas Boehler return $this->getPrivateURLForCalendar($calid); 1034f69bb449SAndreas Boehler } 1035f69bb449SAndreas Boehler 1036cb71a62aSAndreas Boehler /** 1037cb71a62aSAndreas Boehler * Return the private calendar's URL for a given calendar ID 1038cb71a62aSAndreas Boehler * 1039cb71a62aSAndreas Boehler * @param string $calid The calendar's ID 1040cb71a62aSAndreas Boehler * 1041cb71a62aSAndreas Boehler * @return mixed The private URL or false 1042cb71a62aSAndreas Boehler */ 1043f69bb449SAndreas Boehler public function getPrivateURLForCalendar($calid) 1044f69bb449SAndreas Boehler { 1045185e2535SAndreas Boehler if(isset($this->cachedValues['privateurl'][$calid])) 1046185e2535SAndreas Boehler return $this->cachedValues['privateurl'][$calid]; 1047f69bb449SAndreas Boehler $query = "SELECT url FROM calendartoprivateurlmapping WHERE calid=".$this->sqlite->quote_string($calid); 1048f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 1049f69bb449SAndreas Boehler $row = $this->sqlite->res2row($res); 1050f69bb449SAndreas Boehler if(!isset($row['url'])) 1051f69bb449SAndreas Boehler { 1052f69bb449SAndreas Boehler $url = uniqid("dokuwiki-").".ics"; 1053f69bb449SAndreas Boehler $values = array( 1054f69bb449SAndreas Boehler $url, 1055f69bb449SAndreas Boehler $calid 1056f69bb449SAndreas Boehler ); 1057f69bb449SAndreas Boehler $query = "INSERT INTO calendartoprivateurlmapping (url, calid) VALUES(". 1058f69bb449SAndreas Boehler $this->sqlite->quote_and_join($values, ", ").")"; 1059f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 1060f69bb449SAndreas Boehler if($res === false) 1061f69bb449SAndreas Boehler return false; 1062f69bb449SAndreas Boehler } 1063f69bb449SAndreas Boehler else 1064f69bb449SAndreas Boehler { 1065f69bb449SAndreas Boehler $url = $row['url']; 1066f69bb449SAndreas Boehler } 1067185e2535SAndreas Boehler 1068185e2535SAndreas Boehler $url = DOKU_URL.'lib/plugins/davcal/ics.php/'.$url; 1069185e2535SAndreas Boehler $this->cachedValues['privateurl'][$calid] = $url; 1070185e2535SAndreas Boehler return $url; 1071f69bb449SAndreas Boehler } 1072f69bb449SAndreas Boehler 1073cb71a62aSAndreas Boehler /** 1074cb71a62aSAndreas Boehler * Retrieve the calendar ID for a given private calendar URL 1075cb71a62aSAndreas Boehler * 1076cb71a62aSAndreas Boehler * @param string $url The private URL 1077cb71a62aSAndreas Boehler * 1078cb71a62aSAndreas Boehler * @return mixed The calendar ID or false 1079cb71a62aSAndreas Boehler */ 1080f69bb449SAndreas Boehler public function getCalendarForPrivateURL($url) 1081f69bb449SAndreas Boehler { 1082f69bb449SAndreas Boehler $query = "SELECT calid FROM calendartoprivateurlmapping WHERE url=".$this->sqlite->quote_string($url); 1083f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 1084f69bb449SAndreas Boehler $row = $this->sqlite->res2row($res); 1085f69bb449SAndreas Boehler if(!isset($row['calid'])) 1086f69bb449SAndreas Boehler return false; 1087f69bb449SAndreas Boehler return $row['calid']; 1088f69bb449SAndreas Boehler } 1089f69bb449SAndreas Boehler 1090cb71a62aSAndreas Boehler /** 1091cb71a62aSAndreas Boehler * Return a given calendar as ICS feed, i.e. all events in one ICS file. 1092cb71a62aSAndreas Boehler * 1093cb71a62aSAndreas Boehler * @param string $caldi The calendar ID to retrieve 1094cb71a62aSAndreas Boehler * 1095cb71a62aSAndreas Boehler * @return mixed The calendar events as string or false 1096cb71a62aSAndreas Boehler */ 1097f69bb449SAndreas Boehler public function getCalendarAsICSFeed($calid) 1098f69bb449SAndreas Boehler { 1099f69bb449SAndreas Boehler $calSettings = $this->getCalendarSettings($calid); 1100f69bb449SAndreas Boehler if($calSettings === false) 1101f69bb449SAndreas Boehler return false; 1102f69bb449SAndreas Boehler $events = $this->getAllCalendarEvents($calid); 1103f69bb449SAndreas Boehler if($events === false) 1104f69bb449SAndreas Boehler return false; 1105f69bb449SAndreas Boehler 1106f69bb449SAndreas Boehler $out = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//DAVCal//DAVCal for DokuWiki//EN\nCALSCALE:GREGORIAN\nX-WR-CALNAME:"; 1107f69bb449SAndreas Boehler $out .= $calSettings['displayname']."\n"; 1108f69bb449SAndreas Boehler foreach($events as $event) 1109f69bb449SAndreas Boehler { 1110f69bb449SAndreas Boehler $out .= rtrim($event['calendardata']); 1111f69bb449SAndreas Boehler $out .= "\n"; 1112f69bb449SAndreas Boehler } 1113f69bb449SAndreas Boehler $out .= "END:VCALENDAR\n"; 1114f69bb449SAndreas Boehler return $out; 1115f69bb449SAndreas Boehler } 1116f69bb449SAndreas Boehler 11177c7c6b0bSAndreas Boehler /** 11187c7c6b0bSAndreas Boehler * Retrieve a configuration option for the plugin 11197c7c6b0bSAndreas Boehler * 11207c7c6b0bSAndreas Boehler * @param string $key The key to query 112121d04f73SAndreas Boehler * @return mixed The option set, null if not found 11227c7c6b0bSAndreas Boehler */ 11237c7c6b0bSAndreas Boehler public function getConfig($key) 11247c7c6b0bSAndreas Boehler { 11257c7c6b0bSAndreas Boehler return $this->getConf($key); 11267c7c6b0bSAndreas Boehler } 11277c7c6b0bSAndreas Boehler 1128a1a3b679SAndreas Boehler} 1129