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() { 2021d04f73SAndreas Boehler dbglog('---- DAVCAL helper.php init'); 215f2c3e2dSAndreas Boehler } 225f2c3e2dSAndreas Boehler 235f2c3e2dSAndreas Boehler /** Establish and initialize the database if not already done 245f2c3e2dSAndreas Boehler * @return sqlite interface or false 255f2c3e2dSAndreas Boehler */ 265f2c3e2dSAndreas Boehler private function getDB() 275f2c3e2dSAndreas Boehler { 285f2c3e2dSAndreas Boehler if($this->sqlite === null) 295f2c3e2dSAndreas Boehler { 305f2c3e2dSAndreas Boehler $this->sqlite = plugin_load('helper', 'sqlite'); 31a1a3b679SAndreas Boehler if(!$this->sqlite) 32a1a3b679SAndreas Boehler { 3321d04f73SAndreas Boehler dbglog('This plugin requires the sqlite plugin. Please install it.'); 345f2c3e2dSAndreas Boehler msg('This plugin requires the sqlite plugin. Please install it.', -1); 355f2c3e2dSAndreas Boehler return false; 36a1a3b679SAndreas Boehler } 37a1a3b679SAndreas Boehler if(!$this->sqlite->init('davcal', DOKU_PLUGIN.'davcal/db/')) 38a1a3b679SAndreas Boehler { 395f2c3e2dSAndreas Boehler $this->sqlite = null; 4021d04f73SAndreas Boehler dbglog('Error initialising the SQLite DB for DAVCal'); 415f2c3e2dSAndreas Boehler return false; 42a1a3b679SAndreas Boehler } 43a1a3b679SAndreas Boehler } 445f2c3e2dSAndreas Boehler return $this->sqlite; 455f2c3e2dSAndreas Boehler } 46a1a3b679SAndreas Boehler 47cb71a62aSAndreas Boehler /** 48185e2535SAndreas Boehler * Retrieve meta data for a given page 49185e2535SAndreas Boehler * 50185e2535SAndreas Boehler * @param string $id optional The page ID 51185e2535SAndreas Boehler * @return array The metadata 52185e2535SAndreas Boehler */ 53185e2535SAndreas Boehler private function getMeta($id = null) { 54185e2535SAndreas Boehler global $ID; 55185e2535SAndreas Boehler global $INFO; 56185e2535SAndreas Boehler 57185e2535SAndreas Boehler if ($id === null) $id = $ID; 58185e2535SAndreas Boehler 59185e2535SAndreas Boehler if($ID === $id && $INFO['meta']) { 60185e2535SAndreas Boehler $meta = $INFO['meta']; 61185e2535SAndreas Boehler } else { 62185e2535SAndreas Boehler $meta = p_get_metadata($id); 63185e2535SAndreas Boehler } 64185e2535SAndreas Boehler 65185e2535SAndreas Boehler return $meta; 66185e2535SAndreas Boehler } 67185e2535SAndreas Boehler 68185e2535SAndreas Boehler /** 69185e2535SAndreas Boehler * Retrieve the meta data for a given page 70185e2535SAndreas Boehler * 71185e2535SAndreas Boehler * @param string $id optional The page ID 72185e2535SAndreas Boehler * @return array with meta data 73185e2535SAndreas Boehler */ 74185e2535SAndreas Boehler public function getCalendarMetaForPage($id = null) 75185e2535SAndreas Boehler { 76185e2535SAndreas Boehler if(is_null($id)) 77185e2535SAndreas Boehler { 78185e2535SAndreas Boehler global $ID; 79185e2535SAndreas Boehler $id = $ID; 80185e2535SAndreas Boehler } 81185e2535SAndreas Boehler 82185e2535SAndreas Boehler $meta = $this->getMeta($id); 83185e2535SAndreas Boehler if(isset($meta['plugin_davcal'])) 84185e2535SAndreas Boehler return $meta['plugin_davcal']; 85185e2535SAndreas Boehler else 86185e2535SAndreas Boehler return array(); 87185e2535SAndreas Boehler } 88185e2535SAndreas Boehler 89185e2535SAndreas Boehler /** 90d71c9934SAndreas Boehler * Check the permission of a user for a given calendar ID 91d71c9934SAndreas Boehler * 92d71c9934SAndreas Boehler * @param string $id The calendar ID to check 93d71c9934SAndreas Boehler * @return int AUTH_* constants 94d71c9934SAndreas Boehler */ 95d71c9934SAndreas Boehler public function checkCalendarPermission($id) 96d71c9934SAndreas Boehler { 97*d4992453SAndreas Boehler if(strpos($id, 'webdav://') === 0) 98d71c9934SAndreas Boehler { 99d71c9934SAndreas Boehler $wdc =& plugin_load('helper', 'webdavclient'); 100d71c9934SAndreas Boehler if(is_null($wdc)) 101d71c9934SAndreas Boehler return AUTH_NONE; 102*d4992453SAndreas Boehler $connectionId = str_replace('webdav://', '', $id); 103d71c9934SAndreas Boehler $settings = $wdc->getConnection($connectionId); 104d71c9934SAndreas Boehler if($settings === false) 105d71c9934SAndreas Boehler return AUTH_NONE; 106d71c9934SAndreas Boehler if($settings['write'] === '1') 107d71c9934SAndreas Boehler return AUTH_CREATE; 108d71c9934SAndreas Boehler return AUTH_READ; 109d71c9934SAndreas Boehler } 110d71c9934SAndreas Boehler else 111d71c9934SAndreas Boehler { 112d71c9934SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 113d71c9934SAndreas Boehler // We return AUTH_READ if the calendar does not exist. This makes 114d71c9934SAndreas Boehler // davcal happy when there are just included calendars 115d71c9934SAndreas Boehler if($calid === false) 116d71c9934SAndreas Boehler return AUTH_READ; 117d71c9934SAndreas Boehler return auth_quickaclcheck($id); 118d71c9934SAndreas Boehler } 119d71c9934SAndreas Boehler } 120d71c9934SAndreas Boehler 121d71c9934SAndreas Boehler /** 12280e1ddf7SAndreas Boehler * Filter calendar pages and return only those where the current 12380e1ddf7SAndreas Boehler * user has at least read permission. 12480e1ddf7SAndreas Boehler * 12580e1ddf7SAndreas Boehler * @param array $calendarPages Array with calendar pages to check 12680e1ddf7SAndreas Boehler * @return array with filtered calendar pages 12780e1ddf7SAndreas Boehler */ 12880e1ddf7SAndreas Boehler public function filterCalendarPagesByUserPermission($calendarPages) 12980e1ddf7SAndreas Boehler { 13080e1ddf7SAndreas Boehler $retList = array(); 13180e1ddf7SAndreas Boehler foreach($calendarPages as $page => $data) 13280e1ddf7SAndreas Boehler { 1330b805092SAndreas Boehler // WebDAV Connections are always readable 1340b805092SAndreas Boehler if(strpos($page, 'webdav://') === 0) 1350b805092SAndreas Boehler { 1360b805092SAndreas Boehler $retList[$page] = $data; 1370b805092SAndreas Boehler } 1380b805092SAndreas Boehler elseif(auth_quickaclcheck($page) >= AUTH_READ) 13980e1ddf7SAndreas Boehler { 14080e1ddf7SAndreas Boehler $retList[$page] = $data; 14180e1ddf7SAndreas Boehler } 14280e1ddf7SAndreas Boehler } 14380e1ddf7SAndreas Boehler return $retList; 14480e1ddf7SAndreas Boehler } 14580e1ddf7SAndreas Boehler 14680e1ddf7SAndreas Boehler /** 147185e2535SAndreas Boehler * Get all calendar pages used by a given page 148185e2535SAndreas Boehler * based on the stored metadata 149185e2535SAndreas Boehler * 150185e2535SAndreas Boehler * @param string $id optional The page id 151185e2535SAndreas Boehler * @return mixed The pages as array or false 152185e2535SAndreas Boehler */ 153185e2535SAndreas Boehler public function getCalendarPagesByMeta($id = null) 154185e2535SAndreas Boehler { 155185e2535SAndreas Boehler if(is_null($id)) 156185e2535SAndreas Boehler { 157185e2535SAndreas Boehler global $ID; 158185e2535SAndreas Boehler $id = $ID; 159185e2535SAndreas Boehler } 160185e2535SAndreas Boehler 161185e2535SAndreas Boehler $meta = $this->getCalendarMetaForPage($id); 1620b805092SAndreas Boehler 163185e2535SAndreas Boehler if(isset($meta['id'])) 164ed764890SAndreas Boehler { 165ed764890SAndreas Boehler // Filter the list of pages by permission 16680e1ddf7SAndreas Boehler $pages = $this->filterCalendarPagesByUserPermission($meta['id']); 16780e1ddf7SAndreas Boehler if(empty($pages)) 168ed764890SAndreas Boehler return false; 16980e1ddf7SAndreas Boehler return $pages; 170ed764890SAndreas Boehler } 171185e2535SAndreas Boehler return false; 172185e2535SAndreas Boehler } 173185e2535SAndreas Boehler 174185e2535SAndreas Boehler /** 175185e2535SAndreas Boehler * Get a list of calendar names/pages/ids/colors 176185e2535SAndreas Boehler * for an array of page ids 177185e2535SAndreas Boehler * 178185e2535SAndreas Boehler * @param array $calendarPages The calendar pages to retrieve 179185e2535SAndreas Boehler * @return array The list 180185e2535SAndreas Boehler */ 181185e2535SAndreas Boehler public function getCalendarMapForIDs($calendarPages) 182185e2535SAndreas Boehler { 183185e2535SAndreas Boehler $data = array(); 1844a2bf5eeSAndreas Boehler foreach($calendarPages as $page => $color) 185185e2535SAndreas Boehler { 1860b805092SAndreas Boehler if(strpos($page, 'webdav://') === 0) 1870b805092SAndreas Boehler { 1880b805092SAndreas Boehler $wdc =& plugin_load('helper', 'webdavclient'); 1890b805092SAndreas Boehler if(is_null($wdc)) 1900b805092SAndreas Boehler continue; 1910b805092SAndreas Boehler $connectionId = str_replace('webdav://', '', $page); 1920b805092SAndreas Boehler $settings = $wdc->getConnection($connectionId); 1932393a702SAndreas Boehler if($settings === false) 1942393a702SAndreas Boehler continue; 1950b805092SAndreas Boehler $name = $settings['displayname']; 196d71c9934SAndreas Boehler $write = ($settings['write'] === '1'); 1970b805092SAndreas Boehler $calid = $connectionId; 198cd2f100dSAndreas Boehler $color = '#3a87ad'; 1990b805092SAndreas Boehler } 2000b805092SAndreas Boehler else 2010b805092SAndreas Boehler { 202185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($page); 203185e2535SAndreas Boehler if($calid !== false) 204185e2535SAndreas Boehler { 205185e2535SAndreas Boehler $settings = $this->getCalendarSettings($calid); 206185e2535SAndreas Boehler $name = $settings['displayname']; 207cd2f100dSAndreas Boehler $color = $settings['calendarcolor']; 208ed764890SAndreas Boehler $write = (auth_quickaclcheck($page) > AUTH_READ); 2090b805092SAndreas Boehler } 2100b805092SAndreas Boehler else 2110b805092SAndreas Boehler { 2120b805092SAndreas Boehler continue; 2130b805092SAndreas Boehler } 2140b805092SAndreas Boehler } 215185e2535SAndreas Boehler $data[] = array('name' => $name, 'page' => $page, 'calid' => $calid, 216ed764890SAndreas Boehler 'color' => $color, 'write' => $write); 217185e2535SAndreas Boehler } 218185e2535SAndreas Boehler return $data; 219185e2535SAndreas Boehler } 220185e2535SAndreas Boehler 221185e2535SAndreas Boehler /** 222185e2535SAndreas Boehler * Get the saved calendar color for a given page. 223185e2535SAndreas Boehler * 224185e2535SAndreas Boehler * @param string $id optional The page ID 225185e2535SAndreas Boehler * @return mixed The color on success, otherwise false 226185e2535SAndreas Boehler */ 227185e2535SAndreas Boehler public function getCalendarColorForPage($id = null) 228185e2535SAndreas Boehler { 229185e2535SAndreas Boehler if(is_null($id)) 230185e2535SAndreas Boehler { 231185e2535SAndreas Boehler global $ID; 232185e2535SAndreas Boehler $id = $ID; 233185e2535SAndreas Boehler } 234185e2535SAndreas Boehler 235185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 236185e2535SAndreas Boehler if($calid === false) 237185e2535SAndreas Boehler return false; 238185e2535SAndreas Boehler 239185e2535SAndreas Boehler return $this->getCalendarColorForCalendar($calid); 240185e2535SAndreas Boehler } 241185e2535SAndreas Boehler 242185e2535SAndreas Boehler /** 243185e2535SAndreas Boehler * Get the saved calendar color for a given calendar ID. 244185e2535SAndreas Boehler * 245185e2535SAndreas Boehler * @param string $id optional The calendar ID 246185e2535SAndreas Boehler * @return mixed The color on success, otherwise false 247185e2535SAndreas Boehler */ 248185e2535SAndreas Boehler public function getCalendarColorForCalendar($calid) 249185e2535SAndreas Boehler { 250185e2535SAndreas Boehler if(isset($this->cachedValues['calendarcolor'][$calid])) 251185e2535SAndreas Boehler return $this->cachedValues['calendarcolor'][$calid]; 252185e2535SAndreas Boehler 253185e2535SAndreas Boehler $row = $this->getCalendarSettings($calid); 254185e2535SAndreas Boehler 255185e2535SAndreas Boehler if(!isset($row['calendarcolor'])) 256185e2535SAndreas Boehler return false; 257185e2535SAndreas Boehler 258185e2535SAndreas Boehler $color = $row['calendarcolor']; 259185e2535SAndreas Boehler $this->cachedValues['calendarcolor'][$calid] = $color; 260185e2535SAndreas Boehler return $color; 261185e2535SAndreas Boehler } 262185e2535SAndreas Boehler 263185e2535SAndreas Boehler /** 264e86c8dd3SAndreas Boehler * Get the user's principal URL for iOS sync 265e86c8dd3SAndreas Boehler * @param string $user the user name 266e86c8dd3SAndreas Boehler * @return the URL to the principal sync 267e86c8dd3SAndreas Boehler */ 268e86c8dd3SAndreas Boehler public function getPrincipalUrlForUser($user) 269e86c8dd3SAndreas Boehler { 270e86c8dd3SAndreas Boehler if(is_null($user)) 271e86c8dd3SAndreas Boehler return false; 272e86c8dd3SAndreas Boehler $url = DOKU_URL.'lib/plugins/davcal/calendarserver.php/principals/'.$user; 273e86c8dd3SAndreas Boehler return $url; 274e86c8dd3SAndreas Boehler } 275e86c8dd3SAndreas Boehler 276e86c8dd3SAndreas Boehler /** 277185e2535SAndreas Boehler * Set the calendar color for a given page. 278185e2535SAndreas Boehler * 279185e2535SAndreas Boehler * @param string $color The color definition 280185e2535SAndreas Boehler * @param string $id optional The page ID 281185e2535SAndreas Boehler * @return boolean True on success, otherwise false 282185e2535SAndreas Boehler */ 283185e2535SAndreas Boehler public function setCalendarColorForPage($color, $id = null) 284185e2535SAndreas Boehler { 285185e2535SAndreas Boehler if(is_null($id)) 286185e2535SAndreas Boehler { 287185e2535SAndreas Boehler global $ID; 288185e2535SAndreas Boehler $id = $ID; 289185e2535SAndreas Boehler } 290185e2535SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 291185e2535SAndreas Boehler if($calid === false) 292185e2535SAndreas Boehler return false; 293185e2535SAndreas Boehler 2945f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 2955f2c3e2dSAndreas Boehler if(!$sqlite) 2965f2c3e2dSAndreas Boehler return false; 29751f4febbSAndreas Boehler $query = "UPDATE calendars SET calendarcolor = ? ". 29851f4febbSAndreas Boehler " WHERE id = ?"; 2995f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $color, $calid); 300185e2535SAndreas Boehler if($res !== false) 301185e2535SAndreas Boehler { 302185e2535SAndreas Boehler $this->cachedValues['calendarcolor'][$calid] = $color; 303185e2535SAndreas Boehler return true; 304185e2535SAndreas Boehler } 305185e2535SAndreas Boehler return false; 306185e2535SAndreas Boehler } 307185e2535SAndreas Boehler 308185e2535SAndreas Boehler /** 309cb71a62aSAndreas Boehler * Set the calendar name and description for a given page with a given 310cb71a62aSAndreas Boehler * page id. 311cb71a62aSAndreas Boehler * If the calendar doesn't exist, the calendar is created! 312cb71a62aSAndreas Boehler * 313cb71a62aSAndreas Boehler * @param string $name The name of the new calendar 314cb71a62aSAndreas Boehler * @param string $description The description of the new calendar 315cb71a62aSAndreas Boehler * @param string $id (optional) The ID of the page 316cb71a62aSAndreas Boehler * @param string $userid The userid of the creating user 317cb71a62aSAndreas Boehler * 318cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false. 319cb71a62aSAndreas Boehler */ 320a1a3b679SAndreas Boehler public function setCalendarNameForPage($name, $description, $id = null, $userid = null) 321a1a3b679SAndreas Boehler { 322a1a3b679SAndreas Boehler if(is_null($id)) 323a1a3b679SAndreas Boehler { 324a1a3b679SAndreas Boehler global $ID; 325a1a3b679SAndreas Boehler $id = $ID; 326a1a3b679SAndreas Boehler } 327a1a3b679SAndreas Boehler if(is_null($userid)) 32834a47953SAndreas Boehler { 32934a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 33034a47953SAndreas Boehler { 331a1a3b679SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 33234a47953SAndreas Boehler } 33334a47953SAndreas Boehler else 33434a47953SAndreas Boehler { 33534a47953SAndreas Boehler $userid = uniqid('davcal-'); 33634a47953SAndreas Boehler } 33734a47953SAndreas Boehler } 338a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 339a1a3b679SAndreas Boehler if($calid === false) 340a1a3b679SAndreas Boehler return $this->createCalendarForPage($name, $description, $id, $userid); 341a1a3b679SAndreas Boehler 3425f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 3435f2c3e2dSAndreas Boehler if(!$sqlite) 3445f2c3e2dSAndreas Boehler return false; 34551f4febbSAndreas Boehler $query = "UPDATE calendars SET displayname = ?, description = ? WHERE id = ?"; 3465f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $name, $description, $calid); 347b269830cSAndreas Boehler if($res !== false) 348b269830cSAndreas Boehler return true; 349b269830cSAndreas Boehler return false; 350a1a3b679SAndreas Boehler } 351a1a3b679SAndreas Boehler 352cb71a62aSAndreas Boehler /** 353d5703f5aSAndreas Boehler * Update a calendar's displayname 354d5703f5aSAndreas Boehler * 355d5703f5aSAndreas Boehler * @param int $calid The calendar's ID 356d5703f5aSAndreas Boehler * @param string $name The new calendar name 357d5703f5aSAndreas Boehler * 358d5703f5aSAndreas Boehler * @return boolean True on success, otherwise false 359d5703f5aSAndreas Boehler */ 360d5703f5aSAndreas Boehler public function updateCalendarName($calid, $name) 361d5703f5aSAndreas Boehler { 3625f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 3635f2c3e2dSAndreas Boehler if(!$sqlite) 3645f2c3e2dSAndreas Boehler return false; 365d5703f5aSAndreas Boehler $query = "UPDATE calendars SET displayname = ? WHERE id = ?"; 3665f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid, $name); 367d5703f5aSAndreas Boehler if($res !== false) 368d5703f5aSAndreas Boehler { 369d5703f5aSAndreas Boehler $this->updateSyncTokenLog($calid, '', 'modified'); 370d5703f5aSAndreas Boehler return true; 371d5703f5aSAndreas Boehler } 372d5703f5aSAndreas Boehler return false; 373d5703f5aSAndreas Boehler } 374d5703f5aSAndreas Boehler 375d5703f5aSAndreas Boehler /** 376d5703f5aSAndreas Boehler * Update the calendar description 377d5703f5aSAndreas Boehler * 378d5703f5aSAndreas Boehler * @param int $calid The calendar's ID 379d5703f5aSAndreas Boehler * @param string $description The new calendar's description 380d5703f5aSAndreas Boehler * 381d5703f5aSAndreas Boehler * @return boolean True on success, otherwise false 382d5703f5aSAndreas Boehler */ 383d5703f5aSAndreas Boehler public function updateCalendarDescription($calid, $description) 384d5703f5aSAndreas Boehler { 3855f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 3865f2c3e2dSAndreas Boehler if(!$sqlite) 3875f2c3e2dSAndreas Boehler return false; 388d5703f5aSAndreas Boehler $query = "UPDATE calendars SET description = ? WHERE id = ?"; 3895f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid, $description); 390d5703f5aSAndreas Boehler if($res !== false) 391d5703f5aSAndreas Boehler { 392d5703f5aSAndreas Boehler $this->updateSyncTokenLog($calid, '', 'modified'); 393d5703f5aSAndreas Boehler return true; 394d5703f5aSAndreas Boehler } 395d5703f5aSAndreas Boehler return false; 396d5703f5aSAndreas Boehler } 397d5703f5aSAndreas Boehler 398d5703f5aSAndreas Boehler /** 399d5703f5aSAndreas Boehler * Update a calendar's timezone information 400d5703f5aSAndreas Boehler * 401d5703f5aSAndreas Boehler * @param int $calid The calendar's ID 402d5703f5aSAndreas Boehler * @param string $timezone The new timezone to set 403d5703f5aSAndreas Boehler * 404d5703f5aSAndreas Boehler * @return boolean True on success, otherwise false 405d5703f5aSAndreas Boehler */ 406d5703f5aSAndreas Boehler public function updateCalendarTimezone($calid, $timezone) 407d5703f5aSAndreas Boehler { 4085f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 4095f2c3e2dSAndreas Boehler if(!$sqlite) 4105f2c3e2dSAndreas Boehler return false; 411d5703f5aSAndreas Boehler $query = "UPDATE calendars SET timezone = ? WHERE id = ?"; 4125f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid, $timezone); 413d5703f5aSAndreas Boehler if($res !== false) 414d5703f5aSAndreas Boehler { 415d5703f5aSAndreas Boehler $this->updateSyncTokenLog($calid, '', 'modified'); 416d5703f5aSAndreas Boehler return true; 417d5703f5aSAndreas Boehler } 418d5703f5aSAndreas Boehler return false; 419d5703f5aSAndreas Boehler } 420d5703f5aSAndreas Boehler 421d5703f5aSAndreas Boehler /** 422cb71a62aSAndreas Boehler * Save the personal settings to the SQLite database 'calendarsettings'. 423cb71a62aSAndreas Boehler * 424cb71a62aSAndreas Boehler * @param array $settings The settings array to store 425cb71a62aSAndreas Boehler * @param string $userid (optional) The userid to store 426cb71a62aSAndreas Boehler * 427cb71a62aSAndreas Boehler * @param boolean True on success, otherwise false 428cb71a62aSAndreas Boehler */ 429a495d34cSAndreas Boehler public function savePersonalSettings($settings, $userid = null) 430a495d34cSAndreas Boehler { 431a495d34cSAndreas Boehler if(is_null($userid)) 43234a47953SAndreas Boehler { 43334a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 43434a47953SAndreas Boehler { 435a495d34cSAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 43634a47953SAndreas Boehler } 43734a47953SAndreas Boehler else 43834a47953SAndreas Boehler { 43934a47953SAndreas Boehler return false; 44034a47953SAndreas Boehler } 44134a47953SAndreas Boehler } 4425f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 4435f2c3e2dSAndreas Boehler if(!$sqlite) 4445f2c3e2dSAndreas Boehler return false; 4455f2c3e2dSAndreas Boehler $sqlite->query("BEGIN TRANSACTION"); 446a495d34cSAndreas Boehler 44751f4febbSAndreas Boehler $query = "DELETE FROM calendarsettings WHERE userid = ?"; 4485f2c3e2dSAndreas Boehler $sqlite->query($query, $userid); 449bd883736SAndreas Boehler 450a495d34cSAndreas Boehler foreach($settings as $key => $value) 451a495d34cSAndreas Boehler { 45251f4febbSAndreas Boehler $query = "INSERT INTO calendarsettings (userid, key, value) VALUES (?, ?, ?)"; 4535f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $userid, $key, $value); 454a495d34cSAndreas Boehler if($res === false) 455a495d34cSAndreas Boehler return false; 456a495d34cSAndreas Boehler } 4575f2c3e2dSAndreas Boehler $sqlite->query("COMMIT TRANSACTION"); 458185e2535SAndreas Boehler $this->cachedValues['settings'][$userid] = $settings; 459a495d34cSAndreas Boehler return true; 460a495d34cSAndreas Boehler } 461a495d34cSAndreas Boehler 462cb71a62aSAndreas Boehler /** 463cb71a62aSAndreas Boehler * Retrieve the settings array for a given user id. 464cb71a62aSAndreas Boehler * Some sane defaults are returned, currently: 465cb71a62aSAndreas Boehler * 466cb71a62aSAndreas Boehler * timezone => local 467cb71a62aSAndreas Boehler * weeknumbers => 0 468cb71a62aSAndreas Boehler * workweek => 0 469cb71a62aSAndreas Boehler * 470cb71a62aSAndreas Boehler * @param string $userid (optional) The user id to retrieve 471cb71a62aSAndreas Boehler * 472cb71a62aSAndreas Boehler * @return array The settings array 473cb71a62aSAndreas Boehler */ 474a495d34cSAndreas Boehler public function getPersonalSettings($userid = null) 475a495d34cSAndreas Boehler { 476bd883736SAndreas Boehler // Some sane default settings 477bd883736SAndreas Boehler $settings = array( 478fb813b30SAndreas Boehler 'timezone' => $this->getConf('timezone'), 479fb813b30SAndreas Boehler 'weeknumbers' => $this->getConf('weeknumbers'), 480fb813b30SAndreas Boehler 'workweek' => $this->getConf('workweek'), 4811d5bdcd0SAndreas Boehler 'monday' => $this->getConf('monday'), 4821d5bdcd0SAndreas Boehler 'timeformat' => $this->getConf('timeformat') 483bd883736SAndreas Boehler ); 48434a47953SAndreas Boehler if(is_null($userid)) 48534a47953SAndreas Boehler { 48634a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 48734a47953SAndreas Boehler { 48834a47953SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 48934a47953SAndreas Boehler } 49034a47953SAndreas Boehler else 49134a47953SAndreas Boehler { 49234a47953SAndreas Boehler return $settings; 49334a47953SAndreas Boehler } 49434a47953SAndreas Boehler } 49534a47953SAndreas Boehler 4965f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 4975f2c3e2dSAndreas Boehler if(!$sqlite) 4985f2c3e2dSAndreas Boehler return false; 49934a47953SAndreas Boehler if(isset($this->cachedValues['settings'][$userid])) 50034a47953SAndreas Boehler return $this->cachedValues['settings'][$userid]; 50151f4febbSAndreas Boehler $query = "SELECT key, value FROM calendarsettings WHERE userid = ?"; 5025f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $userid); 5035f2c3e2dSAndreas Boehler $arr = $sqlite->res2arr($res); 504a495d34cSAndreas Boehler foreach($arr as $row) 505a495d34cSAndreas Boehler { 506a495d34cSAndreas Boehler $settings[$row['key']] = $row['value']; 507a495d34cSAndreas Boehler } 508185e2535SAndreas Boehler $this->cachedValues['settings'][$userid] = $settings; 509a495d34cSAndreas Boehler return $settings; 510a495d34cSAndreas Boehler } 511a495d34cSAndreas Boehler 512cb71a62aSAndreas Boehler /** 513cb71a62aSAndreas Boehler * Retrieve the calendar ID based on a page ID from the SQLite table 514cb71a62aSAndreas Boehler * 'pagetocalendarmapping'. 515cb71a62aSAndreas Boehler * 516cb71a62aSAndreas Boehler * @param string $id (optional) The page ID to retrieve the corresponding calendar 517cb71a62aSAndreas Boehler * 518cb71a62aSAndreas Boehler * @return mixed the ID on success, otherwise false 519cb71a62aSAndreas Boehler */ 520a1a3b679SAndreas Boehler public function getCalendarIdForPage($id = null) 521a1a3b679SAndreas Boehler { 522a1a3b679SAndreas Boehler if(is_null($id)) 523a1a3b679SAndreas Boehler { 524a1a3b679SAndreas Boehler global $ID; 525a1a3b679SAndreas Boehler $id = $ID; 526a1a3b679SAndreas Boehler } 527a1a3b679SAndreas Boehler 528185e2535SAndreas Boehler if(isset($this->cachedValues['calid'][$id])) 529185e2535SAndreas Boehler return $this->cachedValues['calid'][$id]; 530185e2535SAndreas Boehler 5315f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 5325f2c3e2dSAndreas Boehler if(!$sqlite) 5335f2c3e2dSAndreas Boehler return false; 53451f4febbSAndreas Boehler $query = "SELECT calid FROM pagetocalendarmapping WHERE page = ?"; 5355f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $id); 5365f2c3e2dSAndreas Boehler $row = $sqlite->res2row($res); 537a1a3b679SAndreas Boehler if(isset($row['calid'])) 538185e2535SAndreas Boehler { 539185e2535SAndreas Boehler $calid = $row['calid']; 540185e2535SAndreas Boehler $this->cachedValues['calid'] = $calid; 541185e2535SAndreas Boehler return $calid; 542185e2535SAndreas Boehler } 543a1a3b679SAndreas Boehler return false; 544a1a3b679SAndreas Boehler } 545a1a3b679SAndreas Boehler 546cb71a62aSAndreas Boehler /** 547cb71a62aSAndreas Boehler * Retrieve the complete calendar id to page mapping. 548cb71a62aSAndreas Boehler * This is necessary to be able to retrieve a list of 549cb71a62aSAndreas Boehler * calendars for a given user and check the access rights. 550cb71a62aSAndreas Boehler * 551cb71a62aSAndreas Boehler * @return array The mapping array 552cb71a62aSAndreas Boehler */ 553a1a3b679SAndreas Boehler public function getCalendarIdToPageMapping() 554a1a3b679SAndreas Boehler { 5555f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 5565f2c3e2dSAndreas Boehler if(!$sqlite) 5575f2c3e2dSAndreas Boehler return false; 558a1a3b679SAndreas Boehler $query = "SELECT calid, page FROM pagetocalendarmapping"; 5595f2c3e2dSAndreas Boehler $res = $sqlite->query($query); 5605f2c3e2dSAndreas Boehler $arr = $sqlite->res2arr($res); 561a1a3b679SAndreas Boehler return $arr; 562a1a3b679SAndreas Boehler } 563a1a3b679SAndreas Boehler 564cb71a62aSAndreas Boehler /** 565cb71a62aSAndreas Boehler * Retrieve all calendar IDs a given user has access to. 566cb71a62aSAndreas Boehler * The user is specified by the principalUri, so the 567cb71a62aSAndreas Boehler * user name is actually split from the URI component. 568cb71a62aSAndreas Boehler * 569cb71a62aSAndreas Boehler * Access rights are checked against DokuWiki's ACL 570cb71a62aSAndreas Boehler * and applied accordingly. 571cb71a62aSAndreas Boehler * 572cb71a62aSAndreas Boehler * @param string $principalUri The principal URI to work on 573cb71a62aSAndreas Boehler * 574cb71a62aSAndreas Boehler * @return array An associative array of calendar IDs 575cb71a62aSAndreas Boehler */ 576a1a3b679SAndreas Boehler public function getCalendarIdsForUser($principalUri) 577a1a3b679SAndreas Boehler { 57834a47953SAndreas Boehler global $auth; 579a1a3b679SAndreas Boehler $user = explode('/', $principalUri); 580a1a3b679SAndreas Boehler $user = end($user); 581a1a3b679SAndreas Boehler $mapping = $this->getCalendarIdToPageMapping(); 582a1a3b679SAndreas Boehler $calids = array(); 58334a47953SAndreas Boehler $ud = $auth->getUserData($user); 58434a47953SAndreas Boehler $groups = $ud['grps']; 585a1a3b679SAndreas Boehler foreach($mapping as $row) 586a1a3b679SAndreas Boehler { 587a1a3b679SAndreas Boehler $id = $row['calid']; 58813b16484SAndreas Boehler $enabled = $this->getCalendarStatus($id); 58913b16484SAndreas Boehler if($enabled == false) 59013b16484SAndreas Boehler continue; 591a1a3b679SAndreas Boehler $page = $row['page']; 59234a47953SAndreas Boehler $acl = auth_aclcheck($page, $user, $groups); 593a1a3b679SAndreas Boehler if($acl >= AUTH_READ) 594a1a3b679SAndreas Boehler { 595a1a3b679SAndreas Boehler $write = $acl > AUTH_READ; 596a1a3b679SAndreas Boehler $calids[$id] = array('readonly' => !$write); 597a1a3b679SAndreas Boehler } 598a1a3b679SAndreas Boehler } 599a1a3b679SAndreas Boehler return $calids; 600a1a3b679SAndreas Boehler } 601a1a3b679SAndreas Boehler 602cb71a62aSAndreas Boehler /** 603cb71a62aSAndreas Boehler * Create a new calendar for a given page ID and set name and description 604cb71a62aSAndreas Boehler * accordingly. Also update the pagetocalendarmapping table on success. 605cb71a62aSAndreas Boehler * 606cb71a62aSAndreas Boehler * @param string $name The calendar's name 607cb71a62aSAndreas Boehler * @param string $description The calendar's description 608cb71a62aSAndreas Boehler * @param string $id (optional) The page ID to work on 609cb71a62aSAndreas Boehler * @param string $userid (optional) The user ID that created the calendar 610cb71a62aSAndreas Boehler * 611cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 612cb71a62aSAndreas Boehler */ 613a1a3b679SAndreas Boehler public function createCalendarForPage($name, $description, $id = null, $userid = null) 614a1a3b679SAndreas Boehler { 615a1a3b679SAndreas Boehler if(is_null($id)) 616a1a3b679SAndreas Boehler { 617a1a3b679SAndreas Boehler global $ID; 618a1a3b679SAndreas Boehler $id = $ID; 619a1a3b679SAndreas Boehler } 620a1a3b679SAndreas Boehler if(is_null($userid)) 62134a47953SAndreas Boehler { 62234a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 62334a47953SAndreas Boehler { 624a1a3b679SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 62534a47953SAndreas Boehler } 62634a47953SAndreas Boehler else 62734a47953SAndreas Boehler { 62834a47953SAndreas Boehler $userid = uniqid('davcal-'); 62934a47953SAndreas Boehler } 63034a47953SAndreas Boehler } 631a1a3b679SAndreas Boehler $values = array('principals/'.$userid, 632a1a3b679SAndreas Boehler $name, 633a1a3b679SAndreas Boehler str_replace(array('/', ' ', ':'), '_', $id), 634a1a3b679SAndreas Boehler $description, 635a1a3b679SAndreas Boehler 'VEVENT,VTODO', 63655a741c0SAndreas Boehler 0, 63755a741c0SAndreas Boehler 1); 6385f2c3e2dSAndreas Boehler 6395f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 6405f2c3e2dSAndreas Boehler if(!$sqlite) 6415f2c3e2dSAndreas Boehler return false; 64251f4febbSAndreas Boehler $query = "INSERT INTO calendars (principaluri, displayname, uri, description, components, transparent, synctoken) ". 64351f4febbSAndreas Boehler "VALUES (?, ?, ?, ?, ?, ?, ?)"; 6445f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $values[0], $values[1], $values[2], $values[3], $values[4], $values[5], $values[6]); 64555a741c0SAndreas Boehler if($res === false) 64655a741c0SAndreas Boehler return false; 647cb71a62aSAndreas Boehler 648cb71a62aSAndreas Boehler // Get the new calendar ID 64951f4febbSAndreas Boehler $query = "SELECT id FROM calendars WHERE principaluri = ? AND displayname = ? AND ". 65051f4febbSAndreas Boehler "uri = ? AND description = ?"; 6515f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $values[0], $values[1], $values[2], $values[3]); 6525f2c3e2dSAndreas Boehler $row = $sqlite->res2row($res); 653cb71a62aSAndreas Boehler 654cb71a62aSAndreas Boehler // Update the pagetocalendarmapping table with the new calendar ID 655a1a3b679SAndreas Boehler if(isset($row['id'])) 656a1a3b679SAndreas Boehler { 65751f4febbSAndreas Boehler $query = "INSERT INTO pagetocalendarmapping (page, calid) VALUES (?, ?)"; 6585f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $id, $row['id']); 65955a741c0SAndreas Boehler return ($res !== false); 660a1a3b679SAndreas Boehler } 661a1a3b679SAndreas Boehler 662a1a3b679SAndreas Boehler return false; 663a1a3b679SAndreas Boehler } 664a1a3b679SAndreas Boehler 665cb71a62aSAndreas Boehler /** 666d5703f5aSAndreas Boehler * Add a new calendar entry to the given calendar. Calendar data is 667d5703f5aSAndreas Boehler * specified as ICS file, thus it needs to be parsed first. 668d5703f5aSAndreas Boehler * 669d5703f5aSAndreas Boehler * This is mainly needed for the sync support. 670d5703f5aSAndreas Boehler * 671d5703f5aSAndreas Boehler * @param int $calid The calendar's ID 672d5703f5aSAndreas Boehler * @param string $uri The new object URI 673d5703f5aSAndreas Boehler * @param string $ics The ICS file 674d5703f5aSAndreas Boehler * 675d5703f5aSAndreas Boehler * @return mixed The etag. 676d5703f5aSAndreas Boehler */ 677d5703f5aSAndreas Boehler public function addCalendarEntryToCalendarByICS($calid, $uri, $ics) 678d5703f5aSAndreas Boehler { 679d5703f5aSAndreas Boehler $extraData = $this->getDenormalizedData($ics); 680d5703f5aSAndreas Boehler 6815f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 6825f2c3e2dSAndreas Boehler if(!$sqlite) 6835f2c3e2dSAndreas Boehler return false; 684d5703f5aSAndreas Boehler $query = "INSERT INTO calendarobjects (calendarid, uri, calendardata, lastmodified, etag, size, componenttype, firstoccurence, lastoccurence, uid) VALUES (?,?,?,?,?,?,?,?,?,?)"; 6855f2c3e2dSAndreas Boehler $res = $sqlite->query($query, 686d5703f5aSAndreas Boehler $calid, 687d5703f5aSAndreas Boehler $uri, 688d5703f5aSAndreas Boehler $ics, 689d5703f5aSAndreas Boehler time(), 690d5703f5aSAndreas Boehler $extraData['etag'], 691d5703f5aSAndreas Boehler $extraData['size'], 692d5703f5aSAndreas Boehler $extraData['componentType'], 693d5703f5aSAndreas Boehler $extraData['firstOccurence'], 694d5703f5aSAndreas Boehler $extraData['lastOccurence'], 695d5703f5aSAndreas Boehler $extraData['uid']); 696d5703f5aSAndreas Boehler // If successfully, update the sync token database 697d5703f5aSAndreas Boehler if($res !== false) 698d5703f5aSAndreas Boehler { 699d5703f5aSAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'added'); 700d5703f5aSAndreas Boehler } 701d5703f5aSAndreas Boehler return $extraData['etag']; 702d5703f5aSAndreas Boehler } 703d5703f5aSAndreas Boehler 704d5703f5aSAndreas Boehler /** 705d5703f5aSAndreas Boehler * Edit a calendar entry by providing a new ICS file. This is mainly 706d5703f5aSAndreas Boehler * needed for the sync support. 707d5703f5aSAndreas Boehler * 708d5703f5aSAndreas Boehler * @param int $calid The calendar's IS 709d5703f5aSAndreas Boehler * @param string $uri The object's URI to modify 710d5703f5aSAndreas Boehler * @param string $ics The new object's ICS file 711d5703f5aSAndreas Boehler */ 712d5703f5aSAndreas Boehler public function editCalendarEntryToCalendarByICS($calid, $uri, $ics) 713d5703f5aSAndreas Boehler { 714d5703f5aSAndreas Boehler $extraData = $this->getDenormalizedData($ics); 715d5703f5aSAndreas Boehler 7165f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 7175f2c3e2dSAndreas Boehler if(!$sqlite) 7185f2c3e2dSAndreas Boehler return false; 719d5703f5aSAndreas Boehler $query = "UPDATE calendarobjects SET calendardata = ?, lastmodified = ?, etag = ?, size = ?, componenttype = ?, firstoccurence = ?, lastoccurence = ?, uid = ? WHERE calendarid = ? AND uri = ?"; 7205f2c3e2dSAndreas Boehler $res = $sqlite->query($query, 721d5703f5aSAndreas Boehler $ics, 722d5703f5aSAndreas Boehler time(), 723d5703f5aSAndreas Boehler $extraData['etag'], 724d5703f5aSAndreas Boehler $extraData['size'], 725d5703f5aSAndreas Boehler $extraData['componentType'], 726d5703f5aSAndreas Boehler $extraData['firstOccurence'], 727d5703f5aSAndreas Boehler $extraData['lastOccurence'], 728d5703f5aSAndreas Boehler $extraData['uid'], 729d5703f5aSAndreas Boehler $calid, 730d5703f5aSAndreas Boehler $uri 731d5703f5aSAndreas Boehler ); 732d5703f5aSAndreas Boehler if($res !== false) 733d5703f5aSAndreas Boehler { 734d5703f5aSAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'modified'); 735d5703f5aSAndreas Boehler } 736d5703f5aSAndreas Boehler return $extraData['etag']; 737d5703f5aSAndreas Boehler } 738d5703f5aSAndreas Boehler 739d5703f5aSAndreas Boehler /** 740cb71a62aSAndreas Boehler * Add a new iCal entry for a given page, i.e. a given calendar. 741cb71a62aSAndreas Boehler * 742cb71a62aSAndreas Boehler * The parameter array needs to contain 743cb71a62aSAndreas Boehler * detectedtz => The timezone as detected by the browser 74482a48dfbSAndreas Boehler * currenttz => The timezone in use by the calendar 745cb71a62aSAndreas Boehler * eventfrom => The event's start date 746cb71a62aSAndreas Boehler * eventfromtime => The event's start time 747cb71a62aSAndreas Boehler * eventto => The event's end date 748cb71a62aSAndreas Boehler * eventtotime => The event's end time 749cb71a62aSAndreas Boehler * eventname => The event's name 750cb71a62aSAndreas Boehler * eventdescription => The event's description 751cb71a62aSAndreas Boehler * 752cb71a62aSAndreas Boehler * @param string $id The page ID to work on 753cb71a62aSAndreas Boehler * @param string $user The user who created the calendar 754cb71a62aSAndreas Boehler * @param string $params A parameter array with values to create 755cb71a62aSAndreas Boehler * 756cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 757cb71a62aSAndreas Boehler */ 758a1a3b679SAndreas Boehler public function addCalendarEntryToCalendarForPage($id, $user, $params) 759a1a3b679SAndreas Boehler { 76082a48dfbSAndreas Boehler if($params['currenttz'] !== '' && $params['currenttz'] !== 'local') 76182a48dfbSAndreas Boehler $timezone = new \DateTimeZone($params['currenttz']); 76282a48dfbSAndreas Boehler elseif($params['currenttz'] === 'local') 763a25c89eaSAndreas Boehler $timezone = new \DateTimeZone($params['detectedtz']); 764bd883736SAndreas Boehler else 765bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 766cb71a62aSAndreas Boehler 767cb71a62aSAndreas Boehler // Retrieve dates from settings 768b269830cSAndreas Boehler $startDate = explode('-', $params['eventfrom']); 769b269830cSAndreas Boehler $startTime = explode(':', $params['eventfromtime']); 770b269830cSAndreas Boehler $endDate = explode('-', $params['eventto']); 771b269830cSAndreas Boehler $endTime = explode(':', $params['eventtotime']); 772cb71a62aSAndreas Boehler 773cb71a62aSAndreas Boehler // Load SabreDAV 7749bef4ad8SAndreas Boehler require_once(DOKU_PLUGIN.'davcal/vendor/autoload.php'); 775a1a3b679SAndreas Boehler $vcalendar = new \Sabre\VObject\Component\VCalendar(); 776cb71a62aSAndreas Boehler 777cb71a62aSAndreas Boehler // Add VCalendar, UID and Event Name 778a1a3b679SAndreas Boehler $event = $vcalendar->add('VEVENT'); 779b269830cSAndreas Boehler $uuid = \Sabre\VObject\UUIDUtil::getUUID(); 780b269830cSAndreas Boehler $event->add('UID', $uuid); 781a1a3b679SAndreas Boehler $event->summary = $params['eventname']; 782cb71a62aSAndreas Boehler 783cb71a62aSAndreas Boehler // Add a description if requested 7840eebc909SAndreas Boehler $description = $params['eventdescription']; 7850eebc909SAndreas Boehler if($description !== '') 7860eebc909SAndreas Boehler $event->add('DESCRIPTION', $description); 787cb71a62aSAndreas Boehler 7882b7be5bdSAndreas Boehler // Add a location if requested 7892b7be5bdSAndreas Boehler $location = $params['eventlocation']; 7902b7be5bdSAndreas Boehler if($location !== '') 7912b7be5bdSAndreas Boehler $event->add('LOCATION', $location); 7922b7be5bdSAndreas Boehler 7934ecb526cSAndreas Boehler // Add attachments 7944ecb526cSAndreas Boehler $attachments = $params['attachments']; 79582a48dfbSAndreas Boehler if(!is_null($attachments)) 7964ecb526cSAndreas Boehler foreach($attachments as $attachment) 7974ecb526cSAndreas Boehler $event->add('ATTACH', $attachment); 7984ecb526cSAndreas Boehler 799cb71a62aSAndreas Boehler // Create a timestamp for last modified, created and dtstamp values in UTC 800b269830cSAndreas Boehler $dtStamp = new \DateTime(null, new \DateTimeZone('UTC')); 801b269830cSAndreas Boehler $event->add('DTSTAMP', $dtStamp); 802b269830cSAndreas Boehler $event->add('CREATED', $dtStamp); 803b269830cSAndreas Boehler $event->add('LAST-MODIFIED', $dtStamp); 804cb71a62aSAndreas Boehler 805cb71a62aSAndreas Boehler // Adjust the start date, based on the given timezone information 806b269830cSAndreas Boehler $dtStart = new \DateTime(); 807a25c89eaSAndreas Boehler $dtStart->setTimezone($timezone); 808b269830cSAndreas Boehler $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2])); 809cb71a62aSAndreas Boehler 810cb71a62aSAndreas Boehler // Only add the time values if it's not an allday event 811b269830cSAndreas Boehler if($params['allday'] != '1') 812b269830cSAndreas Boehler $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0); 813cb71a62aSAndreas Boehler 814cb71a62aSAndreas Boehler // Adjust the end date, based on the given timezone information 815b269830cSAndreas Boehler $dtEnd = new \DateTime(); 816a25c89eaSAndreas Boehler $dtEnd->setTimezone($timezone); 817b269830cSAndreas Boehler $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2])); 818cb71a62aSAndreas Boehler 819cb71a62aSAndreas Boehler // Only add the time values if it's not an allday event 820b269830cSAndreas Boehler if($params['allday'] != '1') 821b269830cSAndreas Boehler $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0); 822cb71a62aSAndreas Boehler 823b269830cSAndreas Boehler // According to the VCal spec, we need to add a whole day here 824b269830cSAndreas Boehler if($params['allday'] == '1') 825b269830cSAndreas Boehler $dtEnd->add(new \DateInterval('P1D')); 826cb71a62aSAndreas Boehler 827cb71a62aSAndreas Boehler // Really add Start and End events 828b269830cSAndreas Boehler $dtStartEv = $event->add('DTSTART', $dtStart); 829b269830cSAndreas Boehler $dtEndEv = $event->add('DTEND', $dtEnd); 830cb71a62aSAndreas Boehler 831cb71a62aSAndreas Boehler // Adjust the DATE format for allday events 832b269830cSAndreas Boehler if($params['allday'] == '1') 833b269830cSAndreas Boehler { 834b269830cSAndreas Boehler $dtStartEv['VALUE'] = 'DATE'; 835b269830cSAndreas Boehler $dtEndEv['VALUE'] = 'DATE'; 836b269830cSAndreas Boehler } 837cb71a62aSAndreas Boehler 838809cb0faSAndreas Boehler $eventStr = $vcalendar->serialize(); 839809cb0faSAndreas Boehler 840809cb0faSAndreas Boehler if(strpos($id, 'webdav://') === 0) 841809cb0faSAndreas Boehler { 842809cb0faSAndreas Boehler $wdc =& plugin_load('helper', 'webdavclient'); 843809cb0faSAndreas Boehler if(is_null($wdc)) 844809cb0faSAndreas Boehler return false; 845809cb0faSAndreas Boehler $connectionId = str_replace('webdav://', '', $id); 846809cb0faSAndreas Boehler return $wdc->addCalendarEntry($connectionId, $eventStr); 847809cb0faSAndreas Boehler } 848809cb0faSAndreas Boehler else 849809cb0faSAndreas Boehler { 850cb71a62aSAndreas Boehler // Actually add the values to the database 851a1a3b679SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 852a1a3b679SAndreas Boehler $uri = uniqid('dokuwiki-').'.ics'; 8531bb22c2bSAndreas Boehler $now = new \DateTime(); 854a1a3b679SAndreas Boehler 8555f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 8565f2c3e2dSAndreas Boehler if(!$sqlite) 8575f2c3e2dSAndreas Boehler return false; 85851f4febbSAndreas Boehler $query = "INSERT INTO calendarobjects (calendarid, uri, calendardata, lastmodified, componenttype, firstoccurence, lastoccurence, size, etag, uid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; 8595f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid, $uri, $eventStr, $now->getTimestamp(), 'VEVENT', 86051f4febbSAndreas Boehler $event->DTSTART->getDateTime()->getTimeStamp(), $event->DTEND->getDateTime()->getTimeStamp(), 86151f4febbSAndreas Boehler strlen($eventStr), md5($eventStr), $uuid); 862cb71a62aSAndreas Boehler 863cb71a62aSAndreas Boehler // If successfully, update the sync token database 86455a741c0SAndreas Boehler if($res !== false) 86555a741c0SAndreas Boehler { 86655a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'added'); 867a1a3b679SAndreas Boehler return true; 868a1a3b679SAndreas Boehler } 869809cb0faSAndreas Boehler } 87055a741c0SAndreas Boehler return false; 87155a741c0SAndreas Boehler } 872a1a3b679SAndreas Boehler 873cb71a62aSAndreas Boehler /** 874cb71a62aSAndreas Boehler * Retrieve the calendar settings of a given calendar id 875cb71a62aSAndreas Boehler * 876cb71a62aSAndreas Boehler * @param string $calid The calendar ID 877cb71a62aSAndreas Boehler * 878cb71a62aSAndreas Boehler * @return array The calendar settings array 879cb71a62aSAndreas Boehler */ 880b269830cSAndreas Boehler public function getCalendarSettings($calid) 881b269830cSAndreas Boehler { 8825f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 8835f2c3e2dSAndreas Boehler if(!$sqlite) 8845f2c3e2dSAndreas Boehler return false; 88513b16484SAndreas Boehler $query = "SELECT id, principaluri, calendarcolor, displayname, uri, description, components, transparent, synctoken, disabled FROM calendars WHERE id= ? "; 8865f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid); 8875f2c3e2dSAndreas Boehler $row = $sqlite->res2row($res); 888b269830cSAndreas Boehler return $row; 889b269830cSAndreas Boehler } 890b269830cSAndreas Boehler 891cb71a62aSAndreas Boehler /** 89213b16484SAndreas Boehler * Retrieve the calendar status of a given calendar id 89313b16484SAndreas Boehler * 89413b16484SAndreas Boehler * @param string $calid The calendar ID 89513b16484SAndreas Boehler * @return boolean True if calendar is enabled, otherwise false 89613b16484SAndreas Boehler */ 89713b16484SAndreas Boehler public function getCalendarStatus($calid) 89813b16484SAndreas Boehler { 8995f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 9005f2c3e2dSAndreas Boehler if(!$sqlite) 9015f2c3e2dSAndreas Boehler return false; 90213b16484SAndreas Boehler $query = "SELECT disabled FROM calendars WHERE id = ?"; 9035f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid); 9045f2c3e2dSAndreas Boehler $row = $sqlite->res2row($res); 90513b16484SAndreas Boehler if($row['disabled'] == 1) 90613b16484SAndreas Boehler return false; 90713b16484SAndreas Boehler else 90813b16484SAndreas Boehler return true; 90913b16484SAndreas Boehler } 91013b16484SAndreas Boehler 91113b16484SAndreas Boehler /** 91213b16484SAndreas Boehler * Disable a calendar for a given page 91313b16484SAndreas Boehler * 91413b16484SAndreas Boehler * @param string $id The page ID 91513b16484SAndreas Boehler * 91613b16484SAndreas Boehler * @return boolean true on success, otherwise false 91713b16484SAndreas Boehler */ 91813b16484SAndreas Boehler public function disableCalendarForPage($id) 91913b16484SAndreas Boehler { 92013b16484SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 92113b16484SAndreas Boehler if($calid === false) 92213b16484SAndreas Boehler return false; 9235f2c3e2dSAndreas Boehler 9245f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 9255f2c3e2dSAndreas Boehler if(!$sqlite) 9265f2c3e2dSAndreas Boehler return false; 92713b16484SAndreas Boehler $query = "UPDATE calendars SET disabled = 1 WHERE id = ?"; 9285f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid); 92913b16484SAndreas Boehler if($res !== false) 93013b16484SAndreas Boehler return true; 93113b16484SAndreas Boehler return false; 93213b16484SAndreas Boehler } 93313b16484SAndreas Boehler 93413b16484SAndreas Boehler /** 93513b16484SAndreas Boehler * Enable a calendar for a given page 93613b16484SAndreas Boehler * 93713b16484SAndreas Boehler * @param string $id The page ID 93813b16484SAndreas Boehler * 93913b16484SAndreas Boehler * @return boolean true on success, otherwise false 94013b16484SAndreas Boehler */ 94113b16484SAndreas Boehler public function enableCalendarForPage($id) 94213b16484SAndreas Boehler { 94313b16484SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 94413b16484SAndreas Boehler if($calid === false) 94513b16484SAndreas Boehler return false; 9465f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 9475f2c3e2dSAndreas Boehler if(!$sqlite) 9485f2c3e2dSAndreas Boehler return false; 94913b16484SAndreas Boehler $query = "UPDATE calendars SET disabled = 0 WHERE id = ?"; 9505f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid); 95113b16484SAndreas Boehler if($res !== false) 95213b16484SAndreas Boehler return true; 95313b16484SAndreas Boehler return false; 95413b16484SAndreas Boehler } 95513b16484SAndreas Boehler 95613b16484SAndreas Boehler /** 957cb71a62aSAndreas Boehler * Retrieve all events that are within a given date range, 958cb71a62aSAndreas Boehler * based on the timezone setting. 959cb71a62aSAndreas Boehler * 960cb71a62aSAndreas Boehler * There is also support for retrieving recurring events, 961cb71a62aSAndreas Boehler * using Sabre's VObject Iterator. Recurring events are represented 962cb71a62aSAndreas Boehler * as individual calendar entries with the same UID. 963cb71a62aSAndreas Boehler * 964cb71a62aSAndreas Boehler * @param string $id The page ID to work with 965cb71a62aSAndreas Boehler * @param string $user The user ID to work with 966cb71a62aSAndreas Boehler * @param string $startDate The start date as a string 967cb71a62aSAndreas Boehler * @param string $endDate The end date as a string 9684a2bf5eeSAndreas Boehler * @param string $color (optional) The calendar's color 969cb71a62aSAndreas Boehler * 970cb71a62aSAndreas Boehler * @return array An array containing the calendar entries. 971cb71a62aSAndreas Boehler */ 9724a2bf5eeSAndreas Boehler public function getEventsWithinDateRange($id, $user, $startDate, $endDate, $timezone, $color = null) 973a1a3b679SAndreas Boehler { 97482a48dfbSAndreas Boehler if($timezone !== '' && $timezone !== 'local') 97582a48dfbSAndreas Boehler $timezone = new \DateTimeZone($timezone); 976bd883736SAndreas Boehler else 977bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 978a1a3b679SAndreas Boehler $data = array(); 979cb71a62aSAndreas Boehler 9805f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 9815f2c3e2dSAndreas Boehler if(!$sqlite) 9825f2c3e2dSAndreas Boehler return false; 9835f2c3e2dSAndreas Boehler 984a469597cSAndreas Boehler $query = "SELECT calendardata, componenttype, uid FROM calendarobjects WHERE calendarid = ?"; 985a469597cSAndreas Boehler $startTs = null; 986a469597cSAndreas Boehler $endTs = null; 987a469597cSAndreas Boehler if($startDate !== null) 988a469597cSAndreas Boehler { 989a1a3b679SAndreas Boehler $startTs = new \DateTime($startDate); 9905f2c3e2dSAndreas Boehler $query .= " AND lastoccurence > ".$sqlite->quote_string($startTs->getTimestamp()); 991a469597cSAndreas Boehler } 992a469597cSAndreas Boehler if($endDate !== null) 993a469597cSAndreas Boehler { 994a1a3b679SAndreas Boehler $endTs = new \DateTime($endDate); 9955f2c3e2dSAndreas Boehler $query .= " AND firstoccurence < ".$sqlite->quote_string($endTs->getTimestamp()); 996a469597cSAndreas Boehler } 997cb71a62aSAndreas Boehler 9980b805092SAndreas Boehler // Load SabreDAV 9990b805092SAndreas Boehler require_once(DOKU_PLUGIN.'davcal/vendor/autoload.php'); 10000b805092SAndreas Boehler 10010b805092SAndreas Boehler if(strpos($id, 'webdav://') === 0) 10020b805092SAndreas Boehler { 10030b805092SAndreas Boehler $wdc =& plugin_load('helper', 'webdavclient'); 10040b805092SAndreas Boehler if(is_null($wdc)) 10050b805092SAndreas Boehler return $data; 10060b805092SAndreas Boehler $connectionId = str_replace('webdav://', '', $id); 10070b805092SAndreas Boehler $arr = $wdc->getCalendarEntries($connectionId, $startDate, $endDate); 10080b805092SAndreas Boehler } 10090b805092SAndreas Boehler else 10100b805092SAndreas Boehler { 10110b805092SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 10120b805092SAndreas Boehler if(is_null($color)) 10130b805092SAndreas Boehler $color = $this->getCalendarColorForCalendar($calid); 10140b805092SAndreas Boehler 101559b68239SAndreas Boehler $enabled = $this->getCalendarStatus($calid); 101659b68239SAndreas Boehler if($enabled === false) 101759b68239SAndreas Boehler return $data; 101859b68239SAndreas Boehler 1019cb71a62aSAndreas Boehler // Retrieve matching calendar objects 10205f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid); 10215f2c3e2dSAndreas Boehler $arr = $sqlite->res2arr($res); 10220b805092SAndreas Boehler } 1023cb71a62aSAndreas Boehler 1024cb71a62aSAndreas Boehler // Parse individual calendar entries 1025a1a3b679SAndreas Boehler foreach($arr as $row) 1026a1a3b679SAndreas Boehler { 1027a1a3b679SAndreas Boehler if(isset($row['calendardata'])) 1028a1a3b679SAndreas Boehler { 1029b269830cSAndreas Boehler $entry = array(); 1030a1a3b679SAndreas Boehler $vcal = \Sabre\VObject\Reader::read($row['calendardata']); 1031ebc4eb57SAndreas Boehler $recurrence = $vcal->VEVENT->RRULE; 1032cb71a62aSAndreas Boehler // If it is a recurring event, pass it through Sabre's EventIterator 1033ebc4eb57SAndreas Boehler if($recurrence != null) 1034ebc4eb57SAndreas Boehler { 1035ebc4eb57SAndreas Boehler $rEvents = new \Sabre\VObject\Recur\EventIterator(array($vcal->VEVENT)); 1036ebc4eb57SAndreas Boehler $rEvents->rewind(); 1037e9b7d302SAndreas Boehler while($rEvents->valid()) 1038ebc4eb57SAndreas Boehler { 1039ebc4eb57SAndreas Boehler $event = $rEvents->getEventObject(); 1040cb71a62aSAndreas Boehler // If we are after the given time range, exit 1041a469597cSAndreas Boehler if(($endTs !== null) && ($rEvents->getDtStart()->getTimestamp() > $endTs->getTimestamp())) 1042e9b7d302SAndreas Boehler break; 1043cb71a62aSAndreas Boehler 1044cb71a62aSAndreas Boehler // If we are before the given time range, continue 1045a469597cSAndreas Boehler if(($startTs != null) && ($rEvents->getDtEnd()->getTimestamp() < $startTs->getTimestamp())) 1046ebc4eb57SAndreas Boehler { 1047ebc4eb57SAndreas Boehler $rEvents->next(); 1048ebc4eb57SAndreas Boehler continue; 1049ebc4eb57SAndreas Boehler } 1050cb71a62aSAndreas Boehler 1051cb71a62aSAndreas Boehler // If we are within the given time range, parse the event 1052185e2535SAndreas Boehler $data[] = $this->convertIcalDataToEntry($event, $id, $timezone, $row['uid'], $color, true); 1053ebc4eb57SAndreas Boehler $rEvents->next(); 1054ebc4eb57SAndreas Boehler } 1055ebc4eb57SAndreas Boehler } 1056ebc4eb57SAndreas Boehler else 1057185e2535SAndreas Boehler $data[] = $this->convertIcalDataToEntry($vcal->VEVENT, $id, $timezone, $row['uid'], $color); 1058ebc4eb57SAndreas Boehler } 1059ebc4eb57SAndreas Boehler } 1060ebc4eb57SAndreas Boehler return $data; 1061ebc4eb57SAndreas Boehler } 1062ebc4eb57SAndreas Boehler 1063cb71a62aSAndreas Boehler /** 1064cb71a62aSAndreas Boehler * Helper function that parses the iCal data of a VEVENT to a calendar entry. 1065cb71a62aSAndreas Boehler * 1066cb71a62aSAndreas Boehler * @param \Sabre\VObject\VEvent $event The event to parse 1067cb71a62aSAndreas Boehler * @param \DateTimeZone $timezone The timezone object 1068cb71a62aSAndreas Boehler * @param string $uid The entry's UID 10693c86dda8SAndreas Boehler * @param boolean $recurring (optional) Set to true to define a recurring event 1070cb71a62aSAndreas Boehler * 1071cb71a62aSAndreas Boehler * @return array The parse calendar entry 1072cb71a62aSAndreas Boehler */ 1073185e2535SAndreas Boehler private function convertIcalDataToEntry($event, $page, $timezone, $uid, $color, $recurring = false) 1074ebc4eb57SAndreas Boehler { 1075ebc4eb57SAndreas Boehler $entry = array(); 1076ebc4eb57SAndreas Boehler $start = $event->DTSTART; 1077cb71a62aSAndreas Boehler // Parse only if the start date/time is present 1078b269830cSAndreas Boehler if($start !== null) 1079b269830cSAndreas Boehler { 1080b269830cSAndreas Boehler $dtStart = $start->getDateTime(); 1081b269830cSAndreas Boehler $dtStart->setTimezone($timezone); 1082bf0ad2b4SAndreas Boehler 1083bf0ad2b4SAndreas Boehler // moment.js doesn't like times be given even if 1084bf0ad2b4SAndreas Boehler // allDay is set to true 1085bf0ad2b4SAndreas Boehler // This should fix T23 1086b269830cSAndreas Boehler if($start['VALUE'] == 'DATE') 1087bf0ad2b4SAndreas Boehler { 1088b269830cSAndreas Boehler $entry['allDay'] = true; 1089bf0ad2b4SAndreas Boehler $entry['start'] = $dtStart->format("Y-m-d"); 1090bf0ad2b4SAndreas Boehler } 1091b269830cSAndreas Boehler else 1092bf0ad2b4SAndreas Boehler { 1093b269830cSAndreas Boehler $entry['allDay'] = false; 1094bf0ad2b4SAndreas Boehler $entry['start'] = $dtStart->format(\DateTime::ATOM); 1095bf0ad2b4SAndreas Boehler } 1096b269830cSAndreas Boehler } 1097ebc4eb57SAndreas Boehler $end = $event->DTEND; 1098bf0ad2b4SAndreas Boehler // Parse only if the end date/time is present 1099b269830cSAndreas Boehler if($end !== null) 1100b269830cSAndreas Boehler { 1101b269830cSAndreas Boehler $dtEnd = $end->getDateTime(); 1102b269830cSAndreas Boehler $dtEnd->setTimezone($timezone); 1103bf0ad2b4SAndreas Boehler if($end['VALUE'] == 'DATE') 1104bf0ad2b4SAndreas Boehler $entry['end'] = $dtEnd->format("Y-m-d"); 1105bf0ad2b4SAndreas Boehler else 1106b269830cSAndreas Boehler $entry['end'] = $dtEnd->format(\DateTime::ATOM); 1107b269830cSAndreas Boehler } 1108ebc4eb57SAndreas Boehler $description = $event->DESCRIPTION; 11090eebc909SAndreas Boehler if($description !== null) 11100eebc909SAndreas Boehler $entry['description'] = (string)$description; 11110eebc909SAndreas Boehler else 11120eebc909SAndreas Boehler $entry['description'] = ''; 11134ecb526cSAndreas Boehler $attachments = $event->ATTACH; 11144ecb526cSAndreas Boehler if($attachments !== null) 11154ecb526cSAndreas Boehler { 11164ecb526cSAndreas Boehler $entry['attachments'] = array(); 11174ecb526cSAndreas Boehler foreach($attachments as $attachment) 11184ecb526cSAndreas Boehler $entry['attachments'][] = (string)$attachment; 11194ecb526cSAndreas Boehler } 1120ebc4eb57SAndreas Boehler $entry['title'] = (string)$event->summary; 11212b7be5bdSAndreas Boehler $entry['location'] = (string)$event->location; 1122ebc4eb57SAndreas Boehler $entry['id'] = $uid; 1123185e2535SAndreas Boehler $entry['page'] = $page; 1124185e2535SAndreas Boehler $entry['color'] = $color; 11253c86dda8SAndreas Boehler $entry['recurring'] = $recurring; 1126185e2535SAndreas Boehler 1127ebc4eb57SAndreas Boehler return $entry; 1128a1a3b679SAndreas Boehler } 1129a1a3b679SAndreas Boehler 1130cb71a62aSAndreas Boehler /** 1131cb71a62aSAndreas Boehler * Retrieve an event by its UID 1132cb71a62aSAndreas Boehler * 1133cb71a62aSAndreas Boehler * @param string $uid The event's UID 1134cb71a62aSAndreas Boehler * 1135cb71a62aSAndreas Boehler * @return mixed The table row with the given event 1136cb71a62aSAndreas Boehler */ 1137a1a3b679SAndreas Boehler public function getEventWithUid($uid) 1138a1a3b679SAndreas Boehler { 11395f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 11405f2c3e2dSAndreas Boehler if(!$sqlite) 11415f2c3e2dSAndreas Boehler return false; 114251f4febbSAndreas Boehler $query = "SELECT calendardata, calendarid, componenttype, uri FROM calendarobjects WHERE uid = ?"; 11435f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $uid); 11445f2c3e2dSAndreas Boehler $row = $sqlite->res2row($res); 1145a1a3b679SAndreas Boehler return $row; 1146a1a3b679SAndreas Boehler } 1147a1a3b679SAndreas Boehler 1148cb71a62aSAndreas Boehler /** 1149d5703f5aSAndreas Boehler * Retrieve information of a calendar's object, not including the actual 115059b68239SAndreas Boehler * calendar data! This is mainly needed for the sync support. 1151d5703f5aSAndreas Boehler * 1152d5703f5aSAndreas Boehler * @param int $calid The calendar ID 1153d5703f5aSAndreas Boehler * 1154d5703f5aSAndreas Boehler * @return mixed The result 1155d5703f5aSAndreas Boehler */ 1156d5703f5aSAndreas Boehler public function getCalendarObjects($calid) 1157d5703f5aSAndreas Boehler { 11585f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 11595f2c3e2dSAndreas Boehler if(!$sqlite) 11605f2c3e2dSAndreas Boehler return false; 1161d5703f5aSAndreas Boehler $query = "SELECT id, uri, lastmodified, etag, calendarid, size, componenttype FROM calendarobjects WHERE calendarid = ?"; 11625f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid); 11635f2c3e2dSAndreas Boehler $arr = $sqlite->res2arr($res); 1164d5703f5aSAndreas Boehler return $arr; 1165d5703f5aSAndreas Boehler } 1166d5703f5aSAndreas Boehler 1167d5703f5aSAndreas Boehler /** 1168d5703f5aSAndreas Boehler * Retrieve a single calendar object by calendar ID and URI 1169d5703f5aSAndreas Boehler * 1170d5703f5aSAndreas Boehler * @param int $calid The calendar's ID 1171d5703f5aSAndreas Boehler * @param string $uri The object's URI 1172d5703f5aSAndreas Boehler * 1173d5703f5aSAndreas Boehler * @return mixed The result 1174d5703f5aSAndreas Boehler */ 1175d5703f5aSAndreas Boehler public function getCalendarObjectByUri($calid, $uri) 1176d5703f5aSAndreas Boehler { 11775f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 11785f2c3e2dSAndreas Boehler if(!$sqlite) 11795f2c3e2dSAndreas Boehler return false; 1180d5703f5aSAndreas Boehler $query = "SELECT id, uri, lastmodified, etag, calendarid, size, calendardata, componenttype FROM calendarobjects WHERE calendarid = ? AND uri = ?"; 11815f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid, $uri); 11825f2c3e2dSAndreas Boehler $row = $sqlite->res2row($res); 1183d5703f5aSAndreas Boehler return $row; 1184d5703f5aSAndreas Boehler } 1185d5703f5aSAndreas Boehler 1186d5703f5aSAndreas Boehler /** 1187d5703f5aSAndreas Boehler * Retrieve several calendar objects by specifying an array of URIs. 1188d5703f5aSAndreas Boehler * This is mainly neede for sync. 1189d5703f5aSAndreas Boehler * 1190d5703f5aSAndreas Boehler * @param int $calid The calendar's ID 1191d5703f5aSAndreas Boehler * @param array $uris An array of URIs 1192d5703f5aSAndreas Boehler * 1193d5703f5aSAndreas Boehler * @return mixed The result 1194d5703f5aSAndreas Boehler */ 1195d5703f5aSAndreas Boehler public function getMultipleCalendarObjectsByUri($calid, $uris) 1196d5703f5aSAndreas Boehler { 11975f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 11985f2c3e2dSAndreas Boehler if(!$sqlite) 11995f2c3e2dSAndreas Boehler return false; 1200d5703f5aSAndreas Boehler $query = "SELECT id, uri, lastmodified, etag, calendarid, size, calendardata, componenttype FROM calendarobjects WHERE calendarid = ? AND uri IN ("; 1201d5703f5aSAndreas Boehler // Inserting a whole bunch of question marks 1202d5703f5aSAndreas Boehler $query .= implode(',', array_fill(0, count($uris), '?')); 1203d5703f5aSAndreas Boehler $query .= ')'; 1204d5703f5aSAndreas Boehler $vals = array_merge(array($calid), $uris); 1205d5703f5aSAndreas Boehler 12065f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $vals); 12075f2c3e2dSAndreas Boehler $arr = $sqlite->res2arr($res); 1208d5703f5aSAndreas Boehler return $arr; 1209d5703f5aSAndreas Boehler } 1210d5703f5aSAndreas Boehler 1211d5703f5aSAndreas Boehler /** 1212cb71a62aSAndreas Boehler * Retrieve all calendar events for a given calendar ID 1213cb71a62aSAndreas Boehler * 1214cb71a62aSAndreas Boehler * @param string $calid The calendar's ID 1215cb71a62aSAndreas Boehler * 1216cb71a62aSAndreas Boehler * @return array An array containing all calendar data 1217cb71a62aSAndreas Boehler */ 1218f69bb449SAndreas Boehler public function getAllCalendarEvents($calid) 1219f69bb449SAndreas Boehler { 122059b68239SAndreas Boehler $enabled = $this->getCalendarStatus($calid); 122159b68239SAndreas Boehler if($enabled === false) 122259b68239SAndreas Boehler return false; 12235f2c3e2dSAndreas Boehler 12245f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 12255f2c3e2dSAndreas Boehler if(!$sqlite) 12265f2c3e2dSAndreas Boehler return false; 12277e0b8590SAndreas Boehler $query = "SELECT calendardata, uid, componenttype, uri FROM calendarobjects WHERE calendarid = ?"; 12285f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid); 12295f2c3e2dSAndreas Boehler $arr = $sqlite->res2arr($res); 1230f69bb449SAndreas Boehler return $arr; 1231f69bb449SAndreas Boehler } 1232f69bb449SAndreas Boehler 1233cb71a62aSAndreas Boehler /** 1234cb71a62aSAndreas Boehler * Edit a calendar entry for a page, given by its parameters. 1235cb71a62aSAndreas Boehler * The params array has the same format as @see addCalendarEntryForPage 1236cb71a62aSAndreas Boehler * 1237cb71a62aSAndreas Boehler * @param string $id The page's ID to work on 1238cb71a62aSAndreas Boehler * @param string $user The user's ID to work on 1239cb71a62aSAndreas Boehler * @param array $params The parameter array for the edited calendar event 1240cb71a62aSAndreas Boehler * 1241cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 1242cb71a62aSAndreas Boehler */ 1243a1a3b679SAndreas Boehler public function editCalendarEntryForPage($id, $user, $params) 1244a1a3b679SAndreas Boehler { 124582a48dfbSAndreas Boehler if($params['currenttz'] !== '' && $params['currenttz'] !== 'local') 124682a48dfbSAndreas Boehler $timezone = new \DateTimeZone($params['currenttz']); 124782a48dfbSAndreas Boehler elseif($params['currenttz'] === 'local') 1248a25c89eaSAndreas Boehler $timezone = new \DateTimeZone($params['detectedtz']); 1249bd883736SAndreas Boehler else 1250bd883736SAndreas Boehler $timezone = new \DateTimeZone('UTC'); 1251cb71a62aSAndreas Boehler 1252cb71a62aSAndreas Boehler // Parse dates 1253b269830cSAndreas Boehler $startDate = explode('-', $params['eventfrom']); 1254b269830cSAndreas Boehler $startTime = explode(':', $params['eventfromtime']); 1255b269830cSAndreas Boehler $endDate = explode('-', $params['eventto']); 1256b269830cSAndreas Boehler $endTime = explode(':', $params['eventtotime']); 1257cb71a62aSAndreas Boehler 1258cb71a62aSAndreas Boehler // Retrieve the existing event based on the UID 125955a741c0SAndreas Boehler $uid = $params['uid']; 1260809cb0faSAndreas Boehler 1261809cb0faSAndreas Boehler if(strpos($id, 'webdav://') === 0) 1262809cb0faSAndreas Boehler { 1263809cb0faSAndreas Boehler $wdc =& plugin_load('helper', 'webdavclient'); 1264809cb0faSAndreas Boehler if(is_null($wdc)) 1265809cb0faSAndreas Boehler return false; 1266809cb0faSAndreas Boehler $event = $wdc->getCalendarEntryByUid($uid); 1267809cb0faSAndreas Boehler } 1268809cb0faSAndreas Boehler else 1269809cb0faSAndreas Boehler { 127055a741c0SAndreas Boehler $event = $this->getEventWithUid($uid); 1271809cb0faSAndreas Boehler } 1272cb71a62aSAndreas Boehler 1273cb71a62aSAndreas Boehler // Load SabreDAV 12749bef4ad8SAndreas Boehler require_once(DOKU_PLUGIN.'davcal/vendor/autoload.php'); 1275a1a3b679SAndreas Boehler if(!isset($event['calendardata'])) 1276a1a3b679SAndreas Boehler return false; 127755a741c0SAndreas Boehler $uri = $event['uri']; 127855a741c0SAndreas Boehler $calid = $event['calendarid']; 1279cb71a62aSAndreas Boehler 1280cb71a62aSAndreas Boehler // Parse the existing event 1281a1a3b679SAndreas Boehler $vcal = \Sabre\VObject\Reader::read($event['calendardata']); 1282b269830cSAndreas Boehler $vevent = $vcal->VEVENT; 1283cb71a62aSAndreas Boehler 1284cb71a62aSAndreas Boehler // Set the new event values 1285b269830cSAndreas Boehler $vevent->summary = $params['eventname']; 1286b269830cSAndreas Boehler $dtStamp = new \DateTime(null, new \DateTimeZone('UTC')); 12870eebc909SAndreas Boehler $description = $params['eventdescription']; 12882b7be5bdSAndreas Boehler $location = $params['eventlocation']; 1289cb71a62aSAndreas Boehler 1290cb71a62aSAndreas Boehler // Remove existing timestamps to overwrite them 12910eebc909SAndreas Boehler $vevent->remove('DESCRIPTION'); 1292b269830cSAndreas Boehler $vevent->remove('DTSTAMP'); 1293b269830cSAndreas Boehler $vevent->remove('LAST-MODIFIED'); 12944ecb526cSAndreas Boehler $vevent->remove('ATTACH'); 12952b7be5bdSAndreas Boehler $vevent->remove('LOCATION'); 1296cb71a62aSAndreas Boehler 12972b7be5bdSAndreas Boehler // Add new time stamps, description and location 1298b269830cSAndreas Boehler $vevent->add('DTSTAMP', $dtStamp); 1299b269830cSAndreas Boehler $vevent->add('LAST-MODIFIED', $dtStamp); 13000eebc909SAndreas Boehler if($description !== '') 13010eebc909SAndreas Boehler $vevent->add('DESCRIPTION', $description); 13022b7be5bdSAndreas Boehler if($location !== '') 13032b7be5bdSAndreas Boehler $vevent->add('LOCATION', $location); 1304cb71a62aSAndreas Boehler 13054ecb526cSAndreas Boehler // Add attachments 13064ecb526cSAndreas Boehler $attachments = $params['attachments']; 130782a48dfbSAndreas Boehler if(!is_null($attachments)) 13084ecb526cSAndreas Boehler foreach($attachments as $attachment) 13094ecb526cSAndreas Boehler $vevent->add('ATTACH', $attachment); 13104ecb526cSAndreas Boehler 1311cb71a62aSAndreas Boehler // Setup DTSTART 1312b269830cSAndreas Boehler $dtStart = new \DateTime(); 1313a25c89eaSAndreas Boehler $dtStart->setTimezone($timezone); 1314b269830cSAndreas Boehler $dtStart->setDate(intval($startDate[0]), intval($startDate[1]), intval($startDate[2])); 1315b269830cSAndreas Boehler if($params['allday'] != '1') 1316b269830cSAndreas Boehler $dtStart->setTime(intval($startTime[0]), intval($startTime[1]), 0); 1317cb71a62aSAndreas Boehler 13184ecb526cSAndreas Boehler // Setup DTEND 1319b269830cSAndreas Boehler $dtEnd = new \DateTime(); 1320a25c89eaSAndreas Boehler $dtEnd->setTimezone($timezone); 1321b269830cSAndreas Boehler $dtEnd->setDate(intval($endDate[0]), intval($endDate[1]), intval($endDate[2])); 1322b269830cSAndreas Boehler if($params['allday'] != '1') 1323b269830cSAndreas Boehler $dtEnd->setTime(intval($endTime[0]), intval($endTime[1]), 0); 1324cb71a62aSAndreas Boehler 1325b269830cSAndreas Boehler // According to the VCal spec, we need to add a whole day here 1326b269830cSAndreas Boehler if($params['allday'] == '1') 1327b269830cSAndreas Boehler $dtEnd->add(new \DateInterval('P1D')); 1328b269830cSAndreas Boehler $vevent->remove('DTSTART'); 1329b269830cSAndreas Boehler $vevent->remove('DTEND'); 1330b269830cSAndreas Boehler $dtStartEv = $vevent->add('DTSTART', $dtStart); 1331b269830cSAndreas Boehler $dtEndEv = $vevent->add('DTEND', $dtEnd); 1332cb71a62aSAndreas Boehler 1333cb71a62aSAndreas Boehler // Remove the time for allday events 1334b269830cSAndreas Boehler if($params['allday'] == '1') 1335b269830cSAndreas Boehler { 1336b269830cSAndreas Boehler $dtStartEv['VALUE'] = 'DATE'; 1337b269830cSAndreas Boehler $dtEndEv['VALUE'] = 'DATE'; 1338b269830cSAndreas Boehler } 1339a1a3b679SAndreas Boehler $eventStr = $vcal->serialize(); 1340809cb0faSAndreas Boehler if(strpos($id, 'webdav://') === 0) 1341809cb0faSAndreas Boehler { 1342809cb0faSAndreas Boehler $connectionId = str_replace('webdav://', '', $id); 1343809cb0faSAndreas Boehler return $wdc->editCalendarEntry($connectionId, $uid, $eventStr); 1344809cb0faSAndreas Boehler } 1345809cb0faSAndreas Boehler else 1346809cb0faSAndreas Boehler { 13475f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 13485f2c3e2dSAndreas Boehler if(!$sqlite) 13495f2c3e2dSAndreas Boehler return false; 1350809cb0faSAndreas Boehler $now = new DateTime(); 1351cb71a62aSAndreas Boehler // Actually write to the database 135251f4febbSAndreas Boehler $query = "UPDATE calendarobjects SET calendardata = ?, lastmodified = ?, ". 135351f4febbSAndreas Boehler "firstoccurence = ?, lastoccurence = ?, size = ?, etag = ? WHERE uid = ?"; 13545f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $eventStr, $now->getTimestamp(), $dtStart->getTimestamp(), 135551f4febbSAndreas Boehler $dtEnd->getTimestamp(), strlen($eventStr), md5($eventStr), $uid); 135655a741c0SAndreas Boehler if($res !== false) 135755a741c0SAndreas Boehler { 135855a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'modified'); 1359a1a3b679SAndreas Boehler return true; 1360a1a3b679SAndreas Boehler } 1361809cb0faSAndreas Boehler } 136255a741c0SAndreas Boehler return false; 136355a741c0SAndreas Boehler } 1364a1a3b679SAndreas Boehler 1365cb71a62aSAndreas Boehler /** 1366d5703f5aSAndreas Boehler * Delete an event from a calendar by calendar ID and URI 1367d5703f5aSAndreas Boehler * 1368d5703f5aSAndreas Boehler * @param int $calid The calendar's ID 1369d5703f5aSAndreas Boehler * @param string $uri The object's URI 1370d5703f5aSAndreas Boehler * 1371d5703f5aSAndreas Boehler * @return true 1372d5703f5aSAndreas Boehler */ 1373d5703f5aSAndreas Boehler public function deleteCalendarEntryForCalendarByUri($calid, $uri) 1374d5703f5aSAndreas Boehler { 13755f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 13765f2c3e2dSAndreas Boehler if(!$sqlite) 13775f2c3e2dSAndreas Boehler return false; 1378d5703f5aSAndreas Boehler $query = "DELETE FROM calendarobjects WHERE calendarid = ? AND uri = ?"; 13795f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid, $uri); 1380d5703f5aSAndreas Boehler if($res !== false) 1381d5703f5aSAndreas Boehler { 1382d5703f5aSAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'deleted'); 1383d5703f5aSAndreas Boehler } 1384d5703f5aSAndreas Boehler return true; 1385d5703f5aSAndreas Boehler } 1386d5703f5aSAndreas Boehler 1387d5703f5aSAndreas Boehler /** 1388cb71a62aSAndreas Boehler * Delete a calendar entry for a given page. Actually, the event is removed 1389cb71a62aSAndreas Boehler * based on the entry's UID, so that page ID is no used. 1390cb71a62aSAndreas Boehler * 1391cb71a62aSAndreas Boehler * @param string $id The page's ID (unused) 1392cb71a62aSAndreas Boehler * @param array $params The parameter array to work with 1393cb71a62aSAndreas Boehler * 1394cb71a62aSAndreas Boehler * @return boolean True 1395cb71a62aSAndreas Boehler */ 1396a1a3b679SAndreas Boehler public function deleteCalendarEntryForPage($id, $params) 1397a1a3b679SAndreas Boehler { 1398a1a3b679SAndreas Boehler $uid = $params['uid']; 1399809cb0faSAndreas Boehler if(strpos($id, 'webdav://') === 0) 1400809cb0faSAndreas Boehler { 1401809cb0faSAndreas Boehler $wdc =& plugin_load('helper', 'webdavclient'); 1402809cb0faSAndreas Boehler if(is_null($wdc)) 1403809cb0faSAndreas Boehler return false; 1404809cb0faSAndreas Boehler $connectionId = str_replace('webdav://', '', $id); 1405809cb0faSAndreas Boehler $result = $wdc->deleteCalendarEntry($connectionId, $uid); 1406809cb0faSAndreas Boehler return $result; 1407809cb0faSAndreas Boehler } 14085f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 14095f2c3e2dSAndreas Boehler if(!$sqlite) 14105f2c3e2dSAndreas Boehler return false; 141155a741c0SAndreas Boehler $event = $this->getEventWithUid($uid); 14122c14b82bSAndreas Boehler $calid = $event['calendarid']; 141355a741c0SAndreas Boehler $uri = $event['uri']; 141451f4febbSAndreas Boehler $query = "DELETE FROM calendarobjects WHERE uid = ?"; 14155f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $uid); 141655a741c0SAndreas Boehler if($res !== false) 141755a741c0SAndreas Boehler { 141855a741c0SAndreas Boehler $this->updateSyncTokenLog($calid, $uri, 'deleted'); 141955a741c0SAndreas Boehler } 1420a1a3b679SAndreas Boehler return true; 1421a1a3b679SAndreas Boehler } 1422a1a3b679SAndreas Boehler 1423cb71a62aSAndreas Boehler /** 1424cb71a62aSAndreas Boehler * Retrieve the current sync token for a calendar 1425cb71a62aSAndreas Boehler * 1426cb71a62aSAndreas Boehler * @param string $calid The calendar id 1427cb71a62aSAndreas Boehler * 1428cb71a62aSAndreas Boehler * @return mixed The synctoken or false 1429cb71a62aSAndreas Boehler */ 143055a741c0SAndreas Boehler public function getSyncTokenForCalendar($calid) 143155a741c0SAndreas Boehler { 1432b269830cSAndreas Boehler $row = $this->getCalendarSettings($calid); 143355a741c0SAndreas Boehler if(isset($row['synctoken'])) 143455a741c0SAndreas Boehler return $row['synctoken']; 143555a741c0SAndreas Boehler return false; 143655a741c0SAndreas Boehler } 143755a741c0SAndreas Boehler 1438cb71a62aSAndreas Boehler /** 1439cb71a62aSAndreas Boehler * Helper function to convert the operation name to 1440cb71a62aSAndreas Boehler * an operation code as stored in the database 1441cb71a62aSAndreas Boehler * 1442cb71a62aSAndreas Boehler * @param string $operationName The operation name 1443cb71a62aSAndreas Boehler * 1444cb71a62aSAndreas Boehler * @return mixed The operation code or false 1445cb71a62aSAndreas Boehler */ 144655a741c0SAndreas Boehler public function operationNameToOperation($operationName) 144755a741c0SAndreas Boehler { 144855a741c0SAndreas Boehler switch($operationName) 144955a741c0SAndreas Boehler { 145055a741c0SAndreas Boehler case 'added': 145155a741c0SAndreas Boehler return 1; 145255a741c0SAndreas Boehler break; 145355a741c0SAndreas Boehler case 'modified': 145455a741c0SAndreas Boehler return 2; 145555a741c0SAndreas Boehler break; 145655a741c0SAndreas Boehler case 'deleted': 145755a741c0SAndreas Boehler return 3; 145855a741c0SAndreas Boehler break; 145955a741c0SAndreas Boehler } 146055a741c0SAndreas Boehler return false; 146155a741c0SAndreas Boehler } 146255a741c0SAndreas Boehler 1463cb71a62aSAndreas Boehler /** 1464cb71a62aSAndreas Boehler * Update the sync token log based on the calendar id and the 1465cb71a62aSAndreas Boehler * operation that was performed. 1466cb71a62aSAndreas Boehler * 1467cb71a62aSAndreas Boehler * @param string $calid The calendar ID that was modified 1468cb71a62aSAndreas Boehler * @param string $uri The calendar URI that was modified 1469cb71a62aSAndreas Boehler * @param string $operation The operation that was performed 1470cb71a62aSAndreas Boehler * 1471cb71a62aSAndreas Boehler * @return boolean True on success, otherwise false 1472cb71a62aSAndreas Boehler */ 147355a741c0SAndreas Boehler private function updateSyncTokenLog($calid, $uri, $operation) 147455a741c0SAndreas Boehler { 147555a741c0SAndreas Boehler $currentToken = $this->getSyncTokenForCalendar($calid); 147655a741c0SAndreas Boehler $operationCode = $this->operationNameToOperation($operation); 147755a741c0SAndreas Boehler if(($operationCode === false) || ($currentToken === false)) 147855a741c0SAndreas Boehler return false; 147955a741c0SAndreas Boehler $values = array($uri, 148055a741c0SAndreas Boehler $currentToken, 148155a741c0SAndreas Boehler $calid, 148255a741c0SAndreas Boehler $operationCode 148355a741c0SAndreas Boehler ); 14845f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 14855f2c3e2dSAndreas Boehler if(!$sqlite) 14865f2c3e2dSAndreas Boehler return false; 148751f4febbSAndreas Boehler $query = "INSERT INTO calendarchanges (uri, synctoken, calendarid, operation) VALUES(?, ?, ?, ?)"; 14885f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $uri, $currentToken, $calid, $operationCode); 148955a741c0SAndreas Boehler if($res === false) 149055a741c0SAndreas Boehler return false; 149155a741c0SAndreas Boehler $currentToken++; 149251f4febbSAndreas Boehler $query = "UPDATE calendars SET synctoken = ? WHERE id = ?"; 14935f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $currentToken, $calid); 149455a741c0SAndreas Boehler return ($res !== false); 149555a741c0SAndreas Boehler } 149655a741c0SAndreas Boehler 1497cb71a62aSAndreas Boehler /** 1498cb71a62aSAndreas Boehler * Return the sync URL for a given Page, i.e. a calendar 1499cb71a62aSAndreas Boehler * 1500cb71a62aSAndreas Boehler * @param string $id The page's ID 1501cb71a62aSAndreas Boehler * @param string $user (optional) The user's ID 1502cb71a62aSAndreas Boehler * 1503cb71a62aSAndreas Boehler * @return mixed The sync url or false 1504cb71a62aSAndreas Boehler */ 1505b269830cSAndreas Boehler public function getSyncUrlForPage($id, $user = null) 1506b269830cSAndreas Boehler { 150734a47953SAndreas Boehler if(is_null($userid)) 150834a47953SAndreas Boehler { 150934a47953SAndreas Boehler if(isset($_SERVER['REMOTE_USER']) && !is_null($_SERVER['REMOTE_USER'])) 151034a47953SAndreas Boehler { 151134a47953SAndreas Boehler $userid = $_SERVER['REMOTE_USER']; 151234a47953SAndreas Boehler } 151334a47953SAndreas Boehler else 151434a47953SAndreas Boehler { 151534a47953SAndreas Boehler return false; 151634a47953SAndreas Boehler } 151734a47953SAndreas Boehler } 1518b269830cSAndreas Boehler 1519b269830cSAndreas Boehler $calid = $this->getCalendarIdForPage($id); 1520b269830cSAndreas Boehler if($calid === false) 1521b269830cSAndreas Boehler return false; 1522b269830cSAndreas Boehler 1523b269830cSAndreas Boehler $calsettings = $this->getCalendarSettings($calid); 1524b269830cSAndreas Boehler if(!isset($calsettings['uri'])) 1525b269830cSAndreas Boehler return false; 1526b269830cSAndreas Boehler 1527b269830cSAndreas Boehler $syncurl = DOKU_URL.'lib/plugins/davcal/calendarserver.php/calendars/'.$user.'/'.$calsettings['uri']; 1528b269830cSAndreas Boehler return $syncurl; 1529b269830cSAndreas Boehler } 1530b269830cSAndreas Boehler 1531cb71a62aSAndreas Boehler /** 1532cb71a62aSAndreas Boehler * Return the private calendar's URL for a given page 1533cb71a62aSAndreas Boehler * 1534cb71a62aSAndreas Boehler * @param string $id the page ID 1535cb71a62aSAndreas Boehler * 1536cb71a62aSAndreas Boehler * @return mixed The private URL or false 1537cb71a62aSAndreas Boehler */ 1538f69bb449SAndreas Boehler public function getPrivateURLForPage($id) 1539f69bb449SAndreas Boehler { 1540f69bb449SAndreas Boehler $calid = $this->getCalendarIdForPage($id); 1541f69bb449SAndreas Boehler if($calid === false) 1542f69bb449SAndreas Boehler return false; 1543f69bb449SAndreas Boehler 1544f69bb449SAndreas Boehler return $this->getPrivateURLForCalendar($calid); 1545f69bb449SAndreas Boehler } 1546f69bb449SAndreas Boehler 1547cb71a62aSAndreas Boehler /** 1548cb71a62aSAndreas Boehler * Return the private calendar's URL for a given calendar ID 1549cb71a62aSAndreas Boehler * 1550cb71a62aSAndreas Boehler * @param string $calid The calendar's ID 1551cb71a62aSAndreas Boehler * 1552cb71a62aSAndreas Boehler * @return mixed The private URL or false 1553cb71a62aSAndreas Boehler */ 1554f69bb449SAndreas Boehler public function getPrivateURLForCalendar($calid) 1555f69bb449SAndreas Boehler { 1556185e2535SAndreas Boehler if(isset($this->cachedValues['privateurl'][$calid])) 1557185e2535SAndreas Boehler return $this->cachedValues['privateurl'][$calid]; 15585f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 15595f2c3e2dSAndreas Boehler if(!$sqlite) 15605f2c3e2dSAndreas Boehler return false; 156151f4febbSAndreas Boehler $query = "SELECT url FROM calendartoprivateurlmapping WHERE calid = ?"; 15625f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $calid); 15635f2c3e2dSAndreas Boehler $row = $sqlite->res2row($res); 1564f69bb449SAndreas Boehler if(!isset($row['url'])) 1565f69bb449SAndreas Boehler { 1566f69bb449SAndreas Boehler $url = uniqid("dokuwiki-").".ics"; 156751f4febbSAndreas Boehler $query = "INSERT INTO calendartoprivateurlmapping (url, calid) VALUES(?, ?)"; 15685f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $url, $calid); 1569f69bb449SAndreas Boehler if($res === false) 1570f69bb449SAndreas Boehler return false; 1571f69bb449SAndreas Boehler } 1572f69bb449SAndreas Boehler else 1573f69bb449SAndreas Boehler { 1574f69bb449SAndreas Boehler $url = $row['url']; 1575f69bb449SAndreas Boehler } 1576185e2535SAndreas Boehler 1577185e2535SAndreas Boehler $url = DOKU_URL.'lib/plugins/davcal/ics.php/'.$url; 1578185e2535SAndreas Boehler $this->cachedValues['privateurl'][$calid] = $url; 1579185e2535SAndreas Boehler return $url; 1580f69bb449SAndreas Boehler } 1581f69bb449SAndreas Boehler 1582cb71a62aSAndreas Boehler /** 1583cb71a62aSAndreas Boehler * Retrieve the calendar ID for a given private calendar URL 1584cb71a62aSAndreas Boehler * 1585cb71a62aSAndreas Boehler * @param string $url The private URL 1586cb71a62aSAndreas Boehler * 1587cb71a62aSAndreas Boehler * @return mixed The calendar ID or false 1588cb71a62aSAndreas Boehler */ 1589f69bb449SAndreas Boehler public function getCalendarForPrivateURL($url) 1590f69bb449SAndreas Boehler { 15915f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 15925f2c3e2dSAndreas Boehler if(!$sqlite) 15935f2c3e2dSAndreas Boehler return false; 159451f4febbSAndreas Boehler $query = "SELECT calid FROM calendartoprivateurlmapping WHERE url = ?"; 15955f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $url); 15965f2c3e2dSAndreas Boehler $row = $sqlite->res2row($res); 1597f69bb449SAndreas Boehler if(!isset($row['calid'])) 1598f69bb449SAndreas Boehler return false; 1599f69bb449SAndreas Boehler return $row['calid']; 1600f69bb449SAndreas Boehler } 1601f69bb449SAndreas Boehler 1602cb71a62aSAndreas Boehler /** 1603cb71a62aSAndreas Boehler * Return a given calendar as ICS feed, i.e. all events in one ICS file. 1604cb71a62aSAndreas Boehler * 16057e0b8590SAndreas Boehler * @param string $calid The calendar ID to retrieve 1606cb71a62aSAndreas Boehler * 1607cb71a62aSAndreas Boehler * @return mixed The calendar events as string or false 1608cb71a62aSAndreas Boehler */ 1609f69bb449SAndreas Boehler public function getCalendarAsICSFeed($calid) 1610f69bb449SAndreas Boehler { 1611f69bb449SAndreas Boehler $calSettings = $this->getCalendarSettings($calid); 1612f69bb449SAndreas Boehler if($calSettings === false) 1613f69bb449SAndreas Boehler return false; 1614f69bb449SAndreas Boehler $events = $this->getAllCalendarEvents($calid); 1615f69bb449SAndreas Boehler if($events === false) 1616f69bb449SAndreas Boehler return false; 1617f69bb449SAndreas Boehler 16187e0b8590SAndreas Boehler // Load SabreDAV 16197e0b8590SAndreas Boehler require_once(DOKU_PLUGIN.'davcal/vendor/autoload.php'); 16207e0b8590SAndreas Boehler $out = "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//DAVCal//DAVCal for DokuWiki//EN\r\nCALSCALE:GREGORIAN\r\nX-WR-CALNAME:"; 16217e0b8590SAndreas Boehler $out .= $calSettings['displayname']."\r\n"; 1622f69bb449SAndreas Boehler foreach($events as $event) 1623f69bb449SAndreas Boehler { 16247e0b8590SAndreas Boehler $vcal = \Sabre\VObject\Reader::read($event['calendardata']); 16257e0b8590SAndreas Boehler $evt = $vcal->VEVENT; 16267e0b8590SAndreas Boehler $out .= $evt->serialize(); 1627f69bb449SAndreas Boehler } 16287e0b8590SAndreas Boehler $out .= "END:VCALENDAR\r\n"; 1629f69bb449SAndreas Boehler return $out; 1630f69bb449SAndreas Boehler } 1631f69bb449SAndreas Boehler 16327c7c6b0bSAndreas Boehler /** 16337c7c6b0bSAndreas Boehler * Retrieve a configuration option for the plugin 16347c7c6b0bSAndreas Boehler * 16357c7c6b0bSAndreas Boehler * @param string $key The key to query 163621d04f73SAndreas Boehler * @return mixed The option set, null if not found 16377c7c6b0bSAndreas Boehler */ 16387c7c6b0bSAndreas Boehler public function getConfig($key) 16397c7c6b0bSAndreas Boehler { 16407c7c6b0bSAndreas Boehler return $this->getConf($key); 16417c7c6b0bSAndreas Boehler } 16427c7c6b0bSAndreas Boehler 1643d5703f5aSAndreas Boehler /** 1644d5703f5aSAndreas Boehler * Parses some information from calendar objects, used for optimized 1645d5703f5aSAndreas Boehler * calendar-queries. Taken nearly unmodified from Sabre's PDO backend 1646d5703f5aSAndreas Boehler * 1647d5703f5aSAndreas Boehler * Returns an array with the following keys: 1648d5703f5aSAndreas Boehler * * etag - An md5 checksum of the object without the quotes. 1649d5703f5aSAndreas Boehler * * size - Size of the object in bytes 1650d5703f5aSAndreas Boehler * * componentType - VEVENT, VTODO or VJOURNAL 1651d5703f5aSAndreas Boehler * * firstOccurence 1652d5703f5aSAndreas Boehler * * lastOccurence 1653d5703f5aSAndreas Boehler * * uid - value of the UID property 1654d5703f5aSAndreas Boehler * 1655d5703f5aSAndreas Boehler * @param string $calendarData 1656d5703f5aSAndreas Boehler * @return array 1657d5703f5aSAndreas Boehler */ 1658d5703f5aSAndreas Boehler protected function getDenormalizedData($calendarData) 1659d5703f5aSAndreas Boehler { 1660d5703f5aSAndreas Boehler require_once(DOKU_PLUGIN.'davcal/vendor/autoload.php'); 1661d5703f5aSAndreas Boehler 1662d5703f5aSAndreas Boehler $vObject = \Sabre\VObject\Reader::read($calendarData); 1663d5703f5aSAndreas Boehler $componentType = null; 1664d5703f5aSAndreas Boehler $component = null; 1665d5703f5aSAndreas Boehler $firstOccurence = null; 1666d5703f5aSAndreas Boehler $lastOccurence = null; 1667d5703f5aSAndreas Boehler $uid = null; 1668d5703f5aSAndreas Boehler foreach ($vObject->getComponents() as $component) 1669d5703f5aSAndreas Boehler { 1670d5703f5aSAndreas Boehler if ($component->name !== 'VTIMEZONE') 1671d5703f5aSAndreas Boehler { 1672d5703f5aSAndreas Boehler $componentType = $component->name; 1673d5703f5aSAndreas Boehler $uid = (string)$component->UID; 1674d5703f5aSAndreas Boehler break; 1675d5703f5aSAndreas Boehler } 1676d5703f5aSAndreas Boehler } 1677d5703f5aSAndreas Boehler if (!$componentType) 1678d5703f5aSAndreas Boehler { 1679d5703f5aSAndreas Boehler return false; 1680d5703f5aSAndreas Boehler } 1681d5703f5aSAndreas Boehler if ($componentType === 'VEVENT') 1682d5703f5aSAndreas Boehler { 1683d5703f5aSAndreas Boehler $firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp(); 1684d5703f5aSAndreas Boehler // Finding the last occurence is a bit harder 1685d5703f5aSAndreas Boehler if (!isset($component->RRULE)) 1686d5703f5aSAndreas Boehler { 1687d5703f5aSAndreas Boehler if (isset($component->DTEND)) 1688d5703f5aSAndreas Boehler { 1689d5703f5aSAndreas Boehler $lastOccurence = $component->DTEND->getDateTime()->getTimeStamp(); 1690d5703f5aSAndreas Boehler } 1691d5703f5aSAndreas Boehler elseif (isset($component->DURATION)) 1692d5703f5aSAndreas Boehler { 1693d5703f5aSAndreas Boehler $endDate = clone $component->DTSTART->getDateTime(); 1694d5703f5aSAndreas Boehler $endDate->add(\Sabre\VObject\DateTimeParser::parse($component->DURATION->getValue())); 1695d5703f5aSAndreas Boehler $lastOccurence = $endDate->getTimeStamp(); 1696d5703f5aSAndreas Boehler } 1697d5703f5aSAndreas Boehler elseif (!$component->DTSTART->hasTime()) 1698d5703f5aSAndreas Boehler { 1699d5703f5aSAndreas Boehler $endDate = clone $component->DTSTART->getDateTime(); 1700d5703f5aSAndreas Boehler $endDate->modify('+1 day'); 1701d5703f5aSAndreas Boehler $lastOccurence = $endDate->getTimeStamp(); 1702d5703f5aSAndreas Boehler } 1703d5703f5aSAndreas Boehler else 1704d5703f5aSAndreas Boehler { 1705d5703f5aSAndreas Boehler $lastOccurence = $firstOccurence; 1706d5703f5aSAndreas Boehler } 1707d5703f5aSAndreas Boehler } 1708d5703f5aSAndreas Boehler else 1709d5703f5aSAndreas Boehler { 1710d5703f5aSAndreas Boehler $it = new \Sabre\VObject\Recur\EventIterator($vObject, (string)$component->UID); 1711d5703f5aSAndreas Boehler $maxDate = new \DateTime('2038-01-01'); 1712d5703f5aSAndreas Boehler if ($it->isInfinite()) 1713d5703f5aSAndreas Boehler { 1714d5703f5aSAndreas Boehler $lastOccurence = $maxDate->getTimeStamp(); 1715d5703f5aSAndreas Boehler } 1716d5703f5aSAndreas Boehler else 1717d5703f5aSAndreas Boehler { 1718d5703f5aSAndreas Boehler $end = $it->getDtEnd(); 1719d5703f5aSAndreas Boehler while ($it->valid() && $end < $maxDate) 1720d5703f5aSAndreas Boehler { 1721d5703f5aSAndreas Boehler $end = $it->getDtEnd(); 1722d5703f5aSAndreas Boehler $it->next(); 1723d5703f5aSAndreas Boehler } 1724d5703f5aSAndreas Boehler $lastOccurence = $end->getTimeStamp(); 1725d5703f5aSAndreas Boehler } 1726d5703f5aSAndreas Boehler } 1727d5703f5aSAndreas Boehler } 1728d5703f5aSAndreas Boehler 1729d5703f5aSAndreas Boehler return array( 1730d5703f5aSAndreas Boehler 'etag' => md5($calendarData), 1731d5703f5aSAndreas Boehler 'size' => strlen($calendarData), 1732d5703f5aSAndreas Boehler 'componentType' => $componentType, 1733d5703f5aSAndreas Boehler 'firstOccurence' => $firstOccurence, 1734d5703f5aSAndreas Boehler 'lastOccurence' => $lastOccurence, 1735d5703f5aSAndreas Boehler 'uid' => $uid, 1736d5703f5aSAndreas Boehler ); 1737d5703f5aSAndreas Boehler 1738d5703f5aSAndreas Boehler } 1739d5703f5aSAndreas Boehler 1740d5703f5aSAndreas Boehler /** 1741d5703f5aSAndreas Boehler * Query a calendar by ID and taking several filters into account. 1742d5703f5aSAndreas Boehler * This is heavily based on Sabre's PDO backend. 1743d5703f5aSAndreas Boehler * 1744d5703f5aSAndreas Boehler * @param int $calendarId The calendar's ID 1745d5703f5aSAndreas Boehler * @param array $filters The filter array to apply 1746d5703f5aSAndreas Boehler * 1747d5703f5aSAndreas Boehler * @return mixed The result 1748d5703f5aSAndreas Boehler */ 1749d5703f5aSAndreas Boehler public function calendarQuery($calendarId, $filters) 1750d5703f5aSAndreas Boehler { 175139787131SAndreas Boehler dbglog('davcal::helper::calendarQuery'); 1752d5703f5aSAndreas Boehler $componentType = null; 1753d5703f5aSAndreas Boehler $requirePostFilter = true; 1754d5703f5aSAndreas Boehler $timeRange = null; 17555f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 17565f2c3e2dSAndreas Boehler if(!$sqlite) 17575f2c3e2dSAndreas Boehler return false; 1758d5703f5aSAndreas Boehler 1759d5703f5aSAndreas Boehler // if no filters were specified, we don't need to filter after a query 1760d5703f5aSAndreas Boehler if (!$filters['prop-filters'] && !$filters['comp-filters']) 1761d5703f5aSAndreas Boehler { 1762d5703f5aSAndreas Boehler $requirePostFilter = false; 1763d5703f5aSAndreas Boehler } 1764d5703f5aSAndreas Boehler 1765d5703f5aSAndreas Boehler // Figuring out if there's a component filter 1766d5703f5aSAndreas Boehler if (count($filters['comp-filters']) > 0 && !$filters['comp-filters'][0]['is-not-defined']) 1767d5703f5aSAndreas Boehler { 1768d5703f5aSAndreas Boehler $componentType = $filters['comp-filters'][0]['name']; 1769d5703f5aSAndreas Boehler 1770d5703f5aSAndreas Boehler // Checking if we need post-filters 1771d5703f5aSAndreas Boehler if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['time-range'] && !$filters['comp-filters'][0]['prop-filters']) 1772d5703f5aSAndreas Boehler { 1773d5703f5aSAndreas Boehler $requirePostFilter = false; 1774d5703f5aSAndreas Boehler } 1775d5703f5aSAndreas Boehler // There was a time-range filter 1776d5703f5aSAndreas Boehler if ($componentType == 'VEVENT' && isset($filters['comp-filters'][0]['time-range'])) 1777d5703f5aSAndreas Boehler { 1778d5703f5aSAndreas Boehler $timeRange = $filters['comp-filters'][0]['time-range']; 1779d5703f5aSAndreas Boehler 1780d5703f5aSAndreas Boehler // If start time OR the end time is not specified, we can do a 1781d5703f5aSAndreas Boehler // 100% accurate mysql query. 1782d5703f5aSAndreas Boehler if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['prop-filters'] && (!$timeRange['start'] || !$timeRange['end'])) 1783d5703f5aSAndreas Boehler { 1784d5703f5aSAndreas Boehler $requirePostFilter = false; 1785d5703f5aSAndreas Boehler } 1786d5703f5aSAndreas Boehler } 1787d5703f5aSAndreas Boehler 1788d5703f5aSAndreas Boehler } 1789d5703f5aSAndreas Boehler 1790d5703f5aSAndreas Boehler if ($requirePostFilter) 1791d5703f5aSAndreas Boehler { 1792d5703f5aSAndreas Boehler $query = "SELECT uri, calendardata FROM calendarobjects WHERE calendarid = ?"; 1793d5703f5aSAndreas Boehler } 1794d5703f5aSAndreas Boehler else 1795d5703f5aSAndreas Boehler { 1796d5703f5aSAndreas Boehler $query = "SELECT uri FROM calendarobjects WHERE calendarid = ?"; 1797d5703f5aSAndreas Boehler } 1798d5703f5aSAndreas Boehler 1799d5703f5aSAndreas Boehler $values = array( 1800d5703f5aSAndreas Boehler $calendarId 1801d5703f5aSAndreas Boehler ); 1802d5703f5aSAndreas Boehler 1803d5703f5aSAndreas Boehler if ($componentType) 1804d5703f5aSAndreas Boehler { 1805d5703f5aSAndreas Boehler $query .= " AND componenttype = ?"; 1806d5703f5aSAndreas Boehler $values[] = $componentType; 1807d5703f5aSAndreas Boehler } 1808d5703f5aSAndreas Boehler 1809d5703f5aSAndreas Boehler if ($timeRange && $timeRange['start']) 1810d5703f5aSAndreas Boehler { 1811d5703f5aSAndreas Boehler $query .= " AND lastoccurence > ?"; 1812d5703f5aSAndreas Boehler $values[] = $timeRange['start']->getTimeStamp(); 1813d5703f5aSAndreas Boehler } 1814d5703f5aSAndreas Boehler if ($timeRange && $timeRange['end']) 1815d5703f5aSAndreas Boehler { 1816d5703f5aSAndreas Boehler $query .= " AND firstoccurence < ?"; 1817d5703f5aSAndreas Boehler $values[] = $timeRange['end']->getTimeStamp(); 1818d5703f5aSAndreas Boehler } 1819d5703f5aSAndreas Boehler 18205f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $values); 18215f2c3e2dSAndreas Boehler $arr = $sqlite->res2arr($res); 1822d5703f5aSAndreas Boehler 1823d5703f5aSAndreas Boehler $result = array(); 1824d5703f5aSAndreas Boehler foreach($arr as $row) 1825d5703f5aSAndreas Boehler { 1826d5703f5aSAndreas Boehler if ($requirePostFilter) 1827d5703f5aSAndreas Boehler { 1828d5703f5aSAndreas Boehler if (!$this->validateFilterForObject($row, $filters)) 1829d5703f5aSAndreas Boehler { 1830d5703f5aSAndreas Boehler continue; 1831d5703f5aSAndreas Boehler } 1832d5703f5aSAndreas Boehler } 1833d5703f5aSAndreas Boehler $result[] = $row['uri']; 1834d5703f5aSAndreas Boehler 1835d5703f5aSAndreas Boehler } 1836d5703f5aSAndreas Boehler 1837d5703f5aSAndreas Boehler return $result; 1838d5703f5aSAndreas Boehler } 1839d5703f5aSAndreas Boehler 1840d5703f5aSAndreas Boehler /** 1841d5703f5aSAndreas Boehler * This method validates if a filter (as passed to calendarQuery) matches 1842d5703f5aSAndreas Boehler * the given object. Taken from Sabre's PDO backend 1843d5703f5aSAndreas Boehler * 1844d5703f5aSAndreas Boehler * @param array $object 1845d5703f5aSAndreas Boehler * @param array $filters 1846d5703f5aSAndreas Boehler * @return bool 1847d5703f5aSAndreas Boehler */ 1848d5703f5aSAndreas Boehler protected function validateFilterForObject($object, $filters) 1849d5703f5aSAndreas Boehler { 1850d5703f5aSAndreas Boehler require_once(DOKU_PLUGIN.'davcal/vendor/autoload.php'); 1851d5703f5aSAndreas Boehler // Unfortunately, setting the 'calendardata' here is optional. If 1852d5703f5aSAndreas Boehler // it was excluded, we actually need another call to get this as 1853d5703f5aSAndreas Boehler // well. 1854d5703f5aSAndreas Boehler if (!isset($object['calendardata'])) 1855d5703f5aSAndreas Boehler { 1856d5703f5aSAndreas Boehler $object = $this->getCalendarObjectByUri($object['calendarid'], $object['uri']); 1857d5703f5aSAndreas Boehler } 1858d5703f5aSAndreas Boehler 1859d5703f5aSAndreas Boehler $vObject = \Sabre\VObject\Reader::read($object['calendardata']); 1860d5703f5aSAndreas Boehler $validator = new \Sabre\CalDAV\CalendarQueryValidator(); 1861d5703f5aSAndreas Boehler 186239787131SAndreas Boehler $res = $validator->validate($vObject, $filters); 186339787131SAndreas Boehler return $res; 1864d5703f5aSAndreas Boehler 1865d5703f5aSAndreas Boehler } 1866d5703f5aSAndreas Boehler 1867d5703f5aSAndreas Boehler /** 1868d5703f5aSAndreas Boehler * Retrieve changes for a given calendar based on the given syncToken. 1869d5703f5aSAndreas Boehler * 1870d5703f5aSAndreas Boehler * @param int $calid The calendar's ID 1871d5703f5aSAndreas Boehler * @param int $syncToken The supplied sync token 1872d5703f5aSAndreas Boehler * @param int $syncLevel The sync level 1873d5703f5aSAndreas Boehler * @param int $limit The limit of changes 1874d5703f5aSAndreas Boehler * 1875d5703f5aSAndreas Boehler * @return array The result 1876d5703f5aSAndreas Boehler */ 1877d5703f5aSAndreas Boehler public function getChangesForCalendar($calid, $syncToken, $syncLevel, $limit = null) 1878d5703f5aSAndreas Boehler { 1879d5703f5aSAndreas Boehler // Current synctoken 1880d5703f5aSAndreas Boehler $currentToken = $this->getSyncTokenForCalendar($calid); 1881d5703f5aSAndreas Boehler 1882d5703f5aSAndreas Boehler if ($currentToken === false) return null; 1883d5703f5aSAndreas Boehler 1884d5703f5aSAndreas Boehler $result = array( 1885d5703f5aSAndreas Boehler 'syncToken' => $currentToken, 1886d5703f5aSAndreas Boehler 'added' => array(), 1887d5703f5aSAndreas Boehler 'modified' => array(), 1888d5703f5aSAndreas Boehler 'deleted' => array(), 1889d5703f5aSAndreas Boehler ); 18905f2c3e2dSAndreas Boehler $sqlite = $this->getDB(); 18915f2c3e2dSAndreas Boehler if(!$sqlite) 18925f2c3e2dSAndreas Boehler return false; 1893d5703f5aSAndreas Boehler 1894d5703f5aSAndreas Boehler if ($syncToken) 1895d5703f5aSAndreas Boehler { 1896d5703f5aSAndreas Boehler 1897d5703f5aSAndreas Boehler $query = "SELECT uri, operation FROM calendarchanges WHERE synctoken >= ? AND synctoken < ? AND calendarid = ? ORDER BY synctoken"; 1898d5703f5aSAndreas Boehler if ($limit > 0) $query .= " LIMIT " . (int)$limit; 1899d5703f5aSAndreas Boehler 1900d5703f5aSAndreas Boehler // Fetching all changes 19015f2c3e2dSAndreas Boehler $res = $sqlite->query($query, $syncToken, $currentToken, $calid); 1902d5703f5aSAndreas Boehler if($res === false) 1903d5703f5aSAndreas Boehler return null; 1904d5703f5aSAndreas Boehler 19055f2c3e2dSAndreas Boehler $arr = $sqlite->res2arr($res); 1906d5703f5aSAndreas Boehler $changes = array(); 1907d5703f5aSAndreas Boehler 1908d5703f5aSAndreas Boehler // This loop ensures that any duplicates are overwritten, only the 1909d5703f5aSAndreas Boehler // last change on a node is relevant. 1910d5703f5aSAndreas Boehler foreach($arr as $row) 1911d5703f5aSAndreas Boehler { 1912d5703f5aSAndreas Boehler $changes[$row['uri']] = $row['operation']; 1913d5703f5aSAndreas Boehler } 1914d5703f5aSAndreas Boehler 1915d5703f5aSAndreas Boehler foreach ($changes as $uri => $operation) 1916d5703f5aSAndreas Boehler { 1917d5703f5aSAndreas Boehler switch ($operation) 1918d5703f5aSAndreas Boehler { 1919d5703f5aSAndreas Boehler case 1 : 1920d5703f5aSAndreas Boehler $result['added'][] = $uri; 1921d5703f5aSAndreas Boehler break; 1922d5703f5aSAndreas Boehler case 2 : 1923d5703f5aSAndreas Boehler $result['modified'][] = $uri; 1924d5703f5aSAndreas Boehler break; 1925d5703f5aSAndreas Boehler case 3 : 1926d5703f5aSAndreas Boehler $result['deleted'][] = $uri; 1927d5703f5aSAndreas Boehler break; 1928d5703f5aSAndreas Boehler } 1929d5703f5aSAndreas Boehler 1930d5703f5aSAndreas Boehler } 1931d5703f5aSAndreas Boehler } 1932d5703f5aSAndreas Boehler else 1933d5703f5aSAndreas Boehler { 1934d5703f5aSAndreas Boehler // No synctoken supplied, this is the initial sync. 1935d5703f5aSAndreas Boehler $query = "SELECT uri FROM calendarobjects WHERE calendarid = ?"; 19365f2c3e2dSAndreas Boehler $res = $sqlite->query($query); 19375f2c3e2dSAndreas Boehler $arr = $sqlite->res2arr($res); 1938d5703f5aSAndreas Boehler 1939d5703f5aSAndreas Boehler $result['added'] = $arr; 1940d5703f5aSAndreas Boehler } 1941d5703f5aSAndreas Boehler return $result; 1942d5703f5aSAndreas Boehler } 1943d5703f5aSAndreas Boehler 1944a1a3b679SAndreas Boehler} 1945