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'); 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 /** 34185e2535SAndreas Boehler * Retrieve meta data for a given page 35185e2535SAndreas Boehler * 36185e2535SAndreas Boehler * @param string $id optional The page ID 37185e2535SAndreas Boehler * @return array The metadata 38185e2535SAndreas Boehler */ 39185e2535SAndreas Boehler private function getMeta($id = null) { 40185e2535SAndreas Boehler global $ID; 41185e2535SAndreas Boehler global $INFO; 42185e2535SAndreas Boehler 43185e2535SAndreas Boehler if ($id === null) $id = $ID; 44185e2535SAndreas Boehler 45185e2535SAndreas Boehler if($ID === $id && $INFO['meta']) { 46185e2535SAndreas Boehler $meta = $INFO['meta']; 47185e2535SAndreas Boehler } else { 48185e2535SAndreas Boehler $meta = p_get_metadata($id); 49185e2535SAndreas Boehler } 50185e2535SAndreas Boehler 51185e2535SAndreas Boehler return $meta; 52185e2535SAndreas Boehler } 53185e2535SAndreas Boehler 54185e2535SAndreas Boehler /** 55185e2535SAndreas Boehler * Retrieve the meta data for a given page 56185e2535SAndreas Boehler * 57185e2535SAndreas Boehler * @param string $id optional The page ID 58185e2535SAndreas Boehler * @return array with meta data 59185e2535SAndreas Boehler */ 60185e2535SAndreas Boehler public function getCalendarMetaForPage($id = null) 61185e2535SAndreas Boehler { 62185e2535SAndreas Boehler if(is_null($id)) 63185e2535SAndreas Boehler { 64185e2535SAndreas Boehler global $ID; 65185e2535SAndreas Boehler $id = $ID; 66185e2535SAndreas Boehler } 67185e2535SAndreas Boehler 68185e2535SAndreas Boehler $meta = $this->getMeta($id); 69185e2535SAndreas Boehler if(isset($meta['plugin_davcal'])) 70185e2535SAndreas Boehler return $meta['plugin_davcal']; 71185e2535SAndreas Boehler else 72185e2535SAndreas Boehler return array(); 73185e2535SAndreas Boehler } 74185e2535SAndreas Boehler 75185e2535SAndreas Boehler /** 76185e2535SAndreas Boehler * Get all calendar pages used by a given page 77185e2535SAndreas Boehler * based on the stored metadata 78185e2535SAndreas Boehler * 79185e2535SAndreas Boehler * @param string $id optional The page id 80185e2535SAndreas Boehler * @return mixed The pages as array or false 81185e2535SAndreas Boehler */ 82185e2535SAndreas Boehler public function getCalendarPagesByMeta($id = null) 83185e2535SAndreas Boehler { 84185e2535SAndreas Boehler if(is_null($id)) 85185e2535SAndreas Boehler { 86185e2535SAndreas Boehler global $ID; 87185e2535SAndreas Boehler $id = $ID; 88185e2535SAndreas Boehler } 89185e2535SAndreas Boehler 90185e2535SAndreas Boehler $meta = $this->getCalendarMetaForPage($id); 91185e2535SAndreas Boehler if(isset($meta['id'])) 92185e2535SAndreas Boehler { 93185e2535SAndreas Boehler return array_keys($meta['id']); 94185e2535SAndreas Boehler } 95185e2535SAndreas Boehler return false; 96185e2535SAndreas Boehler } 97185e2535SAndreas Boehler 98185e2535SAndreas Boehler /** 99185e2535SAndreas Boehler * Get a list of calendar names/pages/ids/colors 100185e2535SAndreas Boehler * for an array of page ids 101185e2535SAndreas Boehler * 102185e2535SAndreas Boehler * @param array $calendarPages The calendar pages to retrieve 103185e2535SAndreas Boehler * @return array The list 104185e2535SAndreas Boehler */ 105185e2535SAndreas Boehler public function getCalendarMapForIDs($calendarPages) 106185e2535SAndreas Boehler { 107185e2535SAndreas Boehler $data = array(); 108185e2535SAndreas Boehler foreach($calendarPages as $page) 109185e2535SAndreas Boehler { 110185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($page); 111185e2535SAndreas Boehler if($calid !== false) 112185e2535SAndreas Boehler { 113185e2535SAndreas Boehler $settings = $this->getCalendarSettings($calid); 114185e2535SAndreas Boehler $name = $settings['displayname']; 115185e2535SAndreas Boehler $color = $settings['calendarcolor']; 116185e2535SAndreas Boehler $data[] = array('name' => $name, 'page' => $page, 'calid' => $calid, 117185e2535SAndreas Boehler 'color' => $color); 118185e2535SAndreas Boehler } 119185e2535SAndreas Boehler } 120185e2535SAndreas Boehler return $data; 121185e2535SAndreas Boehler } 122185e2535SAndreas Boehler 123185e2535SAndreas Boehler /** 124185e2535SAndreas Boehler * Get the saved calendar color for a given page. 125185e2535SAndreas Boehler * 126185e2535SAndreas Boehler * @param string $id optional The page ID 127185e2535SAndreas Boehler * @return mixed The color on success, otherwise false 128185e2535SAndreas Boehler */ 129185e2535SAndreas Boehler public function getCalendarColorForPage($id = null) 130185e2535SAndreas Boehler { 131185e2535SAndreas Boehler if(is_null($id)) 132185e2535SAndreas Boehler { 133185e2535SAndreas Boehler global $ID; 134185e2535SAndreas Boehler $id = $ID; 135185e2535SAndreas Boehler } 136185e2535SAndreas Boehler 137185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 138185e2535SAndreas Boehler if($calid === false) 139185e2535SAndreas Boehler return false; 140185e2535SAndreas Boehler 141185e2535SAndreas Boehler return $this->getCalendarColorForCalendar($calid); 142185e2535SAndreas Boehler } 143185e2535SAndreas Boehler 144185e2535SAndreas Boehler /** 145185e2535SAndreas Boehler * Get the saved calendar color for a given calendar ID. 146185e2535SAndreas Boehler * 147185e2535SAndreas Boehler * @param string $id optional The calendar ID 148185e2535SAndreas Boehler * @return mixed The color on success, otherwise false 149185e2535SAndreas Boehler */ 150185e2535SAndreas Boehler public function getCalendarColorForCalendar($calid) 151185e2535SAndreas Boehler { 152185e2535SAndreas Boehler if(isset($this->cachedValues['calendarcolor'][$calid])) 153185e2535SAndreas Boehler return $this->cachedValues['calendarcolor'][$calid]; 154185e2535SAndreas Boehler 155185e2535SAndreas Boehler $row = $this->getCalendarSettings($calid); 156185e2535SAndreas Boehler 157185e2535SAndreas Boehler if(!isset($row['calendarcolor'])) 158185e2535SAndreas Boehler return false; 159185e2535SAndreas Boehler 160185e2535SAndreas Boehler $color = $row['calendarcolor']; 161185e2535SAndreas Boehler $this->cachedValues['calendarcolor'][$calid] = $color; 162185e2535SAndreas Boehler return $color; 163185e2535SAndreas Boehler } 164185e2535SAndreas Boehler 165185e2535SAndreas Boehler /** 166185e2535SAndreas Boehler * Set the calendar color for a given page. 167185e2535SAndreas Boehler * 168185e2535SAndreas Boehler * @param string $color The color definition 169185e2535SAndreas Boehler * @param string $id optional The page ID 170185e2535SAndreas Boehler * @return boolean True on success, otherwise false 171185e2535SAndreas Boehler */ 172185e2535SAndreas Boehler public function setCalendarColorForPage($color, $id = null) 173185e2535SAndreas Boehler { 174185e2535SAndreas Boehler if(is_null($id)) 175185e2535SAndreas Boehler { 176185e2535SAndreas Boehler global $ID; 177185e2535SAndreas Boehler $id = $ID; 178185e2535SAndreas Boehler } 179185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 180185e2535SAndreas Boehler if($calid === false) 181185e2535SAndreas Boehler return false; 182185e2535SAndreas Boehler 183185e2535SAndreas Boehler $query = "UPDATE calendars SET calendarcolor=".$this->sqlite->quote_string($color). 184185e2535SAndreas Boehler " WHERE id=".$this->sqlite->quote_string($calid); 185185e2535SAndreas Boehler $res = $this->sqlite->query($query); 186185e2535SAndreas Boehler if($res !== false) 187185e2535SAndreas Boehler { 188185e2535SAndreas Boehler $this->cachedValues['calendarcolor'][$calid] = $color; 189185e2535SAndreas Boehler return true; 190185e2535SAndreas Boehler } 191185e2535SAndreas Boehler return false; 192185e2535SAndreas Boehler } 193185e2535SAndreas Boehler 194185e2535SAndreas 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)) 214*34a47953SAndreas Boehler { 215*34a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 216*34a47953SAndreas Boehler { 217a1a3b679SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 218*34a47953SAndreas Boehler } 219*34a47953SAndreas Boehler else 220*34a47953SAndreas Boehler { 221*34a47953SAndreas Boehler $userid = uniqid('davcal-'); 222*34a47953SAndreas Boehler } 223*34a47953SAndreas Boehler } 224a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 225a1a3b679SAndreas Boehler if($calid === false) 226a1a3b679SAndreas Boehler return $this->createCalendarForPage($name, $description, $id, $userid); 227a1a3b679SAndreas Boehler 228b269830cSAndreas Boehler $query = "UPDATE calendars SET displayname=".$this->sqlite->quote_string($name).", ". 229b269830cSAndreas Boehler "description=".$this->sqlite->quote_string($description)." WHERE ". 230b269830cSAndreas Boehler "id=".$this->sqlite->quote_string($calid); 231b269830cSAndreas Boehler $res = $this->sqlite->query($query); 232b269830cSAndreas Boehler if($res !== false) 233b269830cSAndreas Boehler return true; 234b269830cSAndreas Boehler return false; 235a1a3b679SAndreas Boehler } 236a1a3b679SAndreas Boehler 237cb71a62aSAndreas Boehler /** 238cb71a62aSAndreas Boehler * Save the personal settings to the SQLite database 'calendarsettings'. 239cb71a62aSAndreas Boehler * 240cb71a62aSAndreas Boehler * @param array $settings The settings array to store 241cb71a62aSAndreas Boehler * @param string $userid (optional) The userid to store 242cb71a62aSAndreas Boehler * 243cb71a62aSAndreas Boehler * @param boolean True on success, otherwise false 244cb71a62aSAndreas Boehler */ 245a495d34cSAndreas Boehler public function savePersonalSettings($settings, $userid = null) 246a495d34cSAndreas Boehler { 247a495d34cSAndreas Boehler if(is_null($userid)) 248*34a47953SAndreas Boehler { 249*34a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 250*34a47953SAndreas Boehler { 251a495d34cSAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 252*34a47953SAndreas Boehler } 253*34a47953SAndreas Boehler else 254*34a47953SAndreas Boehler { 255*34a47953SAndreas Boehler return false; 256*34a47953SAndreas Boehler } 257*34a47953SAndreas Boehler } 258a495d34cSAndreas Boehler $this->sqlite->query("BEGIN TRANSACTION"); 259a495d34cSAndreas Boehler 260bd883736SAndreas Boehler $query = "DELETE FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid); 261bd883736SAndreas Boehler $this->sqlite->query($query); 262bd883736SAndreas Boehler 263a495d34cSAndreas Boehler foreach($settings as $key => $value) 264a495d34cSAndreas Boehler { 265bd883736SAndreas Boehler $query = "INSERT INTO calendarsettings (userid, key, value) VALUES (". 266a495d34cSAndreas Boehler $this->sqlite->quote_string($userid).", ". 267a495d34cSAndreas Boehler $this->sqlite->quote_string($key).", ". 268a495d34cSAndreas Boehler $this->sqlite->quote_string($value).")"; 269a495d34cSAndreas Boehler $res = $this->sqlite->query($query); 270a495d34cSAndreas Boehler if($res === false) 271a495d34cSAndreas Boehler return false; 272a495d34cSAndreas Boehler } 273a495d34cSAndreas Boehler $this->sqlite->query("COMMIT TRANSACTION"); 274185e2535SAndreas Boehler $this->cachedValues['settings'][$userid] = $settings; 275a495d34cSAndreas Boehler return true; 276a495d34cSAndreas Boehler } 277a495d34cSAndreas Boehler 278cb71a62aSAndreas Boehler /** 279cb71a62aSAndreas Boehler * Retrieve the settings array for a given user id. 280cb71a62aSAndreas Boehler * Some sane defaults are returned, currently: 281cb71a62aSAndreas Boehler * 282cb71a62aSAndreas Boehler * timezone => local 283cb71a62aSAndreas Boehler * weeknumbers => 0 284cb71a62aSAndreas Boehler * workweek => 0 285cb71a62aSAndreas Boehler * 286cb71a62aSAndreas Boehler * @param string $userid (optional) The user id to retrieve 287cb71a62aSAndreas Boehler * 288cb71a62aSAndreas Boehler * @return array The settings array 289cb71a62aSAndreas Boehler */ 290a495d34cSAndreas Boehler public function getPersonalSettings($userid = null) 291a495d34cSAndreas Boehler { 292bd883736SAndreas Boehler // Some sane default settings 293bd883736SAndreas Boehler $settings = array( 294fb813b30SAndreas Boehler 'timezone' => $this->getConf('timezone'), 295fb813b30SAndreas Boehler 'weeknumbers' => $this->getConf('weeknumbers'), 296fb813b30SAndreas Boehler 'workweek' => $this->getConf('workweek'), 297fb813b30SAndreas Boehler 'monday' => $this->getConf('monday') 298bd883736SAndreas Boehler ); 299*34a47953SAndreas Boehler if(is_null($userid)) 300*34a47953SAndreas Boehler { 301*34a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 302*34a47953SAndreas Boehler { 303*34a47953SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 304*34a47953SAndreas Boehler } 305*34a47953SAndreas Boehler else 306*34a47953SAndreas Boehler { 307*34a47953SAndreas Boehler return $settings; 308*34a47953SAndreas Boehler } 309*34a47953SAndreas Boehler } 310*34a47953SAndreas Boehler 311*34a47953SAndreas Boehler if(isset($this->cachedValues['settings'][$userid])) 312*34a47953SAndreas Boehler return $this->cachedValues['settings'][$userid]; 313a495d34cSAndreas Boehler $query = "SELECT key, value FROM calendarsettings WHERE userid=".$this->sqlite->quote_string($userid); 314a495d34cSAndreas Boehler $res = $this->sqlite->query($query); 315a495d34cSAndreas Boehler $arr = $this->sqlite->res2arr($res); 316a495d34cSAndreas Boehler foreach($arr as $row) 317a495d34cSAndreas Boehler { 318a495d34cSAndreas Boehler $settings[$row['key']] = $row['value']; 319a495d34cSAndreas Boehler } 320185e2535SAndreas Boehler $this->cachedValues['settings'][$userid] = $settings; 321a495d34cSAndreas Boehler return $settings; 322a495d34cSAndreas Boehler } 323a495d34cSAndreas Boehler 324cb71a62aSAndreas Boehler /** 325cb71a62aSAndreas Boehler * Retrieve the calendar ID based on a page ID from the SQLite table 326cb71a62aSAndreas Boehler * 'pagetocalendarmapping'. 327cb71a62aSAndreas Boehler * 328cb71a62aSAndreas Boehler * @param string $id (optional) The page ID to retrieve the corresponding calendar 329cb71a62aSAndreas Boehler * 330cb71a62aSAndreas Boehler * @return mixed the ID on success, otherwise false 331cb71a62aSAndreas Boehler */ 332a1a3b679SAndreas Boehler public function getCalendarIdForPage($id = null) 333a1a3b679SAndreas Boehler { 334a1a3b679SAndreas Boehler if(is_null($id)) 335a1a3b679SAndreas Boehler { 336a1a3b679SAndreas Boehler global $ID; 337a1a3b679SAndreas Boehler $id = $ID; 338a1a3b679SAndreas Boehler } 339a1a3b679SAndreas Boehler 340185e2535SAndreas Boehler if(isset($this->cachedValues['calid'][$id])) 341185e2535SAndreas Boehler return $this->cachedValues['calid'][$id]; 342185e2535SAndreas Boehler 343a1a3b679SAndreas Boehler $query = "SELECT calid FROM pagetocalendarmapping WHERE page=".$this->sqlite->quote_string($id); 344a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 345a1a3b679SAndreas Boehler $row = $this->sqlite->res2row($res); 346a1a3b679SAndreas Boehler if(isset($row['calid'])) 347185e2535SAndreas Boehler { 348185e2535SAndreas Boehler $calid = $row['calid']; 349185e2535SAndreas Boehler $this->cachedValues['calid'] = $calid; 350185e2535SAndreas Boehler return $calid; 351185e2535SAndreas Boehler } 352a1a3b679SAndreas Boehler return false; 353a1a3b679SAndreas Boehler } 354a1a3b679SAndreas Boehler 355cb71a62aSAndreas Boehler /** 356cb71a62aSAndreas Boehler * Retrieve the complete calendar id to page mapping. 357cb71a62aSAndreas Boehler * This is necessary to be able to retrieve a list of 358cb71a62aSAndreas Boehler * calendars for a given user and check the access rights. 359cb71a62aSAndreas Boehler * 360cb71a62aSAndreas Boehler * @return array The mapping array 361cb71a62aSAndreas Boehler */ 362a1a3b679SAndreas Boehler public function getCalendarIdToPageMapping() 363a1a3b679SAndreas Boehler { 364a1a3b679SAndreas Boehler $query = "SELECT calid, page FROM pagetocalendarmapping"; 365a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 366a1a3b679SAndreas Boehler $arr = $this->sqlite->res2arr($res); 367a1a3b679SAndreas Boehler return $arr; 368a1a3b679SAndreas Boehler } 369a1a3b679SAndreas Boehler 370cb71a62aSAndreas Boehler /** 371cb71a62aSAndreas Boehler * Retrieve all calendar IDs a given user has access to. 372cb71a62aSAndreas Boehler * The user is specified by the principalUri, so the 373cb71a62aSAndreas Boehler * user name is actually split from the URI component. 374cb71a62aSAndreas Boehler * 375cb71a62aSAndreas Boehler * Access rights are checked against DokuWiki's ACL 376cb71a62aSAndreas Boehler * and applied accordingly. 377cb71a62aSAndreas Boehler * 378cb71a62aSAndreas Boehler * @param string $principalUri The principal URI to work on 379cb71a62aSAndreas Boehler * 380cb71a62aSAndreas Boehler * @return array An associative array of calendar IDs 381cb71a62aSAndreas Boehler */ 382a1a3b679SAndreas Boehler public function getCalendarIdsForUser($principalUri) 383a1a3b679SAndreas Boehler { 384*34a47953SAndreas Boehler global $auth; 385a1a3b679SAndreas Boehler $user = explode('/', $principalUri); 386a1a3b679SAndreas Boehler $user = end($user); 387a1a3b679SAndreas Boehler $mapping = $this->getCalendarIdToPageMapping(); 388a1a3b679SAndreas Boehler $calids = array(); 389*34a47953SAndreas Boehler $ud = $auth->getUserData($user); 390*34a47953SAndreas Boehler $groups = $ud['grps']; 391a1a3b679SAndreas Boehler foreach($mapping as $row) 392a1a3b679SAndreas Boehler { 393a1a3b679SAndreas Boehler $id = $row['calid']; 394a1a3b679SAndreas Boehler $page = $row['page']; 395*34a47953SAndreas Boehler $acl = auth_aclcheck($page, $user, $groups); 396a1a3b679SAndreas Boehler if($acl >= AUTH_READ) 397a1a3b679SAndreas Boehler { 398a1a3b679SAndreas Boehler $write = $acl > AUTH_READ; 399a1a3b679SAndreas Boehler $calids[$id] = array('readonly' => !$write); 400a1a3b679SAndreas Boehler } 401a1a3b679SAndreas Boehler } 402a1a3b679SAndreas Boehler return $calids; 403a1a3b679SAndreas Boehler } 404a1a3b679SAndreas Boehler 405cb71a62aSAndreas Boehler /** 406cb71a62aSAndreas Boehler * Create a new calendar for a given page ID and set name and description 407cb71a62aSAndreas Boehler * accordingly. Also update the pagetocalendarmapping table on success. 408cb71a62aSAndreas Boehler * 409cb71a62aSAndreas Boehler * @param string $name The calendar's name 410cb71a62aSAndreas Boehler * @param string $description The calendar's description 411cb71a62aSAndreas Boehler * @param string $id (optional) The page ID to work on 412cb71a62aSAndreas Boehler * @param string $userid (optional) The user ID that created the calendar 413cb71a62aSAndreas Boehler * 414cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 415cb71a62aSAndreas Boehler */ 416a1a3b679SAndreas Boehler public function createCalendarForPage($name, $description, $id = null, $userid = null) 417a1a3b679SAndreas Boehler { 418a1a3b679SAndreas Boehler if(is_null($id)) 419a1a3b679SAndreas Boehler { 420a1a3b679SAndreas Boehler global $ID; 421a1a3b679SAndreas Boehler $id = $ID; 422a1a3b679SAndreas Boehler } 423a1a3b679SAndreas Boehler if(is_null($userid)) 424*34a47953SAndreas Boehler { 425*34a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 426*34a47953SAndreas Boehler { 427a1a3b679SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 428*34a47953SAndreas Boehler } 429*34a47953SAndreas Boehler else 430*34a47953SAndreas Boehler { 431*34a47953SAndreas Boehler $userid = uniqid('davcal-'); 432*34a47953SAndreas Boehler } 433*34a47953SAndreas Boehler } 434a1a3b679SAndreas Boehler $values = array('principals/'.$userid, 435a1a3b679SAndreas Boehler $name, 436a1a3b679SAndreas Boehler str_replace(array('/', ' ', ':'), '_', $id), 437a1a3b679SAndreas Boehler $description, 438a1a3b679SAndreas Boehler 'VEVENT,VTODO', 43955a741c0SAndreas Boehler 0, 44055a741c0SAndreas Boehler 1); 44155a741c0SAndreas Boehler $query = "INSERT INTO calendars (principaluri, displayname, uri, description, components, transparent, synctoken) VALUES (".$this->sqlite->quote_and_join($values, ',').");"; 442a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 44355a741c0SAndreas Boehler if($res === false) 44455a741c0SAndreas Boehler return false; 445cb71a62aSAndreas Boehler 446cb71a62aSAndreas Boehler // Get the new calendar ID 447a1a3b679SAndreas Boehler $query = "SELECT id FROM calendars WHERE principaluri=".$this->sqlite->quote_string($values[0])." AND ". 448a1a3b679SAndreas Boehler "displayname=".$this->sqlite->quote_string($values[1])." AND ". 449a1a3b679SAndreas Boehler "uri=".$this->sqlite->quote_string($values[2])." AND ". 450a1a3b679SAndreas Boehler "description=".$this->sqlite->quote_string($values[3]); 451a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 452a1a3b679SAndreas Boehler $row = $this->sqlite->res2row($res); 453cb71a62aSAndreas Boehler 454cb71a62aSAndreas Boehler // Update the pagetocalendarmapping table with the new calendar ID 455a1a3b679SAndreas Boehler if(isset($row['id'])) 456a1a3b679SAndreas Boehler { 457a1a3b679SAndreas Boehler $values = array($id, $row['id']); 458a1a3b679SAndreas Boehler $query = "INSERT INTO pagetocalendarmapping (page, calid) VALUES (".$this->sqlite->quote_and_join($values, ',').")"; 459a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 46055a741c0SAndreas Boehler return ($res !== false); 461a1a3b679SAndreas Boehler } 462a1a3b679SAndreas Boehler 463a1a3b679SAndreas Boehler return false; 464a1a3b679SAndreas Boehler } 465a1a3b679SAndreas Boehler 466cb71a62aSAndreas Boehler /** 467cb71a62aSAndreas Boehler * Add a new iCal entry for a given page, i.e. a given calendar. 468cb71a62aSAndreas Boehler * 469cb71a62aSAndreas Boehler * The parameter array needs to contain 470cb71a62aSAndreas Boehler * timezone => The timezone of the entries 471cb71a62aSAndreas Boehler * detectedtz => The timezone as detected by the browser 472cb71a62aSAndreas Boehler * eventfrom => The event's start date 473cb71a62aSAndreas Boehler * eventfromtime => The event's start time 474cb71a62aSAndreas Boehler * eventto => The event's end date 475cb71a62aSAndreas Boehler * eventtotime => The event's end time 476cb71a62aSAndreas Boehler * eventname => The event's name 477cb71a62aSAndreas Boehler * eventdescription => The event's description 478cb71a62aSAndreas Boehler * 479cb71a62aSAndreas Boehler * @param string $id The page ID to work on 480cb71a62aSAndreas Boehler * @param string $user The user who created the calendar 481cb71a62aSAndreas Boehler * @param string $params A parameter array with values to create 482cb71a62aSAndreas Boehler * 483cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 484cb71a62aSAndreas Boehler */ 485a1a3b679SAndreas Boehler public function addCalendarEntryToCalendarForPage($id, $user, $params) 486a1a3b679SAndreas Boehler { 487bd883736SAndreas Boehler $settings = $this->getPersonalSettings($user); 488bd883736SAndreas Boehler if($settings['timezone'] !== '' && $settings['timezone'] !== 'local') 489bd883736SAndreas Boehler $timezone = new \DateTimeZone($settings['timezone']); 490a25c89eaSAndreas Boehler elseif($settings['timezone'] === 'local') 491a25c89eaSAndreas Boehler $timezone = new \DateTimeZone($params['detectedtz']); 492bd883736SAndreas Boehler else 493bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 494cb71a62aSAndreas Boehler 495cb71a62aSAndreas Boehler // Retrieve dates from settings 496b269830cSAndreas Boehler $startDate = explode('-', $params['eventfrom']); 497b269830cSAndreas Boehler $startTime = explode(':', $params['eventfromtime']); 498b269830cSAndreas Boehler $endDate = explode('-', $params['eventto']); 499b269830cSAndreas Boehler $endTime = explode(':', $params['eventtotime']); 500cb71a62aSAndreas Boehler 501cb71a62aSAndreas Boehler // Load SabreDAV 502a1a3b679SAndreas Boehler require_once('vendor/autoload.php'); 503a1a3b679SAndreas Boehler $vcalendar = new \Sabre\VObject\Component\VCalendar(); 504cb71a62aSAndreas Boehler 505cb71a62aSAndreas Boehler // Add VCalendar, UID and Event Name 506a1a3b679SAndreas Boehler $event = $vcalendar->add('VEVENT'); 507b269830cSAndreas Boehler $uuid = \Sabre\VObject\UUIDUtil::getUUID(); 508b269830cSAndreas Boehler $event->add('UID', $uuid); 509a1a3b679SAndreas Boehler $event->summary = $params['eventname']; 510cb71a62aSAndreas Boehler 511cb71a62aSAndreas Boehler // Add a description if requested 5120eebc909SAndreas Boehler $description = $params['eventdescription']; 5130eebc909SAndreas Boehler if($description !== '') 5140eebc909SAndreas Boehler $event->add('DESCRIPTION', $description); 515cb71a62aSAndreas Boehler 516cb71a62aSAndreas Boehler // Create a timestamp for last modified, created and dtstamp values in UTC 517b269830cSAndreas Boehler $dtStamp = new \DateTime(null, new \DateTimeZone('UTC')); 518b269830cSAndreas Boehler $event->add('DTSTAMP', $dtStamp); 519b269830cSAndreas Boehler $event->add('CREATED', $dtStamp); 520b269830cSAndreas Boehler $event->add('LAST-MODIFIED', $dtStamp); 521cb71a62aSAndreas Boehler 522cb71a62aSAndreas Boehler // Adjust the start date, based on the given timezone information 523b269830cSAndreas Boehler $dtStart = new \DateTime(); 524a25c89eaSAndreas Boehler $dtStart->setTimezone($timezone); 525b269830cSAndreas Boehler $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2])); 526cb71a62aSAndreas Boehler 527cb71a62aSAndreas Boehler // Only add the time values if it's not an allday event 528b269830cSAndreas Boehler if($params['allday'] != '1') 529b269830cSAndreas Boehler $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0); 530cb71a62aSAndreas Boehler 531cb71a62aSAndreas Boehler // Adjust the end date, based on the given timezone information 532b269830cSAndreas Boehler $dtEnd = new \DateTime(); 533a25c89eaSAndreas Boehler $dtEnd->setTimezone($timezone); 534b269830cSAndreas Boehler $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2])); 535cb71a62aSAndreas Boehler 536cb71a62aSAndreas Boehler // Only add the time values if it's not an allday event 537b269830cSAndreas Boehler if($params['allday'] != '1') 538b269830cSAndreas Boehler $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0); 539cb71a62aSAndreas Boehler 540b269830cSAndreas Boehler // According to the VCal spec, we need to add a whole day here 541b269830cSAndreas Boehler if($params['allday'] == '1') 542b269830cSAndreas Boehler $dtEnd->add(new \DateInterval('P1D')); 543cb71a62aSAndreas Boehler 544cb71a62aSAndreas Boehler // Really add Start and End events 545b269830cSAndreas Boehler $dtStartEv = $event->add('DTSTART', $dtStart); 546b269830cSAndreas Boehler $dtEndEv = $event->add('DTEND', $dtEnd); 547cb71a62aSAndreas Boehler 548cb71a62aSAndreas Boehler // Adjust the DATE format for allday events 549b269830cSAndreas Boehler if($params['allday'] == '1') 550b269830cSAndreas Boehler { 551b269830cSAndreas Boehler $dtStartEv['VALUE'] = 'DATE'; 552b269830cSAndreas Boehler $dtEndEv['VALUE'] = 'DATE'; 553b269830cSAndreas Boehler } 554cb71a62aSAndreas Boehler 555cb71a62aSAndreas Boehler // Actually add the values to the database 556a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 557a1a3b679SAndreas Boehler $uri = uniqid('dokuwiki-').'.ics'; 558a1a3b679SAndreas Boehler $now = new DateTime(); 559a1a3b679SAndreas Boehler $eventStr = $vcalendar->serialize(); 560a1a3b679SAndreas Boehler 561a1a3b679SAndreas Boehler $values = array($calid, 562a1a3b679SAndreas Boehler $uri, 563a1a3b679SAndreas Boehler $eventStr, 564a1a3b679SAndreas Boehler $now->getTimestamp(), 565a1a3b679SAndreas Boehler 'VEVENT', 566a1a3b679SAndreas Boehler $event->DTSTART->getDateTime()->getTimeStamp(), 567a1a3b679SAndreas Boehler $event->DTEND->getDateTime()->getTimeStamp(), 568a1a3b679SAndreas Boehler strlen($eventStr), 569a1a3b679SAndreas Boehler md5($eventStr), 570cb71a62aSAndreas Boehler $uuid 571a1a3b679SAndreas Boehler ); 572a1a3b679SAndreas Boehler 573a1a3b679SAndreas Boehler $query = "INSERT INTO calendarobjects (calendarid, uri, calendardata, lastmodified, componenttype, firstoccurence, lastoccurence, size, etag, uid) VALUES (".$this->sqlite->quote_and_join($values, ',').")"; 574a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 575cb71a62aSAndreas Boehler 576cb71a62aSAndreas Boehler // If successfully, update the sync token database 57755a741c0SAndreas Boehler if($res !== false) 57855a741c0SAndreas Boehler { 57955a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'added'); 580a1a3b679SAndreas Boehler return true; 581a1a3b679SAndreas Boehler } 58255a741c0SAndreas Boehler return false; 58355a741c0SAndreas Boehler } 584a1a3b679SAndreas Boehler 585cb71a62aSAndreas Boehler /** 586cb71a62aSAndreas Boehler * Retrieve the calendar settings of a given calendar id 587cb71a62aSAndreas Boehler * 588cb71a62aSAndreas Boehler * @param string $calid The calendar ID 589cb71a62aSAndreas Boehler * 590cb71a62aSAndreas Boehler * @return array The calendar settings array 591cb71a62aSAndreas Boehler */ 592b269830cSAndreas Boehler public function getCalendarSettings($calid) 593b269830cSAndreas Boehler { 594185e2535SAndreas Boehler $query = "SELECT principaluri, calendarcolor, displayname, uri, description, components, transparent, synctoken FROM calendars WHERE id=".$this->sqlite->quote_string($calid); 595b269830cSAndreas Boehler $res = $this->sqlite->query($query); 596b269830cSAndreas Boehler $row = $this->sqlite->res2row($res); 597b269830cSAndreas Boehler return $row; 598b269830cSAndreas Boehler } 599b269830cSAndreas Boehler 600cb71a62aSAndreas Boehler /** 601cb71a62aSAndreas Boehler * Retrieve all events that are within a given date range, 602cb71a62aSAndreas Boehler * based on the timezone setting. 603cb71a62aSAndreas Boehler * 604cb71a62aSAndreas Boehler * There is also support for retrieving recurring events, 605cb71a62aSAndreas Boehler * using Sabre's VObject Iterator. Recurring events are represented 606cb71a62aSAndreas Boehler * as individual calendar entries with the same UID. 607cb71a62aSAndreas Boehler * 608cb71a62aSAndreas Boehler * @param string $id The page ID to work with 609cb71a62aSAndreas Boehler * @param string $user The user ID to work with 610cb71a62aSAndreas Boehler * @param string $startDate The start date as a string 611cb71a62aSAndreas Boehler * @param string $endDate The end date as a string 612cb71a62aSAndreas Boehler * 613cb71a62aSAndreas Boehler * @return array An array containing the calendar entries. 614cb71a62aSAndreas Boehler */ 615a1a3b679SAndreas Boehler public function getEventsWithinDateRange($id, $user, $startDate, $endDate) 616a1a3b679SAndreas Boehler { 617bd883736SAndreas Boehler $settings = $this->getPersonalSettings($user); 618bd883736SAndreas Boehler if($settings['timezone'] !== '' && $settings['timezone'] !== 'local') 619bd883736SAndreas Boehler $timezone = new \DateTimeZone($settings['timezone']); 620bd883736SAndreas Boehler else 621bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 622a1a3b679SAndreas Boehler $data = array(); 623cb71a62aSAndreas Boehler 624cb71a62aSAndreas Boehler // Load SabreDAV 625a1a3b679SAndreas Boehler require_once('vendor/autoload.php'); 626a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 627185e2535SAndreas Boehler $color = $this->getCalendarColorForCalendar($calid); 628a1a3b679SAndreas Boehler $startTs = new \DateTime($startDate); 629a1a3b679SAndreas Boehler $endTs = new \DateTime($endDate); 630cb71a62aSAndreas Boehler 631cb71a62aSAndreas Boehler // Retrieve matching calendar objects 632ebc4eb57SAndreas Boehler $query = "SELECT calendardata, componenttype, uid FROM calendarobjects WHERE calendarid=". 633ebc4eb57SAndreas Boehler $this->sqlite->quote_string($calid)." AND firstoccurence < ". 634ebc4eb57SAndreas Boehler $this->sqlite->quote_string($endTs->getTimestamp())." AND lastoccurence > ". 635ebc4eb57SAndreas Boehler $this->sqlite->quote_string($startTs->getTimestamp()); 636a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 637a1a3b679SAndreas Boehler $arr = $this->sqlite->res2arr($res); 638cb71a62aSAndreas Boehler 639cb71a62aSAndreas Boehler // Parse individual calendar entries 640a1a3b679SAndreas Boehler foreach($arr as $row) 641a1a3b679SAndreas Boehler { 642a1a3b679SAndreas Boehler if(isset($row['calendardata'])) 643a1a3b679SAndreas Boehler { 644b269830cSAndreas Boehler $entry = array(); 645a1a3b679SAndreas Boehler $vcal = \Sabre\VObject\Reader::read($row['calendardata']); 646ebc4eb57SAndreas Boehler $recurrence = $vcal->VEVENT->RRULE; 647cb71a62aSAndreas Boehler // If it is a recurring event, pass it through Sabre's EventIterator 648ebc4eb57SAndreas Boehler if($recurrence != null) 649ebc4eb57SAndreas Boehler { 650ebc4eb57SAndreas Boehler $rEvents = new \Sabre\VObject\Recur\EventIterator(array($vcal->VEVENT)); 651ebc4eb57SAndreas Boehler $rEvents->rewind(); 652ebc4eb57SAndreas Boehler $done = false; 653ebc4eb57SAndreas Boehler while($rEvents->valid() && !$done) 654ebc4eb57SAndreas Boehler { 655ebc4eb57SAndreas Boehler $event = $rEvents->getEventObject(); 656cb71a62aSAndreas Boehler // If we are after the given time range, exit 657ebc4eb57SAndreas Boehler if(($rEvents->getDtStart()->getTimestamp() > $endTs->getTimestamp()) && 658ebc4eb57SAndreas Boehler ($rEvents->getDtEnd()->getTimestamp() > $endTs->getTimestamp())) 659ebc4eb57SAndreas Boehler $done = true; 660cb71a62aSAndreas Boehler 661cb71a62aSAndreas Boehler // If we are before the given time range, continue 662ebc4eb57SAndreas Boehler if($rEvents->getDtEnd()->getTimestamp() < $startTs->getTimestamp()) 663ebc4eb57SAndreas Boehler { 664ebc4eb57SAndreas Boehler $rEvents->next(); 665ebc4eb57SAndreas Boehler continue; 666ebc4eb57SAndreas Boehler } 667cb71a62aSAndreas Boehler 668cb71a62aSAndreas Boehler // If we are within the given time range, parse the event 669185e2535SAndreas Boehler $data[] = $this->convertIcalDataToEntry($event, $id, $timezone, $row['uid'], $color, true); 670ebc4eb57SAndreas Boehler $rEvents->next(); 671ebc4eb57SAndreas Boehler } 672ebc4eb57SAndreas Boehler } 673ebc4eb57SAndreas Boehler else 674185e2535SAndreas Boehler $data[] = $this->convertIcalDataToEntry($vcal->VEVENT, $id, $timezone, $row['uid'], $color); 675ebc4eb57SAndreas Boehler } 676ebc4eb57SAndreas Boehler } 677ebc4eb57SAndreas Boehler return $data; 678ebc4eb57SAndreas Boehler } 679ebc4eb57SAndreas Boehler 680cb71a62aSAndreas Boehler /** 681cb71a62aSAndreas Boehler * Helper function that parses the iCal data of a VEVENT to a calendar entry. 682cb71a62aSAndreas Boehler * 683cb71a62aSAndreas Boehler * @param \Sabre\VObject\VEvent $event The event to parse 684cb71a62aSAndreas Boehler * @param \DateTimeZone $timezone The timezone object 685cb71a62aSAndreas Boehler * @param string $uid The entry's UID 6863c86dda8SAndreas Boehler * @param boolean $recurring (optional) Set to true to define a recurring event 687cb71a62aSAndreas Boehler * 688cb71a62aSAndreas Boehler * @return array The parse calendar entry 689cb71a62aSAndreas Boehler */ 690185e2535SAndreas Boehler private function convertIcalDataToEntry($event, $page, $timezone, $uid, $color, $recurring = false) 691ebc4eb57SAndreas Boehler { 692ebc4eb57SAndreas Boehler $entry = array(); 693ebc4eb57SAndreas Boehler $start = $event->DTSTART; 694cb71a62aSAndreas Boehler // Parse only if the start date/time is present 695b269830cSAndreas Boehler if($start !== null) 696b269830cSAndreas Boehler { 697b269830cSAndreas Boehler $dtStart = $start->getDateTime(); 698b269830cSAndreas Boehler $dtStart->setTimezone($timezone); 699b269830cSAndreas Boehler $entry['start'] = $dtStart->format(\DateTime::ATOM); 700b269830cSAndreas Boehler if($start['VALUE'] == 'DATE') 701b269830cSAndreas Boehler $entry['allDay'] = true; 702b269830cSAndreas Boehler else 703b269830cSAndreas Boehler $entry['allDay'] = false; 704b269830cSAndreas Boehler } 705ebc4eb57SAndreas Boehler $end = $event->DTEND; 706cb71a62aSAndreas Boehler // Parse onlyl if the end date/time is present 707b269830cSAndreas Boehler if($end !== null) 708b269830cSAndreas Boehler { 709b269830cSAndreas Boehler $dtEnd = $end->getDateTime(); 710b269830cSAndreas Boehler $dtEnd->setTimezone($timezone); 711b269830cSAndreas Boehler $entry['end'] = $dtEnd->format(\DateTime::ATOM); 712b269830cSAndreas Boehler } 713ebc4eb57SAndreas Boehler $description = $event->DESCRIPTION; 7140eebc909SAndreas Boehler if($description !== null) 7150eebc909SAndreas Boehler $entry['description'] = (string)$description; 7160eebc909SAndreas Boehler else 7170eebc909SAndreas Boehler $entry['description'] = ''; 718ebc4eb57SAndreas Boehler $entry['title'] = (string)$event->summary; 719ebc4eb57SAndreas Boehler $entry['id'] = $uid; 720185e2535SAndreas Boehler $entry['page'] = $page; 721185e2535SAndreas Boehler $entry['color'] = $color; 7223c86dda8SAndreas Boehler $entry['recurring'] = $recurring; 723185e2535SAndreas Boehler 724ebc4eb57SAndreas Boehler return $entry; 725a1a3b679SAndreas Boehler } 726a1a3b679SAndreas Boehler 727cb71a62aSAndreas Boehler /** 728cb71a62aSAndreas Boehler * Retrieve an event by its UID 729cb71a62aSAndreas Boehler * 730cb71a62aSAndreas Boehler * @param string $uid The event's UID 731cb71a62aSAndreas Boehler * 732cb71a62aSAndreas Boehler * @return mixed The table row with the given event 733cb71a62aSAndreas Boehler */ 734a1a3b679SAndreas Boehler public function getEventWithUid($uid) 735a1a3b679SAndreas Boehler { 73655a741c0SAndreas Boehler $query = "SELECT calendardata, calendarid, componenttype, uri FROM calendarobjects WHERE uid=". 737a1a3b679SAndreas Boehler $this->sqlite->quote_string($uid); 738a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 739a1a3b679SAndreas Boehler $row = $this->sqlite->res2row($res); 740a1a3b679SAndreas Boehler return $row; 741a1a3b679SAndreas Boehler } 742a1a3b679SAndreas Boehler 743cb71a62aSAndreas Boehler /** 744cb71a62aSAndreas Boehler * Retrieve all calendar events for a given calendar ID 745cb71a62aSAndreas Boehler * 746cb71a62aSAndreas Boehler * @param string $calid The calendar's ID 747cb71a62aSAndreas Boehler * 748cb71a62aSAndreas Boehler * @return array An array containing all calendar data 749cb71a62aSAndreas Boehler */ 750f69bb449SAndreas Boehler public function getAllCalendarEvents($calid) 751f69bb449SAndreas Boehler { 752f69bb449SAndreas Boehler $query = "SELECT calendardata, uid, componenttype, uri FROM calendarobjects WHERE calendarid=". 753f69bb449SAndreas Boehler $this->sqlite->quote_string($calid); 754f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 755f69bb449SAndreas Boehler $arr = $this->sqlite->res2arr($res); 756f69bb449SAndreas Boehler return $arr; 757f69bb449SAndreas Boehler } 758f69bb449SAndreas Boehler 759cb71a62aSAndreas Boehler /** 760cb71a62aSAndreas Boehler * Edit a calendar entry for a page, given by its parameters. 761cb71a62aSAndreas Boehler * The params array has the same format as @see addCalendarEntryForPage 762cb71a62aSAndreas Boehler * 763cb71a62aSAndreas Boehler * @param string $id The page's ID to work on 764cb71a62aSAndreas Boehler * @param string $user The user's ID to work on 765cb71a62aSAndreas Boehler * @param array $params The parameter array for the edited calendar event 766cb71a62aSAndreas Boehler * 767cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 768cb71a62aSAndreas Boehler */ 769a1a3b679SAndreas Boehler public function editCalendarEntryForPage($id, $user, $params) 770a1a3b679SAndreas Boehler { 771bd883736SAndreas Boehler $settings = $this->getPersonalSettings($user); 772bd883736SAndreas Boehler if($settings['timezone'] !== '' && $settings['timezone'] !== 'local') 773bd883736SAndreas Boehler $timezone = new \DateTimeZone($settings['timezone']); 774a25c89eaSAndreas Boehler elseif($settings['timezone'] === 'local') 775a25c89eaSAndreas Boehler $timezone = new \DateTimeZone($params['detectedtz']); 776bd883736SAndreas Boehler else 777bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 778cb71a62aSAndreas Boehler 779cb71a62aSAndreas Boehler // Parse dates 780b269830cSAndreas Boehler $startDate = explode('-', $params['eventfrom']); 781b269830cSAndreas Boehler $startTime = explode(':', $params['eventfromtime']); 782b269830cSAndreas Boehler $endDate = explode('-', $params['eventto']); 783b269830cSAndreas Boehler $endTime = explode(':', $params['eventtotime']); 784cb71a62aSAndreas Boehler 785cb71a62aSAndreas Boehler // Retrieve the existing event based on the UID 78655a741c0SAndreas Boehler $uid = $params['uid']; 78755a741c0SAndreas Boehler $event = $this->getEventWithUid($uid); 788cb71a62aSAndreas Boehler 789cb71a62aSAndreas Boehler // Load SabreDAV 790a1a3b679SAndreas Boehler require_once('vendor/autoload.php'); 791a1a3b679SAndreas Boehler if(!isset($event['calendardata'])) 792a1a3b679SAndreas Boehler return false; 79355a741c0SAndreas Boehler $uri = $event['uri']; 79455a741c0SAndreas Boehler $calid = $event['calendarid']; 795cb71a62aSAndreas Boehler 796cb71a62aSAndreas Boehler // Parse the existing event 797a1a3b679SAndreas Boehler $vcal = \Sabre\VObject\Reader::read($event['calendardata']); 798b269830cSAndreas Boehler $vevent = $vcal->VEVENT; 799cb71a62aSAndreas Boehler 800cb71a62aSAndreas Boehler // Set the new event values 801b269830cSAndreas Boehler $vevent->summary = $params['eventname']; 802b269830cSAndreas Boehler $dtStamp = new \DateTime(null, new \DateTimeZone('UTC')); 8030eebc909SAndreas Boehler $description = $params['eventdescription']; 804cb71a62aSAndreas Boehler 805cb71a62aSAndreas Boehler // Remove existing timestamps to overwrite them 8060eebc909SAndreas Boehler $vevent->remove('DESCRIPTION'); 807b269830cSAndreas Boehler $vevent->remove('DTSTAMP'); 808b269830cSAndreas Boehler $vevent->remove('LAST-MODIFIED'); 809cb71a62aSAndreas Boehler 810cb71a62aSAndreas Boehler // Add new time stamps and description 811b269830cSAndreas Boehler $vevent->add('DTSTAMP', $dtStamp); 812b269830cSAndreas Boehler $vevent->add('LAST-MODIFIED', $dtStamp); 8130eebc909SAndreas Boehler if($description !== '') 8140eebc909SAndreas Boehler $vevent->add('DESCRIPTION', $description); 815cb71a62aSAndreas Boehler 816cb71a62aSAndreas Boehler // Setup DTSTART 817b269830cSAndreas Boehler $dtStart = new \DateTime(); 818a25c89eaSAndreas Boehler $dtStart->setTimezone($timezone); 819b269830cSAndreas Boehler $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2])); 820b269830cSAndreas Boehler if($params['allday'] != '1') 821b269830cSAndreas Boehler $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0); 822cb71a62aSAndreas Boehler 823cb71a62aSAndreas Boehler // Setup DETEND 824b269830cSAndreas Boehler $dtEnd = new \DateTime(); 825a25c89eaSAndreas Boehler $dtEnd->setTimezone($timezone); 826b269830cSAndreas Boehler $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2])); 827b269830cSAndreas Boehler if($params['allday'] != '1') 828b269830cSAndreas Boehler $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0); 829cb71a62aSAndreas Boehler 830b269830cSAndreas Boehler // According to the VCal spec, we need to add a whole day here 831b269830cSAndreas Boehler if($params['allday'] == '1') 832b269830cSAndreas Boehler $dtEnd->add(new \DateInterval('P1D')); 833b269830cSAndreas Boehler $vevent->remove('DTSTART'); 834b269830cSAndreas Boehler $vevent->remove('DTEND'); 835b269830cSAndreas Boehler $dtStartEv = $vevent->add('DTSTART', $dtStart); 836b269830cSAndreas Boehler $dtEndEv = $vevent->add('DTEND', $dtEnd); 837cb71a62aSAndreas Boehler 838cb71a62aSAndreas Boehler // Remove the time for allday events 839b269830cSAndreas Boehler if($params['allday'] == '1') 840b269830cSAndreas Boehler { 841b269830cSAndreas Boehler $dtStartEv['VALUE'] = 'DATE'; 842b269830cSAndreas Boehler $dtEndEv['VALUE'] = 'DATE'; 843b269830cSAndreas Boehler } 844a1a3b679SAndreas Boehler $now = new DateTime(); 845a1a3b679SAndreas Boehler $eventStr = $vcal->serialize(); 846a1a3b679SAndreas Boehler 847cb71a62aSAndreas Boehler // Actually write to the database 848a1a3b679SAndreas Boehler $query = "UPDATE calendarobjects SET calendardata=".$this->sqlite->quote_string($eventStr). 849a1a3b679SAndreas Boehler ", lastmodified=".$this->sqlite->quote_string($now->getTimestamp()). 850a1a3b679SAndreas Boehler ", firstoccurence=".$this->sqlite->quote_string($dtStart->getTimestamp()). 851a1a3b679SAndreas Boehler ", lastoccurence=".$this->sqlite->quote_string($dtEnd->getTimestamp()). 852a1a3b679SAndreas Boehler ", size=".strlen($eventStr). 853a1a3b679SAndreas Boehler ", etag=".$this->sqlite->quote_string(md5($eventStr)). 85455a741c0SAndreas Boehler " WHERE uid=".$this->sqlite->quote_string($uid); 855a1a3b679SAndreas Boehler $res = $this->sqlite->query($query); 85655a741c0SAndreas Boehler if($res !== false) 85755a741c0SAndreas Boehler { 85855a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'modified'); 859a1a3b679SAndreas Boehler return true; 860a1a3b679SAndreas Boehler } 86155a741c0SAndreas Boehler return false; 86255a741c0SAndreas Boehler } 863a1a3b679SAndreas Boehler 864cb71a62aSAndreas Boehler /** 865cb71a62aSAndreas Boehler * Delete a calendar entry for a given page. Actually, the event is removed 866cb71a62aSAndreas Boehler * based on the entry's UID, so that page ID is no used. 867cb71a62aSAndreas Boehler * 868cb71a62aSAndreas Boehler * @param string $id The page's ID (unused) 869cb71a62aSAndreas Boehler * @param array $params The parameter array to work with 870cb71a62aSAndreas Boehler * 871cb71a62aSAndreas Boehler * @return boolean True 872cb71a62aSAndreas Boehler */ 873a1a3b679SAndreas Boehler public function deleteCalendarEntryForPage($id, $params) 874a1a3b679SAndreas Boehler { 875a1a3b679SAndreas Boehler $uid = $params['uid']; 87655a741c0SAndreas Boehler $event = $this->getEventWithUid($uid); 8772c14b82bSAndreas Boehler $calid = $event['calendarid']; 87855a741c0SAndreas Boehler $uri = $event['uri']; 879a1a3b679SAndreas Boehler $query = "DELETE FROM calendarobjects 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, 'deleted'); 88455a741c0SAndreas Boehler } 885a1a3b679SAndreas Boehler return true; 886a1a3b679SAndreas Boehler } 887a1a3b679SAndreas Boehler 888cb71a62aSAndreas Boehler /** 889cb71a62aSAndreas Boehler * Retrieve the current sync token for a calendar 890cb71a62aSAndreas Boehler * 891cb71a62aSAndreas Boehler * @param string $calid The calendar id 892cb71a62aSAndreas Boehler * 893cb71a62aSAndreas Boehler * @return mixed The synctoken or false 894cb71a62aSAndreas Boehler */ 89555a741c0SAndreas Boehler public function getSyncTokenForCalendar($calid) 89655a741c0SAndreas Boehler { 897b269830cSAndreas Boehler $row = $this->getCalendarSettings($calid); 89855a741c0SAndreas Boehler if(isset($row['synctoken'])) 89955a741c0SAndreas Boehler return $row['synctoken']; 90055a741c0SAndreas Boehler return false; 90155a741c0SAndreas Boehler } 90255a741c0SAndreas Boehler 903cb71a62aSAndreas Boehler /** 904cb71a62aSAndreas Boehler * Helper function to convert the operation name to 905cb71a62aSAndreas Boehler * an operation code as stored in the database 906cb71a62aSAndreas Boehler * 907cb71a62aSAndreas Boehler * @param string $operationName The operation name 908cb71a62aSAndreas Boehler * 909cb71a62aSAndreas Boehler * @return mixed The operation code or false 910cb71a62aSAndreas Boehler */ 91155a741c0SAndreas Boehler public function operationNameToOperation($operationName) 91255a741c0SAndreas Boehler { 91355a741c0SAndreas Boehler switch($operationName) 91455a741c0SAndreas Boehler { 91555a741c0SAndreas Boehler case 'added': 91655a741c0SAndreas Boehler return 1; 91755a741c0SAndreas Boehler break; 91855a741c0SAndreas Boehler case 'modified': 91955a741c0SAndreas Boehler return 2; 92055a741c0SAndreas Boehler break; 92155a741c0SAndreas Boehler case 'deleted': 92255a741c0SAndreas Boehler return 3; 92355a741c0SAndreas Boehler break; 92455a741c0SAndreas Boehler } 92555a741c0SAndreas Boehler return false; 92655a741c0SAndreas Boehler } 92755a741c0SAndreas Boehler 928cb71a62aSAndreas Boehler /** 929cb71a62aSAndreas Boehler * Update the sync token log based on the calendar id and the 930cb71a62aSAndreas Boehler * operation that was performed. 931cb71a62aSAndreas Boehler * 932cb71a62aSAndreas Boehler * @param string $calid The calendar ID that was modified 933cb71a62aSAndreas Boehler * @param string $uri The calendar URI that was modified 934cb71a62aSAndreas Boehler * @param string $operation The operation that was performed 935cb71a62aSAndreas Boehler * 936cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 937cb71a62aSAndreas Boehler */ 93855a741c0SAndreas Boehler private function updateSyncTokenLog($calid, $uri, $operation) 93955a741c0SAndreas Boehler { 94055a741c0SAndreas Boehler $currentToken = $this->getSyncTokenForCalendar($calid); 94155a741c0SAndreas Boehler $operationCode = $this->operationNameToOperation($operation); 94255a741c0SAndreas Boehler if(($operationCode === false) || ($currentToken === false)) 94355a741c0SAndreas Boehler return false; 94455a741c0SAndreas Boehler $values = array($uri, 94555a741c0SAndreas Boehler $currentToken, 94655a741c0SAndreas Boehler $calid, 94755a741c0SAndreas Boehler $operationCode 94855a741c0SAndreas Boehler ); 94955a741c0SAndreas Boehler $query = "INSERT INTO calendarchanges (uri, synctoken, calendarid, operation) VALUES(". 95055a741c0SAndreas Boehler $this->sqlite->quote_and_join($values, ',').")"; 95155a741c0SAndreas Boehler $res = $this->sqlite->query($query); 95255a741c0SAndreas Boehler if($res === false) 95355a741c0SAndreas Boehler return false; 95455a741c0SAndreas Boehler $currentToken++; 95555a741c0SAndreas Boehler $query = "UPDATE calendars SET synctoken=".$this->sqlite->quote_string($currentToken)." WHERE id=". 95655a741c0SAndreas Boehler $this->sqlite->quote_string($calid); 95755a741c0SAndreas Boehler $res = $this->sqlite->query($query); 95855a741c0SAndreas Boehler return ($res !== false); 95955a741c0SAndreas Boehler } 96055a741c0SAndreas Boehler 961cb71a62aSAndreas Boehler /** 962cb71a62aSAndreas Boehler * Return the sync URL for a given Page, i.e. a calendar 963cb71a62aSAndreas Boehler * 964cb71a62aSAndreas Boehler * @param string $id The page's ID 965cb71a62aSAndreas Boehler * @param string $user (optional) The user's ID 966cb71a62aSAndreas Boehler * 967cb71a62aSAndreas Boehler * @return mixed The sync url or false 968cb71a62aSAndreas Boehler */ 969b269830cSAndreas Boehler public function getSyncUrlForPage($id, $user = null) 970b269830cSAndreas Boehler { 971*34a47953SAndreas Boehler if(is_null($userid)) 972*34a47953SAndreas Boehler { 973*34a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 974*34a47953SAndreas Boehler { 975*34a47953SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 976*34a47953SAndreas Boehler } 977*34a47953SAndreas Boehler else 978*34a47953SAndreas Boehler { 979*34a47953SAndreas Boehler return false; 980*34a47953SAndreas Boehler } 981*34a47953SAndreas Boehler } 982b269830cSAndreas Boehler 983b269830cSAndreas Boehler $calid = $this->getCalendarIdForPage($id); 984b269830cSAndreas Boehler if($calid === false) 985b269830cSAndreas Boehler return false; 986b269830cSAndreas Boehler 987b269830cSAndreas Boehler $calsettings = $this->getCalendarSettings($calid); 988b269830cSAndreas Boehler if(!isset($calsettings['uri'])) 989b269830cSAndreas Boehler return false; 990b269830cSAndreas Boehler 991b269830cSAndreas Boehler $syncurl = DOKU_URL.'lib/plugins/davcal/calendarserver.php/calendars/'.$user.'/'.$calsettings['uri']; 992b269830cSAndreas Boehler return $syncurl; 993b269830cSAndreas Boehler } 994b269830cSAndreas Boehler 995cb71a62aSAndreas Boehler /** 996cb71a62aSAndreas Boehler * Return the private calendar's URL for a given page 997cb71a62aSAndreas Boehler * 998cb71a62aSAndreas Boehler * @param string $id the page ID 999cb71a62aSAndreas Boehler * 1000cb71a62aSAndreas Boehler * @return mixed The private URL or false 1001cb71a62aSAndreas Boehler */ 1002f69bb449SAndreas Boehler public function getPrivateURLForPage($id) 1003f69bb449SAndreas Boehler { 1004f69bb449SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 1005f69bb449SAndreas Boehler if($calid === false) 1006f69bb449SAndreas Boehler return false; 1007f69bb449SAndreas Boehler 1008f69bb449SAndreas Boehler return $this->getPrivateURLForCalendar($calid); 1009f69bb449SAndreas Boehler } 1010f69bb449SAndreas Boehler 1011cb71a62aSAndreas Boehler /** 1012cb71a62aSAndreas Boehler * Return the private calendar's URL for a given calendar ID 1013cb71a62aSAndreas Boehler * 1014cb71a62aSAndreas Boehler * @param string $calid The calendar's ID 1015cb71a62aSAndreas Boehler * 1016cb71a62aSAndreas Boehler * @return mixed The private URL or false 1017cb71a62aSAndreas Boehler */ 1018f69bb449SAndreas Boehler public function getPrivateURLForCalendar($calid) 1019f69bb449SAndreas Boehler { 1020185e2535SAndreas Boehler if(isset($this->cachedValues['privateurl'][$calid])) 1021185e2535SAndreas Boehler return $this->cachedValues['privateurl'][$calid]; 1022f69bb449SAndreas Boehler $query = "SELECT url FROM calendartoprivateurlmapping WHERE calid=".$this->sqlite->quote_string($calid); 1023f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 1024f69bb449SAndreas Boehler $row = $this->sqlite->res2row($res); 1025f69bb449SAndreas Boehler if(!isset($row['url'])) 1026f69bb449SAndreas Boehler { 1027f69bb449SAndreas Boehler $url = uniqid("dokuwiki-").".ics"; 1028f69bb449SAndreas Boehler $values = array( 1029f69bb449SAndreas Boehler $url, 1030f69bb449SAndreas Boehler $calid 1031f69bb449SAndreas Boehler ); 1032f69bb449SAndreas Boehler $query = "INSERT INTO calendartoprivateurlmapping (url, calid) VALUES(". 1033f69bb449SAndreas Boehler $this->sqlite->quote_and_join($values, ", ").")"; 1034f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 1035f69bb449SAndreas Boehler if($res === false) 1036f69bb449SAndreas Boehler return false; 1037f69bb449SAndreas Boehler } 1038f69bb449SAndreas Boehler else 1039f69bb449SAndreas Boehler { 1040f69bb449SAndreas Boehler $url = $row['url']; 1041f69bb449SAndreas Boehler } 1042185e2535SAndreas Boehler 1043185e2535SAndreas Boehler $url = DOKU_URL.'lib/plugins/davcal/ics.php/'.$url; 1044185e2535SAndreas Boehler $this->cachedValues['privateurl'][$calid] = $url; 1045185e2535SAndreas Boehler return $url; 1046f69bb449SAndreas Boehler } 1047f69bb449SAndreas Boehler 1048cb71a62aSAndreas Boehler /** 1049cb71a62aSAndreas Boehler * Retrieve the calendar ID for a given private calendar URL 1050cb71a62aSAndreas Boehler * 1051cb71a62aSAndreas Boehler * @param string $url The private URL 1052cb71a62aSAndreas Boehler * 1053cb71a62aSAndreas Boehler * @return mixed The calendar ID or false 1054cb71a62aSAndreas Boehler */ 1055f69bb449SAndreas Boehler public function getCalendarForPrivateURL($url) 1056f69bb449SAndreas Boehler { 1057f69bb449SAndreas Boehler $query = "SELECT calid FROM calendartoprivateurlmapping WHERE url=".$this->sqlite->quote_string($url); 1058f69bb449SAndreas Boehler $res = $this->sqlite->query($query); 1059f69bb449SAndreas Boehler $row = $this->sqlite->res2row($res); 1060f69bb449SAndreas Boehler if(!isset($row['calid'])) 1061f69bb449SAndreas Boehler return false; 1062f69bb449SAndreas Boehler return $row['calid']; 1063f69bb449SAndreas Boehler } 1064f69bb449SAndreas Boehler 1065cb71a62aSAndreas Boehler /** 1066cb71a62aSAndreas Boehler * Return a given calendar as ICS feed, i.e. all events in one ICS file. 1067cb71a62aSAndreas Boehler * 1068cb71a62aSAndreas Boehler * @param string $caldi The calendar ID to retrieve 1069cb71a62aSAndreas Boehler * 1070cb71a62aSAndreas Boehler * @return mixed The calendar events as string or false 1071cb71a62aSAndreas Boehler */ 1072f69bb449SAndreas Boehler public function getCalendarAsICSFeed($calid) 1073f69bb449SAndreas Boehler { 1074f69bb449SAndreas Boehler $calSettings = $this->getCalendarSettings($calid); 1075f69bb449SAndreas Boehler if($calSettings === false) 1076f69bb449SAndreas Boehler return false; 1077f69bb449SAndreas Boehler $events = $this->getAllCalendarEvents($calid); 1078f69bb449SAndreas Boehler if($events === false) 1079f69bb449SAndreas Boehler return false; 1080f69bb449SAndreas Boehler 1081f69bb449SAndreas Boehler $out = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//DAVCal//DAVCal for DokuWiki//EN\nCALSCALE:GREGORIAN\nX-WR-CALNAME:"; 1082f69bb449SAndreas Boehler $out .= $calSettings['displayname']."\n"; 1083f69bb449SAndreas Boehler foreach($events as $event) 1084f69bb449SAndreas Boehler { 1085f69bb449SAndreas Boehler $out .= rtrim($event['calendardata']); 1086f69bb449SAndreas Boehler $out .= "\n"; 1087f69bb449SAndreas Boehler } 1088f69bb449SAndreas Boehler $out .= "END:VCALENDAR\n"; 1089f69bb449SAndreas Boehler return $out; 1090f69bb449SAndreas Boehler } 1091f69bb449SAndreas Boehler 1092a1a3b679SAndreas Boehler} 1093