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; 14*185e2535SAndreas 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'); 21a1a3b679SAndreas Boehler if(!$this->sqlite) 22a1a3b679SAndreas Boehler { 23a1a3b679SAndreas Boehler msg('This plugin requires the sqlite plugin. Please install it.'); 24a1a3b679SAndreas Boehler return; 25a1a3b679SAndreas Boehler } 26a1a3b679SAndreas Boehler 27a1a3b679SAndreas Boehler if(!$this->sqlite->init('davcal', DOKU_PLUGIN.'davcal/db/')) 28a1a3b679SAndreas Boehler { 29a1a3b679SAndreas Boehler return; 30a1a3b679SAndreas Boehler } 31a1a3b679SAndreas Boehler } 32a1a3b679SAndreas Boehler 33cb71a62aSAndreas Boehler /** 34*185e2535SAndreas Boehler * Retrieve meta data for a given page 35*185e2535SAndreas Boehler * 36*185e2535SAndreas Boehler * @param string $id optional The page ID 37*185e2535SAndreas Boehler * @return array The metadata 38*185e2535SAndreas Boehler */ 39*185e2535SAndreas Boehler private function getMeta($id = null) { 40*185e2535SAndreas Boehler global $ID; 41*185e2535SAndreas Boehler global $INFO; 42*185e2535SAndreas Boehler 43*185e2535SAndreas Boehler if ($id === null) $id = $ID; 44*185e2535SAndreas Boehler 45*185e2535SAndreas Boehler if($ID === $id && $INFO['meta']) { 46*185e2535SAndreas Boehler $meta = $INFO['meta']; 47*185e2535SAndreas Boehler } else { 48*185e2535SAndreas Boehler $meta = p_get_metadata($id); 49*185e2535SAndreas Boehler } 50*185e2535SAndreas Boehler 51*185e2535SAndreas Boehler return $meta; 52*185e2535SAndreas Boehler } 53*185e2535SAndreas Boehler 54*185e2535SAndreas Boehler /** 55*185e2535SAndreas Boehler * Retrieve the meta data for a given page 56*185e2535SAndreas Boehler * 57*185e2535SAndreas Boehler * @param string $id optional The page ID 58*185e2535SAndreas Boehler * @return array with meta data 59*185e2535SAndreas Boehler */ 60*185e2535SAndreas Boehler public function getCalendarMetaForPage($id = null) 61*185e2535SAndreas Boehler { 62*185e2535SAndreas Boehler if(is_null($id)) 63*185e2535SAndreas Boehler { 64*185e2535SAndreas Boehler global $ID; 65*185e2535SAndreas Boehler $id = $ID; 66*185e2535SAndreas Boehler } 67*185e2535SAndreas Boehler 68*185e2535SAndreas Boehler $meta = $this->getMeta($id); 69*185e2535SAndreas Boehler if(isset($meta['plugin_davcal'])) 70*185e2535SAndreas Boehler return $meta['plugin_davcal']; 71*185e2535SAndreas Boehler else 72*185e2535SAndreas Boehler return array(); 73*185e2535SAndreas Boehler } 74*185e2535SAndreas Boehler 75*185e2535SAndreas Boehler /** 76*185e2535SAndreas Boehler * Get all calendar pages used by a given page 77*185e2535SAndreas Boehler * based on the stored metadata 78*185e2535SAndreas Boehler * 79*185e2535SAndreas Boehler * @param string $id optional The page id 80*185e2535SAndreas Boehler * @return mixed The pages as array or false 81*185e2535SAndreas Boehler */ 82*185e2535SAndreas Boehler public function getCalendarPagesByMeta($id = null) 83*185e2535SAndreas Boehler { 84*185e2535SAndreas Boehler if(is_null($id)) 85*185e2535SAndreas Boehler { 86*185e2535SAndreas Boehler global $ID; 87*185e2535SAndreas Boehler $id = $ID; 88*185e2535SAndreas Boehler } 89*185e2535SAndreas Boehler 90*185e2535SAndreas Boehler $meta = $this->getCalendarMetaForPage($id); 91*185e2535SAndreas Boehler if(isset($meta['id'])) 92*185e2535SAndreas Boehler { 93*185e2535SAndreas Boehler return array_keys($meta['id']); 94*185e2535SAndreas Boehler } 95*185e2535SAndreas Boehler return false; 96*185e2535SAndreas Boehler } 97*185e2535SAndreas Boehler 98*185e2535SAndreas Boehler /** 99*185e2535SAndreas Boehler * Get a list of calendar names/pages/ids/colors 100*185e2535SAndreas Boehler * for an array of page ids 101*185e2535SAndreas Boehler * 102*185e2535SAndreas Boehler * @param array $calendarPages The calendar pages to retrieve 103*185e2535SAndreas Boehler * @return array The list 104*185e2535SAndreas Boehler */ 105*185e2535SAndreas Boehler public function getCalendarMapForIDs($calendarPages) 106*185e2535SAndreas Boehler { 107*185e2535SAndreas Boehler $data = array(); 108*185e2535SAndreas Boehler foreach($calendarPages as $page) 109*185e2535SAndreas Boehler { 110*185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($page); 111*185e2535SAndreas Boehler if($calid !== false) 112*185e2535SAndreas Boehler { 113*185e2535SAndreas Boehler $settings = $this->getCalendarSettings($calid); 114*185e2535SAndreas Boehler $name = $settings['displayname']; 115*185e2535SAndreas Boehler $color = $settings['calendarcolor']; 116*185e2535SAndreas Boehler $data[] = array('name' => $name, 'page' => $page, 'calid' => $calid, 117*185e2535SAndreas Boehler 'color' => $color); 118*185e2535SAndreas Boehler } 119*185e2535SAndreas Boehler } 120*185e2535SAndreas Boehler return $data; 121*185e2535SAndreas Boehler } 122*185e2535SAndreas Boehler 123*185e2535SAndreas Boehler /** 124*185e2535SAndreas Boehler * Get the saved calendar color for a given page. 125*185e2535SAndreas Boehler * 126*185e2535SAndreas Boehler * @param string $id optional The page ID 127*185e2535SAndreas Boehler * @return mixed The color on success, otherwise false 128*185e2535SAndreas Boehler */ 129*185e2535SAndreas Boehler public function getCalendarColorForPage($id = null) 130*185e2535SAndreas Boehler { 131*185e2535SAndreas Boehler if(is_null($id)) 132*185e2535SAndreas Boehler { 133*185e2535SAndreas Boehler global $ID; 134*185e2535SAndreas Boehler $id = $ID; 135*185e2535SAndreas Boehler } 136*185e2535SAndreas Boehler 137*185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 138*185e2535SAndreas Boehler if($calid === false) 139*185e2535SAndreas Boehler return false; 140*185e2535SAndreas Boehler 141*185e2535SAndreas Boehler return $this->getCalendarColorForCalendar($calid); 142*185e2535SAndreas Boehler } 143*185e2535SAndreas Boehler 144*185e2535SAndreas Boehler /** 145*185e2535SAndreas Boehler * Get the saved calendar color for a given calendar ID. 146*185e2535SAndreas Boehler * 147*185e2535SAndreas Boehler * @param string $id optional The calendar ID 148*185e2535SAndreas Boehler * @return mixed The color on success, otherwise false 149*185e2535SAndreas Boehler */ 150*185e2535SAndreas Boehler public function getCalendarColorForCalendar($calid) 151*185e2535SAndreas Boehler { 152*185e2535SAndreas Boehler if(isset($this->cachedValues['calendarcolor'][$calid])) 153*185e2535SAndreas Boehler return $this->cachedValues['calendarcolor'][$calid]; 154*185e2535SAndreas Boehler 155*185e2535SAndreas Boehler $row = $this->getCalendarSettings($calid); 156*185e2535SAndreas Boehler 157*185e2535SAndreas Boehler if(!isset($row['calendarcolor'])) 158*185e2535SAndreas Boehler return false; 159*185e2535SAndreas Boehler 160*185e2535SAndreas Boehler $color = $row['calendarcolor']; 161*185e2535SAndreas Boehler $this->cachedValues['calendarcolor'][$calid] = $color; 162*185e2535SAndreas Boehler return $color; 163*185e2535SAndreas Boehler } 164*185e2535SAndreas Boehler 165*185e2535SAndreas Boehler /** 166*185e2535SAndreas Boehler * Set the calendar color for a given page. 167*185e2535SAndreas Boehler * 168*185e2535SAndreas Boehler * @param string $color The color definition 169*185e2535SAndreas Boehler * @param string $id optional The page ID 170*185e2535SAndreas Boehler * @return boolean True on success, otherwise false 171*185e2535SAndreas Boehler */ 172*185e2535SAndreas Boehler public function setCalendarColorForPage($color, $id = null) 173*185e2535SAndreas Boehler { 174*185e2535SAndreas Boehler if(is_null($id)) 175*185e2535SAndreas Boehler { 176*185e2535SAndreas Boehler global $ID; 177*185e2535SAndreas Boehler $id = $ID; 178*185e2535SAndreas Boehler } 179*185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 180*185e2535SAndreas Boehler if($calid === false) 181*185e2535SAndreas Boehler return false; 182*185e2535SAndreas Boehler 183*185e2535SAndreas Boehler $query = "UPDATE calendars SET calendarcolor=".$this->sqlite->quote_string($color). 184*185e2535SAndreas Boehler " WHERE id=".$this->sqlite->quote_string($calid); 185*185e2535SAndreas Boehler $res = $this->sqlite->query($query); 186*185e2535SAndreas Boehler if($res !== false) 187*185e2535SAndreas Boehler { 188*185e2535SAndreas Boehler $this->cachedValues['calendarcolor'][$calid] = $color; 189*185e2535SAndreas Boehler return true; 190*185e2535SAndreas Boehler } 191*185e2535SAndreas Boehler return false; 192*185e2535SAndreas Boehler } 193*185e2535SAndreas Boehler 194*185e2535SAndreas Boehler /** 195cb71a62aSAndreas Boehler * Set the calendar name and description for a given page with a given 196cb71a62aSAndreas Boehler * page id. 197cb71a62aSAndreas Boehler * If the calendar doesn't exist, the calendar is created! 198cb71a62aSAndreas Boehler * 199cb71a62aSAndreas Boehler * @param string $name The name of the new calendar 200cb71a62aSAndreas Boehler * @param string $description The description of the new calendar 201cb71a62aSAndreas Boehler * @param string $id (optional) The ID of the page 202cb71a62aSAndreas Boehler * @param string $userid The userid of the creating user 203cb71a62aSAndreas Boehler * 204cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false. 205cb71a62aSAndreas Boehler */ 206a1a3b679SAndreas Boehler public function setCalendarNameForPage($name, $description, $id = null, $userid = null) 207a1a3b679SAndreas Boehler { 208a1a3b679SAndreas Boehler if(is_null($id)) 209a1a3b679SAndreas Boehler { 210a1a3b679SAndreas Boehler global $ID; 211a1a3b679SAndreas Boehler $id = $ID; 212a1a3b679SAndreas Boehler } 213a1a3b679SAndreas Boehler if(is_null($userid)) 214a1a3b679SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 215a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 216a1a3b679SAndreas Boehler if($calid === false) 217a1a3b679SAndreas Boehler return $this->createCalendarForPage($name, $description, $id, $userid); 218a1a3b679SAndreas Boehler 219b269830cSAndreas Boehler $query = "UPDATE calendars SET displayname=".$this->sqlite->quote_string($name).", ". 220b269830cSAndreas Boehler "description=".$this->sqlite->quote_string($description)." WHERE ". 221b269830cSAndreas Boehler "id=".$this->sqlite->quote_string($calid); 222b269830cSAndreas Boehler $res = $this->sqlite->query($query); 223b269830cSAndreas Boehler if($res !== false) 224b269830cSAndreas Boehler return true; 225b269830cSAndreas Boehler return false; 226a1a3b679SAndreas Boehler } 227a1a3b679SAndreas Boehler 228cb71a62aSAndreas Boehler /** 229cb71a62aSAndreas Boehler * Save the personal settings to the SQLite database 'calendarsettings'. 230cb71a62aSAndreas Boehler * 231cb71a62aSAndreas Boehler * @param array $settings The settings array to store 232cb71a62aSAndreas Boehler * @param string $userid (optional) The userid to store 233cb71a62aSAndreas Boehler * 234cb71a62aSAndreas Boehler * @param boolean True on success, otherwise false 235cb71a62aSAndreas Boehler */ 236a495d34cSAndreas Boehler public function savePersonalSettings($settings, $userid = null) 237a495d34cSAndreas Boehler { 238a495d34cSAndreas Boehler if(is_null($userid)) 239a495d34cSAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 240a495d34cSAndreas Boehler $this->sqlite->query("BEGIN TRANSACTION"); 241a495d34cSAndreas Boehler 242bd883736SAndreas Boehler $query = "DELETE FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid); 243bd883736SAndreas Boehler $this->sqlite->query($query); 244bd883736SAndreas Boehler 245a495d34cSAndreas Boehler foreach($settings as $key => $value) 246a495d34cSAndreas Boehler { 247bd883736SAndreas Boehler $query = "INSERT INTO calendarsettings (userid, key, value) VALUES (". 248a495d34cSAndreas Boehler $this->sqlite->quote_string($userid).", ". 249a495d34cSAndreas Boehler $this->sqlite->quote_string($key).", ". 250a495d34cSAndreas Boehler $this->sqlite->quote_string($value).")"; 251a495d34cSAndreas Boehler $res = $this->sqlite->query($query); 252a495d34cSAndreas Boehler if($res === false) 253a495d34cSAndreas Boehler return false; 254a495d34cSAndreas Boehler } 255a495d34cSAndreas Boehler $this->sqlite->query("COMMIT TRANSACTION"); 256*185e2535SAndreas Boehler $this->cachedValues['settings'][$userid] = $settings; 257a495d34cSAndreas Boehler return true; 258a495d34cSAndreas Boehler } 259a495d34cSAndreas Boehler 260cb71a62aSAndreas Boehler /** 261cb71a62aSAndreas Boehler * Retrieve the settings array for a given user id. 262cb71a62aSAndreas Boehler * Some sane defaults are returned, currently: 263cb71a62aSAndreas Boehler * 264cb71a62aSAndreas Boehler * timezone => local 265cb71a62aSAndreas Boehler * weeknumbers => 0 266cb71a62aSAndreas Boehler * workweek => 0 267cb71a62aSAndreas Boehler * 268cb71a62aSAndreas Boehler * @param string $userid (optional) The user id to retrieve 269cb71a62aSAndreas Boehler * 270cb71a62aSAndreas Boehler * @return array The settings array 271cb71a62aSAndreas Boehler */ 272a495d34cSAndreas Boehler public function getPersonalSettings($userid = null) 273a495d34cSAndreas Boehler { 274a495d34cSAndreas Boehler if(is_null($userid)) 275a495d34cSAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 276*185e2535SAndreas Boehler 277*185e2535SAndreas Boehler if(isset($this->cachedValues['settings'][$userid])) 278*185e2535SAndreas Boehler return $this->cachedValues['settings'][$userid]; 279bd883736SAndreas Boehler // Some sane default settings 280bd883736SAndreas Boehler $settings = array( 281bd883736SAndreas Boehler 'timezone' => 'local', 282bd883736SAndreas Boehler 'weeknumbers' => '0', 283*185e2535SAndreas Boehler 'workweek' => '0', 284*185e2535SAndreas Boehler 'monday' => '0' 285bd883736SAndreas Boehler ); 286a495d34cSAndreas Boehler $query = "SELECT key, value FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid); 287a495d34cSAndreas Boehler $res = $this->sqlite->query($query); 288a495d34cSAndreas Boehler $arr = $this->sqlite->res2arr($res); 289a495d34cSAndreas Boehler foreach($arr as $row) 290a495d34cSAndreas Boehler { 291a495d34cSAndreas Boehler $settings[$row['key']] = $row['value']; 292a495d34cSAndreas Boehler } 293*185e2535SAndreas Boehler $this->cachedValues['settings'][$userid] = $settings; 294a495d34cSAndreas Boehler return $settings; 295a495d34cSAndreas Boehler } 296a495d34cSAndreas Boehler 297cb71a62aSAndreas Boehler /** 298cb71a62aSAndreas Boehler * Retrieve the calendar ID based on a page ID from the SQLite table 299cb71a62aSAndreas Boehler * 'pagetocalendarmapping'. 300cb71a62aSAndreas Boehler * 301cb71a62aSAndreas Boehler * @param string $id (optional) The page ID to retrieve the corresponding calendar 302cb71a62aSAndreas Boehler * 303cb71a62aSAndreas Boehler * @return mixed the ID on success, otherwise false 304cb71a62aSAndreas Boehler */ 305a1a3b679SAndreas Boehler public function getCalendarIdForPage($id = null) 306a1a3b679SAndreas Boehler { 307a1a3b679SAndreas Boehler if(is_null($id)) 308a1a3b679SAndreas Boehler { 309a1a3b679SAndreas Boehler global $ID; 310a1a3b679SAndreas Boehler $id = $ID; 311a1a3b679SAndreas Boehler } 312a1a3b679SAndreas Boehler 313*185e2535SAndreas Boehler if(isset($this->cachedValues['calid'][$id])) 314*185e2535SAndreas Boehler return $this->cachedValues['calid'][$id]; 315*185e2535SAndreas Boehler 316a1a3b679SAndreas Boehler $query = "SELECT calid FROM pagetocalendarmapping WHERE page=".$this->sqlite->quote_string($id); 317a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 318a1a3b679SAndreas Boehler $row = $this->sqlite->res2row($res); 319a1a3b679SAndreas Boehler if(isset($row['calid'])) 320*185e2535SAndreas Boehler { 321*185e2535SAndreas Boehler $calid = $row['calid']; 322*185e2535SAndreas Boehler $this->cachedValues['calid'] = $calid; 323*185e2535SAndreas Boehler return $calid; 324*185e2535SAndreas Boehler } 325a1a3b679SAndreas Boehler return false; 326a1a3b679SAndreas Boehler } 327a1a3b679SAndreas Boehler 328cb71a62aSAndreas Boehler /** 329cb71a62aSAndreas Boehler * Retrieve the complete calendar id to page mapping. 330cb71a62aSAndreas Boehler * This is necessary to be able to retrieve a list of 331cb71a62aSAndreas Boehler * calendars for a given user and check the access rights. 332cb71a62aSAndreas Boehler * 333cb71a62aSAndreas Boehler * @return array The mapping array 334cb71a62aSAndreas Boehler */ 335a1a3b679SAndreas Boehler public function getCalendarIdToPageMapping() 336a1a3b679SAndreas Boehler { 337a1a3b679SAndreas Boehler $query = "SELECT calid, page FROM pagetocalendarmapping"; 338a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 339a1a3b679SAndreas Boehler $arr = $this->sqlite->res2arr($res); 340a1a3b679SAndreas Boehler return $arr; 341a1a3b679SAndreas Boehler } 342a1a3b679SAndreas Boehler 343cb71a62aSAndreas Boehler /** 344cb71a62aSAndreas Boehler * Retrieve all calendar IDs a given user has access to. 345cb71a62aSAndreas Boehler * The user is specified by the principalUri, so the 346cb71a62aSAndreas Boehler * user name is actually split from the URI component. 347cb71a62aSAndreas Boehler * 348cb71a62aSAndreas Boehler * Access rights are checked against DokuWiki's ACL 349cb71a62aSAndreas Boehler * and applied accordingly. 350cb71a62aSAndreas Boehler * 351cb71a62aSAndreas Boehler * @param string $principalUri The principal URI to work on 352cb71a62aSAndreas Boehler * 353cb71a62aSAndreas Boehler * @return array An associative array of calendar IDs 354cb71a62aSAndreas Boehler */ 355a1a3b679SAndreas Boehler public function getCalendarIdsForUser($principalUri) 356a1a3b679SAndreas Boehler { 357a1a3b679SAndreas Boehler $user = explode('/', $principalUri); 358a1a3b679SAndreas Boehler $user = end($user); 359a1a3b679SAndreas Boehler $mapping = $this->getCalendarIdToPageMapping(); 360a1a3b679SAndreas Boehler $calids = array(); 361a1a3b679SAndreas Boehler foreach($mapping as $row) 362a1a3b679SAndreas Boehler { 363a1a3b679SAndreas Boehler $id = $row['calid']; 364a1a3b679SAndreas Boehler $page = $row['page']; 365a1a3b679SAndreas Boehler $acl = auth_quickaclcheck($page); 366a1a3b679SAndreas Boehler if($acl >= AUTH_READ) 367a1a3b679SAndreas Boehler { 368a1a3b679SAndreas Boehler $write = $acl > AUTH_READ; 369a1a3b679SAndreas Boehler $calids[$id] = array('readonly' => !$write); 370a1a3b679SAndreas Boehler } 371a1a3b679SAndreas Boehler } 372a1a3b679SAndreas Boehler return $calids; 373a1a3b679SAndreas Boehler } 374a1a3b679SAndreas Boehler 375cb71a62aSAndreas Boehler /** 376cb71a62aSAndreas Boehler * Create a new calendar for a given page ID and set name and description 377cb71a62aSAndreas Boehler * accordingly. Also update the pagetocalendarmapping table on success. 378cb71a62aSAndreas Boehler * 379cb71a62aSAndreas Boehler * @param string $name The calendar's name 380cb71a62aSAndreas Boehler * @param string $description The calendar's description 381cb71a62aSAndreas Boehler * @param string $id (optional) The page ID to work on 382cb71a62aSAndreas Boehler * @param string $userid (optional) The user ID that created the calendar 383cb71a62aSAndreas Boehler * 384cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 385cb71a62aSAndreas Boehler */ 386a1a3b679SAndreas Boehler public function createCalendarForPage($name, $description, $id = null, $userid = null) 387a1a3b679SAndreas Boehler { 388a1a3b679SAndreas Boehler if(is_null($id)) 389a1a3b679SAndreas Boehler { 390a1a3b679SAndreas Boehler global $ID; 391a1a3b679SAndreas Boehler $id = $ID; 392a1a3b679SAndreas Boehler } 393a1a3b679SAndreas Boehler if(is_null($userid)) 394a1a3b679SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 395a1a3b679SAndreas Boehler $values = array('principals/'.$userid, 396a1a3b679SAndreas Boehler $name, 397a1a3b679SAndreas Boehler str_replace(array('/', ' ', ':'), '_', $id), 398a1a3b679SAndreas Boehler $description, 399a1a3b679SAndreas Boehler 'VEVENT,VTODO', 40055a741c0SAndreas Boehler 0, 40155a741c0SAndreas Boehler 1); 40255a741c0SAndreas Boehler $query = "INSERT INTO calendars (principaluri, displayname, uri, description, components, transparent, synctoken) VALUES (".$this->sqlite->quote_and_join($values, ',').");"; 403a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 40455a741c0SAndreas Boehler if($res === false) 40555a741c0SAndreas Boehler return false; 406cb71a62aSAndreas Boehler 407cb71a62aSAndreas Boehler // Get the new calendar ID 408a1a3b679SAndreas Boehler $query = "SELECT id FROM calendars WHERE principaluri=".$this->sqlite->quote_string($values[0])." AND ". 409a1a3b679SAndreas Boehler "displayname=".$this->sqlite->quote_string($values[1])." AND ". 410a1a3b679SAndreas Boehler "uri=".$this->sqlite->quote_string($values[2])." AND ". 411a1a3b679SAndreas Boehler "description=".$this->sqlite->quote_string($values[3]); 412a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 413a1a3b679SAndreas Boehler $row = $this->sqlite->res2row($res); 414cb71a62aSAndreas Boehler 415cb71a62aSAndreas Boehler // Update the pagetocalendarmapping table with the new calendar ID 416a1a3b679SAndreas Boehler if(isset($row['id'])) 417a1a3b679SAndreas Boehler { 418a1a3b679SAndreas Boehler $values = array($id, $row['id']); 419a1a3b679SAndreas Boehler $query = "INSERT INTO pagetocalendarmapping (page, calid) VALUES (".$this->sqlite->quote_and_join($values, ',').")"; 420a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 42155a741c0SAndreas Boehler return ($res !== false); 422a1a3b679SAndreas Boehler } 423a1a3b679SAndreas Boehler 424a1a3b679SAndreas Boehler return false; 425a1a3b679SAndreas Boehler } 426a1a3b679SAndreas Boehler 427cb71a62aSAndreas Boehler /** 428cb71a62aSAndreas Boehler * Add a new iCal entry for a given page, i.e. a given calendar. 429cb71a62aSAndreas Boehler * 430cb71a62aSAndreas Boehler * The parameter array needs to contain 431cb71a62aSAndreas Boehler * timezone => The timezone of the entries 432cb71a62aSAndreas Boehler * detectedtz => The timezone as detected by the browser 433cb71a62aSAndreas Boehler * eventfrom => The event's start date 434cb71a62aSAndreas Boehler * eventfromtime => The event's start time 435cb71a62aSAndreas Boehler * eventto => The event's end date 436cb71a62aSAndreas Boehler * eventtotime => The event's end time 437cb71a62aSAndreas Boehler * eventname => The event's name 438cb71a62aSAndreas Boehler * eventdescription => The event's description 439cb71a62aSAndreas Boehler * 440cb71a62aSAndreas Boehler * @param string $id The page ID to work on 441cb71a62aSAndreas Boehler * @param string $user The user who created the calendar 442cb71a62aSAndreas Boehler * @param string $params A parameter array with values to create 443cb71a62aSAndreas Boehler * 444cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 445cb71a62aSAndreas Boehler */ 446a1a3b679SAndreas Boehler public function addCalendarEntryToCalendarForPage($id, $user, $params) 447a1a3b679SAndreas Boehler { 448bd883736SAndreas Boehler $settings = $this->getPersonalSettings($user); 449bd883736SAndreas Boehler if($settings['timezone'] !== '' && $settings['timezone'] !== 'local') 450bd883736SAndreas Boehler $timezone = new \DateTimeZone($settings['timezone']); 451a25c89eaSAndreas Boehler elseif($settings['timezone'] === 'local') 452a25c89eaSAndreas Boehler $timezone = new \DateTimeZone($params['detectedtz']); 453bd883736SAndreas Boehler else 454bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 455cb71a62aSAndreas Boehler 456cb71a62aSAndreas Boehler // Retrieve dates from settings 457b269830cSAndreas Boehler $startDate = explode('-', $params['eventfrom']); 458b269830cSAndreas Boehler $startTime = explode(':', $params['eventfromtime']); 459b269830cSAndreas Boehler $endDate = explode('-', $params['eventto']); 460b269830cSAndreas Boehler $endTime = explode(':', $params['eventtotime']); 461cb71a62aSAndreas Boehler 462cb71a62aSAndreas Boehler // Load SabreDAV 463a1a3b679SAndreas Boehler require_once('vendor/autoload.php'); 464a1a3b679SAndreas Boehler $vcalendar = new \Sabre\VObject\Component\VCalendar(); 465cb71a62aSAndreas Boehler 466cb71a62aSAndreas Boehler // Add VCalendar, UID and Event Name 467a1a3b679SAndreas Boehler $event = $vcalendar->add('VEVENT'); 468b269830cSAndreas Boehler $uuid = \Sabre\VObject\UUIDUtil::getUUID(); 469b269830cSAndreas Boehler $event->add('UID', $uuid); 470a1a3b679SAndreas Boehler $event->summary = $params['eventname']; 471cb71a62aSAndreas Boehler 472cb71a62aSAndreas Boehler // Add a description if requested 4730eebc909SAndreas Boehler $description = $params['eventdescription']; 4740eebc909SAndreas Boehler if($description !== '') 4750eebc909SAndreas Boehler $event->add('DESCRIPTION', $description); 476cb71a62aSAndreas Boehler 477cb71a62aSAndreas Boehler // Create a timestamp for last modified, created and dtstamp values in UTC 478b269830cSAndreas Boehler $dtStamp = new \DateTime(null, new \DateTimeZone('UTC')); 479b269830cSAndreas Boehler $event->add('DTSTAMP', $dtStamp); 480b269830cSAndreas Boehler $event->add('CREATED', $dtStamp); 481b269830cSAndreas Boehler $event->add('LAST-MODIFIED', $dtStamp); 482cb71a62aSAndreas Boehler 483cb71a62aSAndreas Boehler // Adjust the start date, based on the given timezone information 484b269830cSAndreas Boehler $dtStart = new \DateTime(); 485a25c89eaSAndreas Boehler $dtStart->setTimezone($timezone); 486b269830cSAndreas Boehler $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2])); 487cb71a62aSAndreas Boehler 488cb71a62aSAndreas Boehler // Only add the time values if it's not an allday event 489b269830cSAndreas Boehler if($params['allday'] != '1') 490b269830cSAndreas Boehler $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0); 491cb71a62aSAndreas Boehler 492cb71a62aSAndreas Boehler // Adjust the end date, based on the given timezone information 493b269830cSAndreas Boehler $dtEnd = new \DateTime(); 494a25c89eaSAndreas Boehler $dtEnd->setTimezone($timezone); 495b269830cSAndreas Boehler $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2])); 496cb71a62aSAndreas Boehler 497cb71a62aSAndreas Boehler // Only add the time values if it's not an allday event 498b269830cSAndreas Boehler if($params['allday'] != '1') 499b269830cSAndreas Boehler $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0); 500cb71a62aSAndreas Boehler 501b269830cSAndreas Boehler // According to the VCal spec, we need to add a whole day here 502b269830cSAndreas Boehler if($params['allday'] == '1') 503b269830cSAndreas Boehler $dtEnd->add(new \DateInterval('P1D')); 504cb71a62aSAndreas Boehler 505cb71a62aSAndreas Boehler // Really add Start and End events 506b269830cSAndreas Boehler $dtStartEv = $event->add('DTSTART', $dtStart); 507b269830cSAndreas Boehler $dtEndEv = $event->add('DTEND', $dtEnd); 508cb71a62aSAndreas Boehler 509cb71a62aSAndreas Boehler // Adjust the DATE format for allday events 510b269830cSAndreas Boehler if($params['allday'] == '1') 511b269830cSAndreas Boehler { 512b269830cSAndreas Boehler $dtStartEv['VALUE'] = 'DATE'; 513b269830cSAndreas Boehler $dtEndEv['VALUE'] = 'DATE'; 514b269830cSAndreas Boehler } 515cb71a62aSAndreas Boehler 516cb71a62aSAndreas Boehler // Actually add the values to the database 517a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 518a1a3b679SAndreas Boehler $uri = uniqid('dokuwiki-').'.ics'; 519a1a3b679SAndreas Boehler $now = new DateTime(); 520a1a3b679SAndreas Boehler $eventStr = $vcalendar->serialize(); 521a1a3b679SAndreas Boehler 522a1a3b679SAndreas Boehler $values = array($calid, 523a1a3b679SAndreas Boehler $uri, 524a1a3b679SAndreas Boehler $eventStr, 525a1a3b679SAndreas Boehler $now->getTimestamp(), 526a1a3b679SAndreas Boehler 'VEVENT', 527a1a3b679SAndreas Boehler $event->DTSTART->getDateTime()->getTimeStamp(), 528a1a3b679SAndreas Boehler $event->DTEND->getDateTime()->getTimeStamp(), 529a1a3b679SAndreas Boehler strlen($eventStr), 530a1a3b679SAndreas Boehler md5($eventStr), 531cb71a62aSAndreas Boehler $uuid 532a1a3b679SAndreas Boehler ); 533a1a3b679SAndreas Boehler 534a1a3b679SAndreas Boehler $query = "INSERT INTO calendarobjects (calendarid, uri, calendardata, lastmodified, componenttype, firstoccurence, lastoccurence, size, etag, uid) VALUES (".$this->sqlite->quote_and_join($values, ',').")"; 535a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 536cb71a62aSAndreas Boehler 537cb71a62aSAndreas Boehler // If successfully, update the sync token database 53855a741c0SAndreas Boehler if($res !== false) 53955a741c0SAndreas Boehler { 54055a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'added'); 541a1a3b679SAndreas Boehler return true; 542a1a3b679SAndreas Boehler } 54355a741c0SAndreas Boehler return false; 54455a741c0SAndreas Boehler } 545a1a3b679SAndreas Boehler 546cb71a62aSAndreas Boehler /** 547cb71a62aSAndreas Boehler * Retrieve the calendar settings of a given calendar id 548cb71a62aSAndreas Boehler * 549cb71a62aSAndreas Boehler * @param string $calid The calendar ID 550cb71a62aSAndreas Boehler * 551cb71a62aSAndreas Boehler * @return array The calendar settings array 552cb71a62aSAndreas Boehler */ 553b269830cSAndreas Boehler public function getCalendarSettings($calid) 554b269830cSAndreas Boehler { 555*185e2535SAndreas Boehler $query = "SELECT principaluri, calendarcolor, displayname, uri, description, components, transparent, synctoken FROM calendars WHERE id=".$this->sqlite->quote_string($calid); 556b269830cSAndreas Boehler $res = $this->sqlite->query($query); 557b269830cSAndreas Boehler $row = $this->sqlite->res2row($res); 558b269830cSAndreas Boehler return $row; 559b269830cSAndreas Boehler } 560b269830cSAndreas Boehler 561cb71a62aSAndreas Boehler /** 562cb71a62aSAndreas Boehler * Retrieve all events that are within a given date range, 563cb71a62aSAndreas Boehler * based on the timezone setting. 564cb71a62aSAndreas Boehler * 565cb71a62aSAndreas Boehler * There is also support for retrieving recurring events, 566cb71a62aSAndreas Boehler * using Sabre's VObject Iterator. Recurring events are represented 567cb71a62aSAndreas Boehler * as individual calendar entries with the same UID. 568cb71a62aSAndreas Boehler * 569cb71a62aSAndreas Boehler * @param string $id The page ID to work with 570cb71a62aSAndreas Boehler * @param string $user The user ID to work with 571cb71a62aSAndreas Boehler * @param string $startDate The start date as a string 572cb71a62aSAndreas Boehler * @param string $endDate The end date as a string 573cb71a62aSAndreas Boehler * 574cb71a62aSAndreas Boehler * @return array An array containing the calendar entries. 575cb71a62aSAndreas Boehler */ 576a1a3b679SAndreas Boehler public function getEventsWithinDateRange($id, $user, $startDate, $endDate) 577a1a3b679SAndreas Boehler { 578bd883736SAndreas Boehler $settings = $this->getPersonalSettings($user); 579bd883736SAndreas Boehler if($settings['timezone'] !== '' && $settings['timezone'] !== 'local') 580bd883736SAndreas Boehler $timezone = new \DateTimeZone($settings['timezone']); 581bd883736SAndreas Boehler else 582bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 583a1a3b679SAndreas Boehler $data = array(); 584cb71a62aSAndreas Boehler 585cb71a62aSAndreas Boehler // Load SabreDAV 586a1a3b679SAndreas Boehler require_once('vendor/autoload.php'); 587a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 588*185e2535SAndreas Boehler $color = $this->getCalendarColorForCalendar($calid); 589a1a3b679SAndreas Boehler $startTs = new \DateTime($startDate); 590a1a3b679SAndreas Boehler $endTs = new \DateTime($endDate); 591cb71a62aSAndreas Boehler 592cb71a62aSAndreas Boehler // Retrieve matching calendar objects 593ebc4eb57SAndreas Boehler $query = "SELECT calendardata, componenttype, uid FROM calendarobjects WHERE calendarid=". 594ebc4eb57SAndreas Boehler $this->sqlite->quote_string($calid)." AND firstoccurence < ". 595ebc4eb57SAndreas Boehler $this->sqlite->quote_string($endTs->getTimestamp())." AND lastoccurence > ". 596ebc4eb57SAndreas Boehler $this->sqlite->quote_string($startTs->getTimestamp()); 597a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 598a1a3b679SAndreas Boehler $arr = $this->sqlite->res2arr($res); 599cb71a62aSAndreas Boehler 600cb71a62aSAndreas Boehler // Parse individual calendar entries 601a1a3b679SAndreas Boehler foreach($arr as $row) 602a1a3b679SAndreas Boehler { 603a1a3b679SAndreas Boehler if(isset($row['calendardata'])) 604a1a3b679SAndreas Boehler { 605b269830cSAndreas Boehler $entry = array(); 606a1a3b679SAndreas Boehler $vcal = \Sabre\VObject\Reader::read($row['calendardata']); 607ebc4eb57SAndreas Boehler $recurrence = $vcal->VEVENT->RRULE; 608cb71a62aSAndreas Boehler // If it is a recurring event, pass it through Sabre's EventIterator 609ebc4eb57SAndreas Boehler if($recurrence != null) 610ebc4eb57SAndreas Boehler { 611ebc4eb57SAndreas Boehler $rEvents = new \Sabre\VObject\Recur\EventIterator(array($vcal->VEVENT)); 612ebc4eb57SAndreas Boehler $rEvents->rewind(); 613ebc4eb57SAndreas Boehler $done = false; 614ebc4eb57SAndreas Boehler while($rEvents->valid() && !$done) 615ebc4eb57SAndreas Boehler { 616ebc4eb57SAndreas Boehler $event = $rEvents->getEventObject(); 617cb71a62aSAndreas Boehler // If we are after the given time range, exit 618ebc4eb57SAndreas Boehler if(($rEvents->getDtStart()->getTimestamp() > $endTs->getTimestamp()) && 619ebc4eb57SAndreas Boehler ($rEvents->getDtEnd()->getTimestamp() > $endTs->getTimestamp())) 620ebc4eb57SAndreas Boehler $done = true; 621cb71a62aSAndreas Boehler 622cb71a62aSAndreas Boehler // If we are before the given time range, continue 623ebc4eb57SAndreas Boehler if($rEvents->getDtEnd()->getTimestamp() < $startTs->getTimestamp()) 624ebc4eb57SAndreas Boehler { 625ebc4eb57SAndreas Boehler $rEvents->next(); 626ebc4eb57SAndreas Boehler continue; 627ebc4eb57SAndreas Boehler } 628cb71a62aSAndreas Boehler 629cb71a62aSAndreas Boehler // If we are within the given time range, parse the event 630*185e2535SAndreas Boehler $data[] = $this->convertIcalDataToEntry($event, $id, $timezone, $row['uid'], $color, true); 631ebc4eb57SAndreas Boehler $rEvents->next(); 632ebc4eb57SAndreas Boehler } 633ebc4eb57SAndreas Boehler } 634ebc4eb57SAndreas Boehler else 635*185e2535SAndreas Boehler $data[] = $this->convertIcalDataToEntry($vcal->VEVENT, $id, $timezone, $row['uid'], $color); 636ebc4eb57SAndreas Boehler } 637ebc4eb57SAndreas Boehler } 638ebc4eb57SAndreas Boehler return $data; 639ebc4eb57SAndreas Boehler } 640ebc4eb57SAndreas Boehler 641cb71a62aSAndreas Boehler /** 642cb71a62aSAndreas Boehler * Helper function that parses the iCal data of a VEVENT to a calendar entry. 643cb71a62aSAndreas Boehler * 644cb71a62aSAndreas Boehler * @param \Sabre\VObject\VEvent $event The event to parse 645cb71a62aSAndreas Boehler * @param \DateTimeZone $timezone The timezone object 646cb71a62aSAndreas Boehler * @param string $uid The entry's UID 6473c86dda8SAndreas Boehler * @param boolean $recurring (optional) Set to true to define a recurring event 648cb71a62aSAndreas Boehler * 649cb71a62aSAndreas Boehler * @return array The parse calendar entry 650cb71a62aSAndreas Boehler */ 651*185e2535SAndreas Boehler private function convertIcalDataToEntry($event, $page, $timezone, $uid, $color, $recurring = false) 652ebc4eb57SAndreas Boehler { 653ebc4eb57SAndreas Boehler $entry = array(); 654ebc4eb57SAndreas Boehler $start = $event->DTSTART; 655cb71a62aSAndreas Boehler // Parse only if the start date/time is present 656b269830cSAndreas Boehler if($start !== null) 657b269830cSAndreas Boehler { 658b269830cSAndreas Boehler $dtStart = $start->getDateTime(); 659b269830cSAndreas Boehler $dtStart->setTimezone($timezone); 660b269830cSAndreas Boehler $entry['start'] = $dtStart->format(\DateTime::ATOM); 661b269830cSAndreas Boehler if($start['VALUE'] == 'DATE') 662b269830cSAndreas Boehler $entry['allDay'] = true; 663b269830cSAndreas Boehler else 664b269830cSAndreas Boehler $entry['allDay'] = false; 665b269830cSAndreas Boehler } 666ebc4eb57SAndreas Boehler $end = $event->DTEND; 667cb71a62aSAndreas Boehler // Parse onlyl if the end date/time is present 668b269830cSAndreas Boehler if($end !== null) 669b269830cSAndreas Boehler { 670b269830cSAndreas Boehler $dtEnd = $end->getDateTime(); 671b269830cSAndreas Boehler $dtEnd->setTimezone($timezone); 672b269830cSAndreas Boehler $entry['end'] = $dtEnd->format(\DateTime::ATOM); 673b269830cSAndreas Boehler } 674ebc4eb57SAndreas Boehler $description = $event->DESCRIPTION; 6750eebc909SAndreas Boehler if($description !== null) 6760eebc909SAndreas Boehler $entry['description'] = (string)$description; 6770eebc909SAndreas Boehler else 6780eebc909SAndreas Boehler $entry['description'] = ''; 679ebc4eb57SAndreas Boehler $entry['title'] = (string)$event->summary; 680ebc4eb57SAndreas Boehler $entry['id'] = $uid; 681*185e2535SAndreas Boehler $entry['page'] = $page; 682*185e2535SAndreas Boehler $entry['color'] = $color; 6833c86dda8SAndreas Boehler $entry['recurring'] = $recurring; 684*185e2535SAndreas Boehler 685ebc4eb57SAndreas Boehler return $entry; 686a1a3b679SAndreas Boehler } 687a1a3b679SAndreas Boehler 688cb71a62aSAndreas Boehler /** 689cb71a62aSAndreas Boehler * Retrieve an event by its UID 690cb71a62aSAndreas Boehler * 691cb71a62aSAndreas Boehler * @param string $uid The event's UID 692cb71a62aSAndreas Boehler * 693cb71a62aSAndreas Boehler * @return mixed The table row with the given event 694cb71a62aSAndreas Boehler */ 695a1a3b679SAndreas Boehler public function getEventWithUid($uid) 696a1a3b679SAndreas Boehler { 69755a741c0SAndreas Boehler $query = "SELECT calendardata, calendarid, componenttype, uri FROM calendarobjects WHERE uid=". 698a1a3b679SAndreas Boehler $this->sqlite->quote_string($uid); 699a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 700a1a3b679SAndreas Boehler $row = $this->sqlite->res2row($res); 701a1a3b679SAndreas Boehler return $row; 702a1a3b679SAndreas Boehler } 703a1a3b679SAndreas Boehler 704cb71a62aSAndreas Boehler /** 705cb71a62aSAndreas Boehler * Retrieve all calendar events for a given calendar ID 706cb71a62aSAndreas Boehler * 707cb71a62aSAndreas Boehler * @param string $calid The calendar's ID 708cb71a62aSAndreas Boehler * 709cb71a62aSAndreas Boehler * @return array An array containing all calendar data 710cb71a62aSAndreas Boehler */ 711f69bb449SAndreas Boehler public function getAllCalendarEvents($calid) 712f69bb449SAndreas Boehler { 713f69bb449SAndreas Boehler $query = "SELECT calendardata, uid, componenttype, uri FROM calendarobjects WHERE calendarid=". 714f69bb449SAndreas Boehler $this->sqlite->quote_string($calid); 715f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 716f69bb449SAndreas Boehler $arr = $this->sqlite->res2arr($res); 717f69bb449SAndreas Boehler return $arr; 718f69bb449SAndreas Boehler } 719f69bb449SAndreas Boehler 720cb71a62aSAndreas Boehler /** 721cb71a62aSAndreas Boehler * Edit a calendar entry for a page, given by its parameters. 722cb71a62aSAndreas Boehler * The params array has the same format as @see addCalendarEntryForPage 723cb71a62aSAndreas Boehler * 724cb71a62aSAndreas Boehler * @param string $id The page's ID to work on 725cb71a62aSAndreas Boehler * @param string $user The user's ID to work on 726cb71a62aSAndreas Boehler * @param array $params The parameter array for the edited calendar event 727cb71a62aSAndreas Boehler * 728cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 729cb71a62aSAndreas Boehler */ 730a1a3b679SAndreas Boehler public function editCalendarEntryForPage($id, $user, $params) 731a1a3b679SAndreas Boehler { 732bd883736SAndreas Boehler $settings = $this->getPersonalSettings($user); 733bd883736SAndreas Boehler if($settings['timezone'] !== '' && $settings['timezone'] !== 'local') 734bd883736SAndreas Boehler $timezone = new \DateTimeZone($settings['timezone']); 735a25c89eaSAndreas Boehler elseif($settings['timezone'] === 'local') 736a25c89eaSAndreas Boehler $timezone = new \DateTimeZone($params['detectedtz']); 737bd883736SAndreas Boehler else 738bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 739cb71a62aSAndreas Boehler 740cb71a62aSAndreas Boehler // Parse dates 741b269830cSAndreas Boehler $startDate = explode('-', $params['eventfrom']); 742b269830cSAndreas Boehler $startTime = explode(':', $params['eventfromtime']); 743b269830cSAndreas Boehler $endDate = explode('-', $params['eventto']); 744b269830cSAndreas Boehler $endTime = explode(':', $params['eventtotime']); 745cb71a62aSAndreas Boehler 746cb71a62aSAndreas Boehler // Retrieve the existing event based on the UID 74755a741c0SAndreas Boehler $uid = $params['uid']; 74855a741c0SAndreas Boehler $event = $this->getEventWithUid($uid); 749cb71a62aSAndreas Boehler 750cb71a62aSAndreas Boehler // Load SabreDAV 751a1a3b679SAndreas Boehler require_once('vendor/autoload.php'); 752a1a3b679SAndreas Boehler if(!isset($event['calendardata'])) 753a1a3b679SAndreas Boehler return false; 75455a741c0SAndreas Boehler $uri = $event['uri']; 75555a741c0SAndreas Boehler $calid = $event['calendarid']; 756cb71a62aSAndreas Boehler 757cb71a62aSAndreas Boehler // Parse the existing event 758a1a3b679SAndreas Boehler $vcal = \Sabre\VObject\Reader::read($event['calendardata']); 759b269830cSAndreas Boehler $vevent = $vcal->VEVENT; 760cb71a62aSAndreas Boehler 761cb71a62aSAndreas Boehler // Set the new event values 762b269830cSAndreas Boehler $vevent->summary = $params['eventname']; 763b269830cSAndreas Boehler $dtStamp = new \DateTime(null, new \DateTimeZone('UTC')); 7640eebc909SAndreas Boehler $description = $params['eventdescription']; 765cb71a62aSAndreas Boehler 766cb71a62aSAndreas Boehler // Remove existing timestamps to overwrite them 7670eebc909SAndreas Boehler $vevent->remove('DESCRIPTION'); 768b269830cSAndreas Boehler $vevent->remove('DTSTAMP'); 769b269830cSAndreas Boehler $vevent->remove('LAST-MODIFIED'); 770cb71a62aSAndreas Boehler 771cb71a62aSAndreas Boehler // Add new time stamps and description 772b269830cSAndreas Boehler $vevent->add('DTSTAMP', $dtStamp); 773b269830cSAndreas Boehler $vevent->add('LAST-MODIFIED', $dtStamp); 7740eebc909SAndreas Boehler if($description !== '') 7750eebc909SAndreas Boehler $vevent->add('DESCRIPTION', $description); 776cb71a62aSAndreas Boehler 777cb71a62aSAndreas Boehler // Setup DTSTART 778b269830cSAndreas Boehler $dtStart = new \DateTime(); 779a25c89eaSAndreas Boehler $dtStart->setTimezone($timezone); 780b269830cSAndreas Boehler $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2])); 781b269830cSAndreas Boehler if($params['allday'] != '1') 782b269830cSAndreas Boehler $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0); 783cb71a62aSAndreas Boehler 784cb71a62aSAndreas Boehler // Setup DETEND 785b269830cSAndreas Boehler $dtEnd = new \DateTime(); 786a25c89eaSAndreas Boehler $dtEnd->setTimezone($timezone); 787b269830cSAndreas Boehler $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2])); 788b269830cSAndreas Boehler if($params['allday'] != '1') 789b269830cSAndreas Boehler $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0); 790cb71a62aSAndreas Boehler 791b269830cSAndreas Boehler // According to the VCal spec, we need to add a whole day here 792b269830cSAndreas Boehler if($params['allday'] == '1') 793b269830cSAndreas Boehler $dtEnd->add(new \DateInterval('P1D')); 794b269830cSAndreas Boehler $vevent->remove('DTSTART'); 795b269830cSAndreas Boehler $vevent->remove('DTEND'); 796b269830cSAndreas Boehler $dtStartEv = $vevent->add('DTSTART', $dtStart); 797b269830cSAndreas Boehler $dtEndEv = $vevent->add('DTEND', $dtEnd); 798cb71a62aSAndreas Boehler 799cb71a62aSAndreas Boehler // Remove the time for allday events 800b269830cSAndreas Boehler if($params['allday'] == '1') 801b269830cSAndreas Boehler { 802b269830cSAndreas Boehler $dtStartEv['VALUE'] = 'DATE'; 803b269830cSAndreas Boehler $dtEndEv['VALUE'] = 'DATE'; 804b269830cSAndreas Boehler } 805a1a3b679SAndreas Boehler $now = new DateTime(); 806a1a3b679SAndreas Boehler $eventStr = $vcal->serialize(); 807a1a3b679SAndreas Boehler 808cb71a62aSAndreas Boehler // Actually write to the database 809a1a3b679SAndreas Boehler $query = "UPDATE calendarobjects SET calendardata=".$this->sqlite->quote_string($eventStr). 810a1a3b679SAndreas Boehler ", lastmodified=".$this->sqlite->quote_string($now->getTimestamp()). 811a1a3b679SAndreas Boehler ", firstoccurence=".$this->sqlite->quote_string($dtStart->getTimestamp()). 812a1a3b679SAndreas Boehler ", lastoccurence=".$this->sqlite->quote_string($dtEnd->getTimestamp()). 813a1a3b679SAndreas Boehler ", size=".strlen($eventStr). 814a1a3b679SAndreas Boehler ", etag=".$this->sqlite->quote_string(md5($eventStr)). 81555a741c0SAndreas Boehler " WHERE uid=".$this->sqlite->quote_string($uid); 816a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 81755a741c0SAndreas Boehler if($res !== false) 81855a741c0SAndreas Boehler { 81955a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'modified'); 820a1a3b679SAndreas Boehler return true; 821a1a3b679SAndreas Boehler } 82255a741c0SAndreas Boehler return false; 82355a741c0SAndreas Boehler } 824a1a3b679SAndreas Boehler 825cb71a62aSAndreas Boehler /** 826cb71a62aSAndreas Boehler * Delete a calendar entry for a given page. Actually, the event is removed 827cb71a62aSAndreas Boehler * based on the entry's UID, so that page ID is no used. 828cb71a62aSAndreas Boehler * 829cb71a62aSAndreas Boehler * @param string $id The page's ID (unused) 830cb71a62aSAndreas Boehler * @param array $params The parameter array to work with 831cb71a62aSAndreas Boehler * 832cb71a62aSAndreas Boehler * @return boolean True 833cb71a62aSAndreas Boehler */ 834a1a3b679SAndreas Boehler public function deleteCalendarEntryForPage($id, $params) 835a1a3b679SAndreas Boehler { 836a1a3b679SAndreas Boehler $uid = $params['uid']; 83755a741c0SAndreas Boehler $event = $this->getEventWithUid($uid); 8382c14b82bSAndreas Boehler $calid = $event['calendarid']; 83955a741c0SAndreas Boehler $uri = $event['uri']; 840a1a3b679SAndreas Boehler $query = "DELETE FROM calendarobjects WHERE uid=".$this->sqlite->quote_string($uid); 841a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 84255a741c0SAndreas Boehler if($res !== false) 84355a741c0SAndreas Boehler { 84455a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'deleted'); 84555a741c0SAndreas Boehler } 846a1a3b679SAndreas Boehler return true; 847a1a3b679SAndreas Boehler } 848a1a3b679SAndreas Boehler 849cb71a62aSAndreas Boehler /** 850cb71a62aSAndreas Boehler * Retrieve the current sync token for a calendar 851cb71a62aSAndreas Boehler * 852cb71a62aSAndreas Boehler * @param string $calid The calendar id 853cb71a62aSAndreas Boehler * 854cb71a62aSAndreas Boehler * @return mixed The synctoken or false 855cb71a62aSAndreas Boehler */ 85655a741c0SAndreas Boehler public function getSyncTokenForCalendar($calid) 85755a741c0SAndreas Boehler { 858b269830cSAndreas Boehler $row = $this->getCalendarSettings($calid); 85955a741c0SAndreas Boehler if(isset($row['synctoken'])) 86055a741c0SAndreas Boehler return $row['synctoken']; 86155a741c0SAndreas Boehler return false; 86255a741c0SAndreas Boehler } 86355a741c0SAndreas Boehler 864cb71a62aSAndreas Boehler /** 865cb71a62aSAndreas Boehler * Helper function to convert the operation name to 866cb71a62aSAndreas Boehler * an operation code as stored in the database 867cb71a62aSAndreas Boehler * 868cb71a62aSAndreas Boehler * @param string $operationName The operation name 869cb71a62aSAndreas Boehler * 870cb71a62aSAndreas Boehler * @return mixed The operation code or false 871cb71a62aSAndreas Boehler */ 87255a741c0SAndreas Boehler public function operationNameToOperation($operationName) 87355a741c0SAndreas Boehler { 87455a741c0SAndreas Boehler switch($operationName) 87555a741c0SAndreas Boehler { 87655a741c0SAndreas Boehler case 'added': 87755a741c0SAndreas Boehler return 1; 87855a741c0SAndreas Boehler break; 87955a741c0SAndreas Boehler case 'modified': 88055a741c0SAndreas Boehler return 2; 88155a741c0SAndreas Boehler break; 88255a741c0SAndreas Boehler case 'deleted': 88355a741c0SAndreas Boehler return 3; 88455a741c0SAndreas Boehler break; 88555a741c0SAndreas Boehler } 88655a741c0SAndreas Boehler return false; 88755a741c0SAndreas Boehler } 88855a741c0SAndreas Boehler 889cb71a62aSAndreas Boehler /** 890cb71a62aSAndreas Boehler * Update the sync token log based on the calendar id and the 891cb71a62aSAndreas Boehler * operation that was performed. 892cb71a62aSAndreas Boehler * 893cb71a62aSAndreas Boehler * @param string $calid The calendar ID that was modified 894cb71a62aSAndreas Boehler * @param string $uri The calendar URI that was modified 895cb71a62aSAndreas Boehler * @param string $operation The operation that was performed 896cb71a62aSAndreas Boehler * 897cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 898cb71a62aSAndreas Boehler */ 89955a741c0SAndreas Boehler private function updateSyncTokenLog($calid, $uri, $operation) 90055a741c0SAndreas Boehler { 90155a741c0SAndreas Boehler $currentToken = $this->getSyncTokenForCalendar($calid); 90255a741c0SAndreas Boehler $operationCode = $this->operationNameToOperation($operation); 90355a741c0SAndreas Boehler if(($operationCode === false) || ($currentToken === false)) 90455a741c0SAndreas Boehler return false; 90555a741c0SAndreas Boehler $values = array($uri, 90655a741c0SAndreas Boehler $currentToken, 90755a741c0SAndreas Boehler $calid, 90855a741c0SAndreas Boehler $operationCode 90955a741c0SAndreas Boehler ); 91055a741c0SAndreas Boehler $query = "INSERT INTO calendarchanges (uri, synctoken, calendarid, operation) VALUES(". 91155a741c0SAndreas Boehler $this->sqlite->quote_and_join($values, ',').")"; 91255a741c0SAndreas Boehler $res = $this->sqlite->query($query); 91355a741c0SAndreas Boehler if($res === false) 91455a741c0SAndreas Boehler return false; 91555a741c0SAndreas Boehler $currentToken++; 91655a741c0SAndreas Boehler $query = "UPDATE calendars SET synctoken=".$this->sqlite->quote_string($currentToken)." WHERE id=". 91755a741c0SAndreas Boehler $this->sqlite->quote_string($calid); 91855a741c0SAndreas Boehler $res = $this->sqlite->query($query); 91955a741c0SAndreas Boehler return ($res !== false); 92055a741c0SAndreas Boehler } 92155a741c0SAndreas Boehler 922cb71a62aSAndreas Boehler /** 923cb71a62aSAndreas Boehler * Return the sync URL for a given Page, i.e. a calendar 924cb71a62aSAndreas Boehler * 925cb71a62aSAndreas Boehler * @param string $id The page's ID 926cb71a62aSAndreas Boehler * @param string $user (optional) The user's ID 927cb71a62aSAndreas Boehler * 928cb71a62aSAndreas Boehler * @return mixed The sync url or false 929cb71a62aSAndreas Boehler */ 930b269830cSAndreas Boehler public function getSyncUrlForPage($id, $user = null) 931b269830cSAndreas Boehler { 932b269830cSAndreas Boehler if(is_null($user)) 933b269830cSAndreas Boehler $user = $_SERVER['REMOTE_USER']; 934b269830cSAndreas Boehler 935b269830cSAndreas Boehler $calid = $this->getCalendarIdForPage($id); 936b269830cSAndreas Boehler if($calid === false) 937b269830cSAndreas Boehler return false; 938b269830cSAndreas Boehler 939b269830cSAndreas Boehler $calsettings = $this->getCalendarSettings($calid); 940b269830cSAndreas Boehler if(!isset($calsettings['uri'])) 941b269830cSAndreas Boehler return false; 942b269830cSAndreas Boehler 943b269830cSAndreas Boehler $syncurl = DOKU_URL.'lib/plugins/davcal/calendarserver.php/calendars/'.$user.'/'.$calsettings['uri']; 944b269830cSAndreas Boehler return $syncurl; 945b269830cSAndreas Boehler } 946b269830cSAndreas Boehler 947cb71a62aSAndreas Boehler /** 948cb71a62aSAndreas Boehler * Return the private calendar's URL for a given page 949cb71a62aSAndreas Boehler * 950cb71a62aSAndreas Boehler * @param string $id the page ID 951cb71a62aSAndreas Boehler * 952cb71a62aSAndreas Boehler * @return mixed The private URL or false 953cb71a62aSAndreas Boehler */ 954f69bb449SAndreas Boehler public function getPrivateURLForPage($id) 955f69bb449SAndreas Boehler { 956f69bb449SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 957f69bb449SAndreas Boehler if($calid === false) 958f69bb449SAndreas Boehler return false; 959f69bb449SAndreas Boehler 960f69bb449SAndreas Boehler return $this->getPrivateURLForCalendar($calid); 961f69bb449SAndreas Boehler } 962f69bb449SAndreas Boehler 963cb71a62aSAndreas Boehler /** 964cb71a62aSAndreas Boehler * Return the private calendar's URL for a given calendar ID 965cb71a62aSAndreas Boehler * 966cb71a62aSAndreas Boehler * @param string $calid The calendar's ID 967cb71a62aSAndreas Boehler * 968cb71a62aSAndreas Boehler * @return mixed The private URL or false 969cb71a62aSAndreas Boehler */ 970f69bb449SAndreas Boehler public function getPrivateURLForCalendar($calid) 971f69bb449SAndreas Boehler { 972*185e2535SAndreas Boehler if(isset($this->cachedValues['privateurl'][$calid])) 973*185e2535SAndreas Boehler return $this->cachedValues['privateurl'][$calid]; 974f69bb449SAndreas Boehler $query = "SELECT url FROM calendartoprivateurlmapping WHERE calid=".$this->sqlite->quote_string($calid); 975f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 976f69bb449SAndreas Boehler $row = $this->sqlite->res2row($res); 977f69bb449SAndreas Boehler if(!isset($row['url'])) 978f69bb449SAndreas Boehler { 979f69bb449SAndreas Boehler $url = uniqid("dokuwiki-").".ics"; 980f69bb449SAndreas Boehler $values = array( 981f69bb449SAndreas Boehler $url, 982f69bb449SAndreas Boehler $calid 983f69bb449SAndreas Boehler ); 984f69bb449SAndreas Boehler $query = "INSERT INTO calendartoprivateurlmapping (url, calid) VALUES(". 985f69bb449SAndreas Boehler $this->sqlite->quote_and_join($values, ", ").")"; 986f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 987f69bb449SAndreas Boehler if($res === false) 988f69bb449SAndreas Boehler return false; 989f69bb449SAndreas Boehler } 990f69bb449SAndreas Boehler else 991f69bb449SAndreas Boehler { 992f69bb449SAndreas Boehler $url = $row['url']; 993f69bb449SAndreas Boehler } 994*185e2535SAndreas Boehler 995*185e2535SAndreas Boehler $url = DOKU_URL.'lib/plugins/davcal/ics.php/'.$url; 996*185e2535SAndreas Boehler $this->cachedValues['privateurl'][$calid] = $url; 997*185e2535SAndreas Boehler return $url; 998f69bb449SAndreas Boehler } 999f69bb449SAndreas Boehler 1000cb71a62aSAndreas Boehler /** 1001cb71a62aSAndreas Boehler * Retrieve the calendar ID for a given private calendar URL 1002cb71a62aSAndreas Boehler * 1003cb71a62aSAndreas Boehler * @param string $url The private URL 1004cb71a62aSAndreas Boehler * 1005cb71a62aSAndreas Boehler * @return mixed The calendar ID or false 1006cb71a62aSAndreas Boehler */ 1007f69bb449SAndreas Boehler public function getCalendarForPrivateURL($url) 1008f69bb449SAndreas Boehler { 1009f69bb449SAndreas Boehler $query = "SELECT calid FROM calendartoprivateurlmapping WHERE url=".$this->sqlite->quote_string($url); 1010f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 1011f69bb449SAndreas Boehler $row = $this->sqlite->res2row($res); 1012f69bb449SAndreas Boehler if(!isset($row['calid'])) 1013f69bb449SAndreas Boehler return false; 1014f69bb449SAndreas Boehler return $row['calid']; 1015f69bb449SAndreas Boehler } 1016f69bb449SAndreas Boehler 1017cb71a62aSAndreas Boehler /** 1018cb71a62aSAndreas Boehler * Return a given calendar as ICS feed, i.e. all events in one ICS file. 1019cb71a62aSAndreas Boehler * 1020cb71a62aSAndreas Boehler * @param string $caldi The calendar ID to retrieve 1021cb71a62aSAndreas Boehler * 1022cb71a62aSAndreas Boehler * @return mixed The calendar events as string or false 1023cb71a62aSAndreas Boehler */ 1024f69bb449SAndreas Boehler public function getCalendarAsICSFeed($calid) 1025f69bb449SAndreas Boehler { 1026f69bb449SAndreas Boehler $calSettings = $this->getCalendarSettings($calid); 1027f69bb449SAndreas Boehler if($calSettings === false) 1028f69bb449SAndreas Boehler return false; 1029f69bb449SAndreas Boehler $events = $this->getAllCalendarEvents($calid); 1030f69bb449SAndreas Boehler if($events === false) 1031f69bb449SAndreas Boehler return false; 1032f69bb449SAndreas Boehler 1033f69bb449SAndreas Boehler $out = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//DAVCal//DAVCal for DokuWiki//EN\nCALSCALE:GREGORIAN\nX-WR-CALNAME:"; 1034f69bb449SAndreas Boehler $out .= $calSettings['displayname']."\n"; 1035f69bb449SAndreas Boehler foreach($events as $event) 1036f69bb449SAndreas Boehler { 1037f69bb449SAndreas Boehler $out .= rtrim($event['calendardata']); 1038f69bb449SAndreas Boehler $out .= "\n"; 1039f69bb449SAndreas Boehler } 1040f69bb449SAndreas Boehler $out .= "END:VCALENDAR\n"; 1041f69bb449SAndreas Boehler return $out; 1042f69bb449SAndreas Boehler } 1043f69bb449SAndreas Boehler 1044a1a3b679SAndreas Boehler} 1045