initial sabre upgrade (needs lots of work - to wit: authentication, redo the browser interface, and rework event export/import)
This commit is contained in:
parent
40b5b6e9d2
commit
0b02a6d123
@ -60,8 +60,16 @@ class Dav extends \Zotlabs\Web\Controller {
|
|||||||
if ($which)
|
if ($which)
|
||||||
profile_load($a, $which, $profile);
|
profile_load($a, $which, $profile);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$auth = new \Zotlabs\Storage\BasicAuth();
|
$auth = new \Zotlabs\Storage\BasicAuth();
|
||||||
|
|
||||||
|
$authBackend = new \Sabre\DAV\Auth\Backend\BasicCallBack(function($userName,$password) {
|
||||||
|
if(account_verify_password($userName,$password))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
$ob_hash = get_observer_hash();
|
$ob_hash = get_observer_hash();
|
||||||
|
|
||||||
if ($ob_hash) {
|
if ($ob_hash) {
|
||||||
@ -92,6 +100,12 @@ class Dav extends \Zotlabs\Web\Controller {
|
|||||||
|
|
||||||
// A SabreDAV server-object
|
// A SabreDAV server-object
|
||||||
$server = new SDAV\Server($rootDirectory);
|
$server = new SDAV\Server($rootDirectory);
|
||||||
|
|
||||||
|
|
||||||
|
$authPlugin = new \Sabre\DAV\Auth\Plugin($authBackend);
|
||||||
|
$server->addPlugin($authPlugin);
|
||||||
|
|
||||||
|
|
||||||
// prevent overwriting changes each other with a lock backend
|
// prevent overwriting changes each other with a lock backend
|
||||||
$lockBackend = new SDAV\Locks\Backend\File('store/[data]/locks');
|
$lockBackend = new SDAV\Locks\Backend\File('store/[data]/locks');
|
||||||
$lockPlugin = new SDAV\Locks\Plugin($lockBackend);
|
$lockPlugin = new SDAV\Locks\Plugin($lockBackend);
|
||||||
|
@ -101,8 +101,8 @@ class Browser extends DAV\Browser\Plugin {
|
|||||||
$parentpath = array();
|
$parentpath = array();
|
||||||
// only show parent if not leaving /cloud/; TODO how to improve this?
|
// only show parent if not leaving /cloud/; TODO how to improve this?
|
||||||
if ($path && $path != "cloud") {
|
if ($path && $path != "cloud") {
|
||||||
list($parentUri) = DAV\URLUtil::splitPath($path);
|
list($parentUri) = \Sabre\HTTP\URLUtil::splitPath($path);
|
||||||
$fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
|
$fullPath = \Sabre\HTTP\URLUtil::encodePath($this->server->getBaseUri() . $parentUri);
|
||||||
|
|
||||||
$parentpath['icon'] = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="' . t('parent') . '"></a>' : '';
|
$parentpath['icon'] = $this->enableAssets ? '<a href="' . $fullPath . '"><img src="' . $this->getAssetUrl('icons/parent' . $this->iconExtension) . '" width="24" alt="' . t('parent') . '"></a>' : '';
|
||||||
$parentpath['path'] = $fullPath;
|
$parentpath['path'] = $fullPath;
|
||||||
@ -116,7 +116,7 @@ class Browser extends DAV\Browser\Plugin {
|
|||||||
// This is the current directory, we can skip it
|
// This is the current directory, we can skip it
|
||||||
if (rtrim($file['href'],'/') == $path) continue;
|
if (rtrim($file['href'],'/') == $path) continue;
|
||||||
|
|
||||||
list(, $name) = DAV\URLUtil::splitPath($file['href']);
|
list(, $name) = \Sabre\HTTP\URLUtil::splitPath($file['href']);
|
||||||
|
|
||||||
if (isset($file[200]['{DAV:}resourcetype'])) {
|
if (isset($file[200]['{DAV:}resourcetype'])) {
|
||||||
$type = $file[200]['{DAV:}resourcetype']->getValue();
|
$type = $file[200]['{DAV:}resourcetype']->getValue();
|
||||||
@ -166,7 +166,7 @@ class Browser extends DAV\Browser\Plugin {
|
|||||||
$size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : '';
|
$size = isset($file[200]['{DAV:}getcontentlength']) ? (int)$file[200]['{DAV:}getcontentlength'] : '';
|
||||||
$lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : '');
|
$lastmodified = ((isset($file[200]['{DAV:}getlastmodified'])) ? $file[200]['{DAV:}getlastmodified']->getTime()->format('Y-m-d H:i:s') : '');
|
||||||
|
|
||||||
$fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/'));
|
$fullPath = \Sabre\HTTP\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path ? $path . '/' : '') . $name, '/'));
|
||||||
|
|
||||||
|
|
||||||
$displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name;
|
$displayName = isset($file[200]['{DAV:}displayname']) ? $file[200]['{DAV:}displayname'] : $name;
|
||||||
@ -219,7 +219,7 @@ class Browser extends DAV\Browser\Plugin {
|
|||||||
|
|
||||||
$output = '';
|
$output = '';
|
||||||
if ($this->enablePost) {
|
if ($this->enablePost) {
|
||||||
$this->server->broadcastEvent('onHTMLActionsPanel', array($parent, &$output));
|
$this->server->emit('onHTMLActionsPanel', array($parent, &$output));
|
||||||
}
|
}
|
||||||
|
|
||||||
$html .= replace_macros(get_markup_template('cloud.tpl'), array(
|
$html .= replace_macros(get_markup_template('cloud.tpl'), array(
|
||||||
|
@ -539,16 +539,16 @@ function event_import_ical($ical, $uid) {
|
|||||||
|
|
||||||
// logger('dtstart: ' . var_export($dtstart,true));
|
// logger('dtstart: ' . var_export($dtstart,true));
|
||||||
|
|
||||||
|
// @FIXME - convert/upgrade to vobject [3|4]
|
||||||
switch($dtstart->timezone_type) {
|
// switch($dtstart->timezone_type) {
|
||||||
case VObject\Property\DateTime::UTC :
|
// case VObject\Property\DateTime::UTC :
|
||||||
$ev['adjust'] = 0;
|
// $ev['adjust'] = 0;
|
||||||
break;
|
// break;
|
||||||
case VObject\Property\DateTime::LOCALTZ :
|
// case VObject\Property\DateTime::LOCALTZ :
|
||||||
default:
|
// default:
|
||||||
$ev['adjust'] = 1;
|
// $ev['adjust'] = 1;
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
|
|
||||||
$ev['start'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
|
$ev['start'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
|
||||||
$dtstart->format(\DateTime::W3C));
|
$dtstart->format(\DateTime::W3C));
|
||||||
|
2
vendor/autoload.php
vendored
2
vendor/autoload.php
vendored
@ -4,4 +4,4 @@
|
|||||||
|
|
||||||
require_once __DIR__ . '/composer' . '/autoload_real.php';
|
require_once __DIR__ . '/composer' . '/autoload_real.php';
|
||||||
|
|
||||||
return ComposerAutoloaderInita478c0bdc9041edcc4f485e8fb39b90d::getLoader();
|
return ComposerAutoloaderInit85a1cefa95be2f464cf7f947cbc4c785::getLoader();
|
||||||
|
1
vendor/bin/generate_vcards
vendored
Symbolic link
1
vendor/bin/generate_vcards
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../sabre/vobject/bin/generate_vcards
|
1
vendor/bin/naturalselection
vendored
Symbolic link
1
vendor/bin/naturalselection
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../sabre/dav/bin/naturalselection
|
1
vendor/bin/sabredav
vendored
Symbolic link
1
vendor/bin/sabredav
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../sabre/dav/bin/sabredav
|
1
vendor/bin/vobject
vendored
Symbolic link
1
vendor/bin/vobject
vendored
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../sabre/vobject/bin/vobject
|
44
vendor/composer/ClassLoader.php
vendored
44
vendor/composer/ClassLoader.php
vendored
@ -13,9 +13,7 @@
|
|||||||
namespace Composer\Autoload;
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ClassLoader implements a PSR-0 class loader
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
*
|
|
||||||
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
|
|
||||||
*
|
*
|
||||||
* $loader = new \Composer\Autoload\ClassLoader();
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
*
|
*
|
||||||
@ -39,6 +37,8 @@ namespace Composer\Autoload;
|
|||||||
*
|
*
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see http://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see http://www.php-fig.org/psr/psr-4/
|
||||||
*/
|
*/
|
||||||
class ClassLoader
|
class ClassLoader
|
||||||
{
|
{
|
||||||
@ -54,9 +54,15 @@ class ClassLoader
|
|||||||
private $useIncludePath = false;
|
private $useIncludePath = false;
|
||||||
private $classMap = array();
|
private $classMap = array();
|
||||||
|
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
|
||||||
public function getPrefixes()
|
public function getPrefixes()
|
||||||
{
|
{
|
||||||
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', $this->prefixesPsr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPrefixesPsr4()
|
public function getPrefixesPsr4()
|
||||||
@ -141,8 +147,10 @@ class ClassLoader
|
|||||||
* appending or prepending to the ones previously set for this namespace.
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
*
|
*
|
||||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
* @param array|string $paths The PSR-0 base directories
|
* @param array|string $paths The PSR-4 base directories
|
||||||
* @param bool $prepend Whether to prepend the directories
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public function addPsr4($prefix, $paths, $prepend = false)
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
{
|
{
|
||||||
@ -204,6 +212,8 @@ class ClassLoader
|
|||||||
*
|
*
|
||||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
* @param array|string $paths The PSR-4 base directories
|
* @param array|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public function setPsr4($prefix, $paths)
|
public function setPsr4($prefix, $paths)
|
||||||
{
|
{
|
||||||
@ -240,6 +250,27 @@ class ClassLoader
|
|||||||
return $this->useIncludePath;
|
return $this->useIncludePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers this instance as an autoloader.
|
* Registers this instance as an autoloader.
|
||||||
*
|
*
|
||||||
@ -291,6 +322,9 @@ class ClassLoader
|
|||||||
if (isset($this->classMap[$class])) {
|
if (isset($this->classMap[$class])) {
|
||||||
return $this->classMap[$class];
|
return $this->classMap[$class];
|
||||||
}
|
}
|
||||||
|
if ($this->classMapAuthoritative) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$file = $this->findFileWithExtension($class, '.php');
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
21
vendor/composer/LICENSE
vendored
Normal file
21
vendor/composer/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
16
vendor/composer/autoload_files.php
vendored
Normal file
16
vendor/composer/autoload_files.php
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_files.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(dirname(__FILE__));
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'383eaff206634a77a1be54e64e6459c7' => $vendorDir . '/sabre/uri/lib/functions.php',
|
||||||
|
'2b9d0f43f9552984cfa82fee95491826' => $vendorDir . '/sabre/event/lib/coroutine.php',
|
||||||
|
'd81bab31d3feb45bfe2f283ea3c8fdf7' => $vendorDir . '/sabre/event/lib/Loop/functions.php',
|
||||||
|
'a1cce3d26cc15c00fcd0b3354bd72c88' => $vendorDir . '/sabre/event/lib/Promise/functions.php',
|
||||||
|
'3569eecfeed3bcf0bad3c998a494ecb8' => $vendorDir . '/sabre/xml/lib/Deserializer/functions.php',
|
||||||
|
'93aa591bc4ca510c520999e34229ee79' => $vendorDir . '/sabre/xml/lib/Serializer/functions.php',
|
||||||
|
'ebdb698ed4152ae445614b69b5e4bb6a' => $vendorDir . '/sabre/http/lib/functions.php',
|
||||||
|
);
|
6
vendor/composer/autoload_namespaces.php
vendored
6
vendor/composer/autoload_namespaces.php
vendored
@ -6,10 +6,4 @@ $vendorDir = dirname(dirname(__FILE__));
|
|||||||
$baseDir = dirname($vendorDir);
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'Sabre\\VObject' => array($vendorDir . '/sabre/vobject/lib'),
|
|
||||||
'Sabre\\HTTP' => array($vendorDir . '/sabre/dav/lib'),
|
|
||||||
'Sabre\\DAVACL' => array($vendorDir . '/sabre/dav/lib'),
|
|
||||||
'Sabre\\DAV' => array($vendorDir . '/sabre/dav/lib'),
|
|
||||||
'Sabre\\CardDAV' => array($vendorDir . '/sabre/dav/lib'),
|
|
||||||
'Sabre\\CalDAV' => array($vendorDir . '/sabre/dav/lib'),
|
|
||||||
);
|
);
|
||||||
|
9
vendor/composer/autoload_psr4.php
vendored
9
vendor/composer/autoload_psr4.php
vendored
@ -6,4 +6,13 @@ $vendorDir = dirname(dirname(__FILE__));
|
|||||||
$baseDir = dirname($vendorDir);
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
'Sabre\\Xml\\' => array($vendorDir . '/sabre/xml/lib'),
|
||||||
|
'Sabre\\VObject\\' => array($vendorDir . '/sabre/vobject/lib'),
|
||||||
|
'Sabre\\Uri\\' => array($vendorDir . '/sabre/uri/lib'),
|
||||||
|
'Sabre\\HTTP\\' => array($vendorDir . '/sabre/http/lib'),
|
||||||
|
'Sabre\\Event\\' => array($vendorDir . '/sabre/event/lib'),
|
||||||
|
'Sabre\\DAV\\' => array($vendorDir . '/sabre/dav/lib/DAV'),
|
||||||
|
'Sabre\\DAVACL\\' => array($vendorDir . '/sabre/dav/lib/DAVACL'),
|
||||||
|
'Sabre\\CardDAV\\' => array($vendorDir . '/sabre/dav/lib/CardDAV'),
|
||||||
|
'Sabre\\CalDAV\\' => array($vendorDir . '/sabre/dav/lib/CalDAV'),
|
||||||
);
|
);
|
||||||
|
52
vendor/composer/autoload_real.php
vendored
52
vendor/composer/autoload_real.php
vendored
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
// autoload_real.php @generated by Composer
|
// autoload_real.php @generated by Composer
|
||||||
|
|
||||||
class ComposerAutoloaderInita478c0bdc9041edcc4f485e8fb39b90d
|
class ComposerAutoloaderInit85a1cefa95be2f464cf7f947cbc4c785
|
||||||
{
|
{
|
||||||
private static $loader;
|
private static $loader;
|
||||||
|
|
||||||
@ -19,32 +19,52 @@ class ComposerAutoloaderInita478c0bdc9041edcc4f485e8fb39b90d
|
|||||||
return self::$loader;
|
return self::$loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInita478c0bdc9041edcc4f485e8fb39b90d', 'loadClassLoader'), true, true);
|
spl_autoload_register(array('ComposerAutoloaderInit85a1cefa95be2f464cf7f947cbc4c785', 'loadClassLoader'), true, true);
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInita478c0bdc9041edcc4f485e8fb39b90d', 'loadClassLoader'));
|
spl_autoload_unregister(array('ComposerAutoloaderInit85a1cefa95be2f464cf7f947cbc4c785', 'loadClassLoader'));
|
||||||
|
|
||||||
$map = require __DIR__ . '/autoload_namespaces.php';
|
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION');
|
||||||
foreach ($map as $namespace => $path) {
|
if ($useStaticLoader) {
|
||||||
$loader->set($namespace, $path);
|
require_once __DIR__ . '/autoload_static.php';
|
||||||
}
|
|
||||||
|
|
||||||
$map = require __DIR__ . '/autoload_psr4.php';
|
call_user_func(\Composer\Autoload\ComposerStaticInit85a1cefa95be2f464cf7f947cbc4c785::getInitializer($loader));
|
||||||
foreach ($map as $namespace => $path) {
|
} else {
|
||||||
$loader->setPsr4($namespace, $path);
|
$map = require __DIR__ . '/autoload_namespaces.php';
|
||||||
}
|
foreach ($map as $namespace => $path) {
|
||||||
|
$loader->set($namespace, $path);
|
||||||
|
}
|
||||||
|
|
||||||
$classMap = require __DIR__ . '/autoload_classmap.php';
|
$map = require __DIR__ . '/autoload_psr4.php';
|
||||||
if ($classMap) {
|
foreach ($map as $namespace => $path) {
|
||||||
$loader->addClassMap($classMap);
|
$loader->setPsr4($namespace, $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$classMap = require __DIR__ . '/autoload_classmap.php';
|
||||||
|
if ($classMap) {
|
||||||
|
$loader->addClassMap($classMap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$loader->register(true);
|
$loader->register(true);
|
||||||
|
|
||||||
|
if ($useStaticLoader) {
|
||||||
|
$includeFiles = Composer\Autoload\ComposerStaticInit85a1cefa95be2f464cf7f947cbc4c785::$files;
|
||||||
|
} else {
|
||||||
|
$includeFiles = require __DIR__ . '/autoload_files.php';
|
||||||
|
}
|
||||||
|
foreach ($includeFiles as $fileIdentifier => $file) {
|
||||||
|
composerRequire85a1cefa95be2f464cf7f947cbc4c785($fileIdentifier, $file);
|
||||||
|
}
|
||||||
|
|
||||||
return $loader;
|
return $loader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function composerRequirea478c0bdc9041edcc4f485e8fb39b90d($file)
|
function composerRequire85a1cefa95be2f464cf7f947cbc4c785($fileIdentifier, $file)
|
||||||
{
|
{
|
||||||
require $file;
|
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||||
|
require $file;
|
||||||
|
|
||||||
|
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
81
vendor/composer/autoload_static.php
vendored
Normal file
81
vendor/composer/autoload_static.php
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_static.php @generated by Composer
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
class ComposerStaticInit85a1cefa95be2f464cf7f947cbc4c785
|
||||||
|
{
|
||||||
|
public static $files = array (
|
||||||
|
'383eaff206634a77a1be54e64e6459c7' => __DIR__ . '/..' . '/sabre/uri/lib/functions.php',
|
||||||
|
'2b9d0f43f9552984cfa82fee95491826' => __DIR__ . '/..' . '/sabre/event/lib/coroutine.php',
|
||||||
|
'd81bab31d3feb45bfe2f283ea3c8fdf7' => __DIR__ . '/..' . '/sabre/event/lib/Loop/functions.php',
|
||||||
|
'a1cce3d26cc15c00fcd0b3354bd72c88' => __DIR__ . '/..' . '/sabre/event/lib/Promise/functions.php',
|
||||||
|
'3569eecfeed3bcf0bad3c998a494ecb8' => __DIR__ . '/..' . '/sabre/xml/lib/Deserializer/functions.php',
|
||||||
|
'93aa591bc4ca510c520999e34229ee79' => __DIR__ . '/..' . '/sabre/xml/lib/Serializer/functions.php',
|
||||||
|
'ebdb698ed4152ae445614b69b5e4bb6a' => __DIR__ . '/..' . '/sabre/http/lib/functions.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixLengthsPsr4 = array (
|
||||||
|
'S' =>
|
||||||
|
array (
|
||||||
|
'Sabre\\Xml\\' => 10,
|
||||||
|
'Sabre\\VObject\\' => 14,
|
||||||
|
'Sabre\\Uri\\' => 10,
|
||||||
|
'Sabre\\HTTP\\' => 11,
|
||||||
|
'Sabre\\Event\\' => 12,
|
||||||
|
'Sabre\\DAV\\' => 10,
|
||||||
|
'Sabre\\DAVACL\\' => 13,
|
||||||
|
'Sabre\\CardDAV\\' => 14,
|
||||||
|
'Sabre\\CalDAV\\' => 13,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixDirsPsr4 = array (
|
||||||
|
'Sabre\\Xml\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/sabre/xml/lib',
|
||||||
|
),
|
||||||
|
'Sabre\\VObject\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/sabre/vobject/lib',
|
||||||
|
),
|
||||||
|
'Sabre\\Uri\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/sabre/uri/lib',
|
||||||
|
),
|
||||||
|
'Sabre\\HTTP\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/sabre/http/lib',
|
||||||
|
),
|
||||||
|
'Sabre\\Event\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/sabre/event/lib',
|
||||||
|
),
|
||||||
|
'Sabre\\DAV\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/sabre/dav/lib/DAV',
|
||||||
|
),
|
||||||
|
'Sabre\\DAVACL\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/sabre/dav/lib/DAVACL',
|
||||||
|
),
|
||||||
|
'Sabre\\CardDAV\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/sabre/dav/lib/CardDAV',
|
||||||
|
),
|
||||||
|
'Sabre\\CalDAV\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/sabre/dav/lib/CalDAV',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
{
|
||||||
|
return \Closure::bind(function () use ($loader) {
|
||||||
|
$loader->prefixLengthsPsr4 = ComposerStaticInit85a1cefa95be2f464cf7f947cbc4c785::$prefixLengthsPsr4;
|
||||||
|
$loader->prefixDirsPsr4 = ComposerStaticInit85a1cefa95be2f464cf7f947cbc4c785::$prefixDirsPsr4;
|
||||||
|
|
||||||
|
}, null, ClassLoader::class);
|
||||||
|
}
|
||||||
|
}
|
373
vendor/composer/installed.json
vendored
373
vendor/composer/installed.json
vendored
@ -1,32 +1,35 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "sabre/vobject",
|
"name": "sabre/uri",
|
||||||
"version": "2.1.4",
|
"version": "1.1.0",
|
||||||
"version_normalized": "2.1.4.0",
|
"version_normalized": "1.1.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/fruux/sabre-vobject.git",
|
"url": "https://github.com/fruux/sabre-uri.git",
|
||||||
"reference": "199b6ec87104b05e3013dfd5b90eafbbe4cf97dc"
|
"reference": "9012116434d84ef6e5e37a89dfdbfbe2204a8704"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/fruux/sabre-vobject/zipball/199b6ec87104b05e3013dfd5b90eafbbe4cf97dc",
|
"url": "https://api.github.com/repos/fruux/sabre-uri/zipball/9012116434d84ef6e5e37a89dfdbfbe2204a8704",
|
||||||
"reference": "199b6ec87104b05e3013dfd5b90eafbbe4cf97dc",
|
"reference": "9012116434d84ef6e5e37a89dfdbfbe2204a8704",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-mbstring": "*",
|
"php": ">=5.4.7"
|
||||||
"php": ">=5.3.1"
|
|
||||||
},
|
},
|
||||||
"time": "2014-03-30 23:01:06",
|
"require-dev": {
|
||||||
"bin": [
|
"phpunit/phpunit": "*",
|
||||||
"bin/vobjectvalidate.php"
|
"sabre/cs": "~0.0.1"
|
||||||
],
|
},
|
||||||
|
"time": "2016-03-08 02:29:27",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"installation-source": "dist",
|
"installation-source": "dist",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": {
|
"files": [
|
||||||
"Sabre\\VObject": "lib/"
|
"lib/functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Sabre\\Uri\\": "lib/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
@ -36,32 +39,310 @@
|
|||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Evert Pot",
|
"name": "Evert Pot",
|
||||||
"email": "evert@rooftopsolutions.nl",
|
"email": "me@evertpot.com",
|
||||||
"homepage": "http://evertpot.com/",
|
"homepage": "http://evertpot.com/",
|
||||||
"role": "Developer"
|
"role": "Developer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects",
|
"description": "Functions for making sense out of URIs.",
|
||||||
"homepage": "https://github.com/fruux/sabre-vobject",
|
"homepage": "http://sabre.io/uri/",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"VObject",
|
"rfc3986",
|
||||||
|
"uri",
|
||||||
|
"url"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sabre/event",
|
||||||
|
"version": "3.0.0",
|
||||||
|
"version_normalized": "3.0.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/fruux/sabre-event.git",
|
||||||
|
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/fruux/sabre-event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534",
|
||||||
|
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "*",
|
||||||
|
"sabre/cs": "~0.0.4"
|
||||||
|
},
|
||||||
|
"time": "2015-11-05 20:14:39",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Sabre\\Event\\": "lib/"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib/coroutine.php",
|
||||||
|
"lib/Loop/functions.php",
|
||||||
|
"lib/Promise/functions.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Evert Pot",
|
||||||
|
"email": "me@evertpot.com",
|
||||||
|
"homepage": "http://evertpot.com/",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "sabre/event is a library for lightweight event-based programming",
|
||||||
|
"homepage": "http://sabre.io/event/",
|
||||||
|
"keywords": [
|
||||||
|
"EventEmitter",
|
||||||
|
"async",
|
||||||
|
"events",
|
||||||
|
"hooks",
|
||||||
|
"plugin",
|
||||||
|
"promise",
|
||||||
|
"signal"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sabre/http",
|
||||||
|
"version": "4.2.1",
|
||||||
|
"version_normalized": "4.2.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/fruux/sabre-http.git",
|
||||||
|
"reference": "2e93bc8321524c67be4ca5b8415daebd4c8bf85e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/fruux/sabre-http/zipball/2e93bc8321524c67be4ca5b8415daebd4c8bf85e",
|
||||||
|
"reference": "2e93bc8321524c67be4ca5b8415daebd4c8bf85e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": ">=5.4",
|
||||||
|
"sabre/event": ">=1.0.0,<4.0.0",
|
||||||
|
"sabre/uri": "~1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "~4.3",
|
||||||
|
"sabre/cs": "~0.0.1"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-curl": " to make http requests with the Client class"
|
||||||
|
},
|
||||||
|
"time": "2016-01-06 23:00:08",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"lib/functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Sabre\\HTTP\\": "lib/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Evert Pot",
|
||||||
|
"email": "me@evertpot.com",
|
||||||
|
"homepage": "http://evertpot.com/",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The sabre/http library provides utilities for dealing with http requests and responses. ",
|
||||||
|
"homepage": "https://github.com/fruux/sabre-http",
|
||||||
|
"keywords": [
|
||||||
|
"http"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sabre/xml",
|
||||||
|
"version": "1.4.1",
|
||||||
|
"version_normalized": "1.4.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/fruux/sabre-xml.git",
|
||||||
|
"reference": "59998046db252634259a878baf1af18159f508f3"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/fruux/sabre-xml/zipball/59998046db252634259a878baf1af18159f508f3",
|
||||||
|
"reference": "59998046db252634259a878baf1af18159f508f3",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-xmlreader": "*",
|
||||||
|
"ext-xmlwriter": "*",
|
||||||
|
"lib-libxml": ">=2.6.20",
|
||||||
|
"php": ">=5.4.1",
|
||||||
|
"sabre/uri": "~1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "*",
|
||||||
|
"sabre/cs": "~0.0.2"
|
||||||
|
},
|
||||||
|
"time": "2016-03-12 22:23:16",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Sabre\\Xml\\": "lib/"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"lib/Deserializer/functions.php",
|
||||||
|
"lib/Serializer/functions.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Evert Pot",
|
||||||
|
"email": "me@evertpot.com",
|
||||||
|
"homepage": "http://evertpot.com/",
|
||||||
|
"role": "Developer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Markus Staab",
|
||||||
|
"email": "markus.staab@redaxo.de",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "sabre/xml is an XML library that you may not hate.",
|
||||||
|
"homepage": "https://sabre.io/xml/",
|
||||||
|
"keywords": [
|
||||||
|
"XMLReader",
|
||||||
|
"XMLWriter",
|
||||||
|
"dom",
|
||||||
|
"xml"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sabre/vobject",
|
||||||
|
"version": "4.1.0",
|
||||||
|
"version_normalized": "4.1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/fruux/sabre-vobject.git",
|
||||||
|
"reference": "8899c0e856b3178b17f4e9a4e85010209f32a2fa"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/fruux/sabre-vobject/zipball/8899c0e856b3178b17f4e9a4e85010209f32a2fa",
|
||||||
|
"reference": "8899c0e856b3178b17f4e9a4e85010209f32a2fa",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": ">=5.5",
|
||||||
|
"sabre/xml": "~1.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "*",
|
||||||
|
"sabre/cs": "~0.0.3"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"hoa/bench": "If you would like to run the benchmark scripts"
|
||||||
|
},
|
||||||
|
"time": "2016-04-07 00:48:27",
|
||||||
|
"bin": [
|
||||||
|
"bin/vobject",
|
||||||
|
"bin/generate_vcards"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "4.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Sabre\\VObject\\": "lib/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Evert Pot",
|
||||||
|
"email": "me@evertpot.com",
|
||||||
|
"homepage": "http://evertpot.com/",
|
||||||
|
"role": "Developer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dominik Tobschall",
|
||||||
|
"email": "dominik@fruux.com",
|
||||||
|
"homepage": "http://tobschall.de/",
|
||||||
|
"role": "Developer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ivan Enderlin",
|
||||||
|
"email": "ivan.enderlin@hoa-project.net",
|
||||||
|
"homepage": "http://mnt.io/",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects",
|
||||||
|
"homepage": "http://sabre.io/vobject/",
|
||||||
|
"keywords": [
|
||||||
|
"availability",
|
||||||
|
"freebusy",
|
||||||
"iCalendar",
|
"iCalendar",
|
||||||
"vCard"
|
"ics",
|
||||||
|
"jCal",
|
||||||
|
"jCard",
|
||||||
|
"recurrence",
|
||||||
|
"rfc2425",
|
||||||
|
"rfc2426",
|
||||||
|
"rfc2739",
|
||||||
|
"rfc4770",
|
||||||
|
"rfc5545",
|
||||||
|
"rfc5546",
|
||||||
|
"rfc6321",
|
||||||
|
"rfc6350",
|
||||||
|
"rfc6351",
|
||||||
|
"rfc6474",
|
||||||
|
"rfc6638",
|
||||||
|
"rfc6715",
|
||||||
|
"rfc6868",
|
||||||
|
"vCard",
|
||||||
|
"vcf",
|
||||||
|
"xCal",
|
||||||
|
"xCard"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sabre/dav",
|
"name": "sabre/dav",
|
||||||
"version": "1.8.10",
|
"version": "3.1.3",
|
||||||
"version_normalized": "1.8.10.0",
|
"version_normalized": "3.1.3.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/fruux/sabre-dav.git",
|
"url": "https://github.com/fruux/sabre-dav.git",
|
||||||
"reference": "0d064536ed3c7974e486b6ebb5b17ad7a974fe18"
|
"reference": "8a266c7b5e140da79529414b9cde2a2d058b536b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/fruux/sabre-dav/zipball/0d064536ed3c7974e486b6ebb5b17ad7a974fe18",
|
"url": "https://api.github.com/repos/fruux/sabre-dav/zipball/8a266c7b5e140da79529414b9cde2a2d058b536b",
|
||||||
"reference": "0d064536ed3c7974e486b6ebb5b17ad7a974fe18",
|
"reference": "8a266c7b5e140da79529414b9cde2a2d058b536b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -69,39 +350,45 @@
|
|||||||
"ext-date": "*",
|
"ext-date": "*",
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
"ext-libxml": "*",
|
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"ext-pcre": "*",
|
"ext-pcre": "*",
|
||||||
"ext-simplexml": "*",
|
"ext-simplexml": "*",
|
||||||
"ext-spl": "*",
|
"ext-spl": "*",
|
||||||
"php": ">=5.3.1",
|
"lib-libxml": ">=2.7.0",
|
||||||
"sabre/vobject": "~2.1.0"
|
"php": ">=5.5.0",
|
||||||
},
|
"sabre/event": ">=2.0.0, <4.0.0",
|
||||||
"provide": {
|
"sabre/http": "^4.2.1",
|
||||||
"evert/sabredav": "1.7.*"
|
"sabre/uri": "~1.0",
|
||||||
|
"sabre/vobject": "~4.0",
|
||||||
|
"sabre/xml": "~1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"evert/phpdoc-md": "~0.0.7",
|
"evert/phpdoc-md": "~0.1.0",
|
||||||
"phpunit/phpunit": "~4.0.0"
|
"phpunit/phpunit": "> 4.8, <=6.0.0",
|
||||||
|
"sabre/cs": "~0.0.5"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-apc": "*",
|
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"ext-pdo": "*"
|
"ext-pdo": "*"
|
||||||
},
|
},
|
||||||
"time": "2014-05-16 00:14:02",
|
"time": "2016-04-07 01:02:57",
|
||||||
"bin": [
|
"bin": [
|
||||||
"bin/sabredav"
|
"bin/sabredav",
|
||||||
|
"bin/naturalselection"
|
||||||
],
|
],
|
||||||
"type": "library",
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.1.0-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
"installation-source": "dist",
|
"installation-source": "dist",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": {
|
"psr-4": {
|
||||||
"Sabre\\DAV": "lib/",
|
"Sabre\\DAV\\": "lib/DAV/",
|
||||||
"Sabre\\HTTP": "lib/",
|
"Sabre\\DAVACL\\": "lib/DAVACL/",
|
||||||
"Sabre\\DAVACL": "lib/",
|
"Sabre\\CalDAV\\": "lib/CalDAV/",
|
||||||
"Sabre\\CalDAV": "lib/",
|
"Sabre\\CardDAV\\": "lib/CardDAV/"
|
||||||
"Sabre\\CardDAV": "lib/"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
@ -117,7 +404,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "WebDAV Framework for PHP",
|
"description": "WebDAV Framework for PHP",
|
||||||
"homepage": "http://code.google.com/p/sabredav/",
|
"homepage": "http://sabre.io/",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"CalDAV",
|
"CalDAV",
|
||||||
"CardDAV",
|
"CardDAV",
|
||||||
|
47
vendor/sabre/dav/.gitignore
vendored
47
vendor/sabre/dav/.gitignore
vendored
@ -1,22 +1,43 @@
|
|||||||
docs/api
|
# Unit tests
|
||||||
docs/wikidocs
|
|
||||||
build.properties
|
|
||||||
build
|
|
||||||
public
|
|
||||||
data
|
|
||||||
fileserver.php
|
|
||||||
fileserver2.php
|
|
||||||
calendarserver.php
|
|
||||||
groupwareserver.php
|
|
||||||
package.xml
|
|
||||||
tmpdata
|
|
||||||
tests/temp
|
tests/temp
|
||||||
tests/.sabredav
|
tests/.sabredav
|
||||||
|
tests/cov
|
||||||
|
|
||||||
|
# Custom settings for tests
|
||||||
|
tests/config.user.php
|
||||||
|
|
||||||
|
# ViM
|
||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
|
# Composer
|
||||||
composer.lock
|
composer.lock
|
||||||
vendor
|
vendor
|
||||||
|
|
||||||
|
# Composer binaries
|
||||||
bin/phing
|
bin/phing
|
||||||
bin/phpunit
|
bin/phpunit
|
||||||
bin/vobjectvalidate.php
|
bin/vobject
|
||||||
|
bin/generate_vcards
|
||||||
bin/phpdocmd
|
bin/phpdocmd
|
||||||
bin/phpunit
|
bin/phpunit
|
||||||
|
bin/php-cs-fixer
|
||||||
|
bin/sabre-cs-fixer
|
||||||
|
|
||||||
|
# Assuming every .php file in the root is for testing
|
||||||
|
/*.php
|
||||||
|
|
||||||
|
# Other testing stuff
|
||||||
|
/tmpdata
|
||||||
|
/data
|
||||||
|
/public
|
||||||
|
|
||||||
|
# Build
|
||||||
|
build
|
||||||
|
build.properties
|
||||||
|
|
||||||
|
# Docs
|
||||||
|
docs/api
|
||||||
|
docs/wikidocs
|
||||||
|
|
||||||
|
# Mac
|
||||||
|
.DS_Store
|
||||||
|
29
vendor/sabre/dav/.travis.yml
vendored
29
vendor/sabre/dav/.travis.yml
vendored
@ -1,28 +1,33 @@
|
|||||||
language: php
|
language: php
|
||||||
php:
|
php:
|
||||||
- 5.3.3
|
|
||||||
- 5.3
|
|
||||||
- 5.4
|
|
||||||
- 5.5
|
- 5.5
|
||||||
- 5.6
|
- 5.6
|
||||||
|
- 7
|
||||||
- hhvm
|
- hhvm
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- php: 5.6
|
- php: hhvm
|
||||||
- php: hhvm
|
|
||||||
|
env:
|
||||||
|
matrix:
|
||||||
|
- LOWEST_DEPS="" TEST_DEPS=""
|
||||||
|
- LOWEST_DEPS="--prefer-lowest" TEST_DEPS="tests/Sabre/"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- mysql
|
- mysql
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
cache: vendor
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- mysql -e 'create database sabredav'
|
- mysql -e 'create database sabredav'
|
||||||
- composer self-update
|
# - composer self-update
|
||||||
- composer install --prefer-source
|
- composer update --prefer-source $LOWEST_DEPS
|
||||||
# - echo "zend.enable_gc=0" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- phpunit --configuration tests/phpunit.xml
|
- ./bin/phpunit --configuration tests/phpunit.xml $TEST_DEPS
|
||||||
- cp tests/composer.vobject3.json composer.json
|
- ./bin/sabre-cs-fixer fix lib/ --dry-run --diff
|
||||||
- composer update --no-dev
|
|
||||||
- phpunit --configuration tests/phpunit.xml
|
|
||||||
|
2242
vendor/sabre/dav/CHANGELOG.md
vendored
Normal file
2242
vendor/sabre/dav/CHANGELOG.md
vendored
Normal file
File diff suppressed because it is too large
Load Diff
87
vendor/sabre/dav/CONTRIBUTING.md
vendored
Normal file
87
vendor/sabre/dav/CONTRIBUTING.md
vendored
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
Contributing to sabre projects
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Want to contribute to sabre/dav? Here are some guidelines to ensure your patch
|
||||||
|
gets accepted.
|
||||||
|
|
||||||
|
|
||||||
|
Building a new feature? Contact us first
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
We may not want to accept every feature that comes our way. Sometimes
|
||||||
|
features are out of scope for our projects.
|
||||||
|
|
||||||
|
We don't want to waste your time, so by having a quick chat with us first,
|
||||||
|
you may find out quickly if the feature makes sense to us, and we can give
|
||||||
|
some tips on how to best build the feature.
|
||||||
|
|
||||||
|
If we don't accept the feature, it could be for a number of reasons. For
|
||||||
|
instance, we've rejected features in the past because we felt uncomfortable
|
||||||
|
assuming responsibility for maintaining the feature.
|
||||||
|
|
||||||
|
In those cases, it's often possible to keep the feature separate from the
|
||||||
|
sabre projects. sabre/dav for instance has a plugin system, and there's no
|
||||||
|
reason the feature can't live in a project you own.
|
||||||
|
|
||||||
|
In that case, definitely let us know about your plugin as well, so we can
|
||||||
|
feature it on [sabre.io][4].
|
||||||
|
|
||||||
|
We are often on [IRC][5], in the #sabredav channel on freenode. If there's
|
||||||
|
no one there, post a message on the [mailing list][6].
|
||||||
|
|
||||||
|
|
||||||
|
Coding standards
|
||||||
|
----------------
|
||||||
|
|
||||||
|
sabre projects follow:
|
||||||
|
|
||||||
|
1. [PSR-1][1]
|
||||||
|
2. [PSR-4][2]
|
||||||
|
|
||||||
|
sabre projects don't follow [PSR-2][3].
|
||||||
|
|
||||||
|
In addition to that, here's a list of basic rules:
|
||||||
|
|
||||||
|
1. PHP 5.4 array syntax must be used every where. This means you use `[` and
|
||||||
|
`]` instead of `array(` and `)`.
|
||||||
|
2. Use PHP namespaces everywhere.
|
||||||
|
3. Use 4 spaces for indentation.
|
||||||
|
4. Try to keep your lines under 80 characters. This is not a hard rule, as
|
||||||
|
there are many places in the source where it felt more sensibile to not
|
||||||
|
do so. In particular, function declarations are never split over multiple
|
||||||
|
lines.
|
||||||
|
5. Opening braces (`{`) are _always_ on the same line as the `class`, `if`,
|
||||||
|
`function`, etc. they belong to.
|
||||||
|
6. `public` must be omitted from method declarations. It must also be omitted
|
||||||
|
for static properties.
|
||||||
|
7. All files should use unix-line endings (`\n`).
|
||||||
|
8. Files must omit the closing php tag (`?>`).
|
||||||
|
9. `true`, `false` and `null` are always lower-case.
|
||||||
|
10. Constants are always upper-case.
|
||||||
|
11. Any of the rules stated before may be broken where this is the pragmatic
|
||||||
|
thing to do.
|
||||||
|
|
||||||
|
|
||||||
|
Unit test requirements
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Any new feature or change requires unittests. We use [PHPUnit][7] for all our
|
||||||
|
tests.
|
||||||
|
|
||||||
|
Adding unittests will greatly increase the likelyhood of us quickly accepting
|
||||||
|
your pull request. If unittests are not included though for whatever reason,
|
||||||
|
we'd still _love_ your pull request.
|
||||||
|
|
||||||
|
We may have to write the tests ourselves, which can increase the time it takes
|
||||||
|
to accept the patch, but we'd still really like your contribution!
|
||||||
|
|
||||||
|
To run the testsuite jump into the directory `cd tests` and trigger `phpunit`.
|
||||||
|
Make sure you did a `composer install` beforehand.
|
||||||
|
|
||||||
|
[1]: http://www.php-fig.org/psr/psr-1/
|
||||||
|
[2]: http://www.php-fig.org/psr/psr-4/
|
||||||
|
[3]: http://www.php-fig.org/psr/psr-2/
|
||||||
|
[4]: http://sabre.io/
|
||||||
|
[5]: irc://freenode.net/#sabredav
|
||||||
|
[6]: http://groups.google.com/group/sabredav-discuss
|
||||||
|
[7]: http://phpunit.de/
|
1164
vendor/sabre/dav/ChangeLog
vendored
1164
vendor/sabre/dav/ChangeLog
vendored
File diff suppressed because it is too large
Load Diff
2
vendor/sabre/dav/LICENSE
vendored
2
vendor/sabre/dav/LICENSE
vendored
@ -1,4 +1,4 @@
|
|||||||
Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
Copyright (C) 2007-2016 fruux GmbH (https://fruux.com/).
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
49
vendor/sabre/dav/README.md
vendored
49
vendor/sabre/dav/README.md
vendored
@ -1,30 +1,29 @@
|
|||||||
# What is SabreDAV
|
 SabreDAV
|
||||||
|
======================================================
|
||||||
|
|
||||||
SabreDAV allows you to easily add WebDAV support to a PHP application. SabreDAV is meant to cover the entire standard, and attempts to allow integration using an easy to understand API.
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
### Feature list:
|
SabreDAV is the most popular WebDAV framework for PHP. Use it to create WebDAV, CalDAV and CardDAV servers.
|
||||||
|
|
||||||
* Fully WebDAV compliant
|
Full documentation can be found on the website:
|
||||||
* Supports Windows XP, Windows Vista, Mac OS/X, DavFSv2, Cadaver, Netdrive, Open Office, and probably more.
|
|
||||||
* Passing all Litmus tests.
|
|
||||||
* Supporting class 1, 2 and 3 Webdav servers.
|
|
||||||
* Locking support.
|
|
||||||
* Custom property support.
|
|
||||||
* CalDAV (tested with [Evolution](http://code.google.com/p/sabredav/wiki/Evolution), [iCal](http://code.google.com/p/sabredav/wiki/ICal), [iPhone](http://code.google.com/p/sabredav/wiki/IPhone) and [Lightning](http://code.google.com/p/sabredav/wiki/Lightning)).
|
|
||||||
* CardDAV (tested with [OS/X addressbook](http://code.google.com/p/sabredav/wiki/OSXAddressbook), the [iOS addressbook](http://code.google.com/p/sabredav/wiki/iOSCardDAV) and [Evolution](http://code.google.com/p/sabredav/wiki/Evolution)).
|
|
||||||
* Over 97% unittest code coverage.
|
|
||||||
|
|
||||||
### Supported RFC's:
|
http://sabre.io/
|
||||||
|
|
||||||
* [RFC2617](http://www.ietf.org/rfc/rfc2617.txt): Basic/Digest auth.
|
Build status
|
||||||
* [RFC2518](http://www.ietf.org/rfc/rfc2518.txt): First WebDAV spec.
|
------------
|
||||||
* [RFC3744](http://www.ietf.org/rfc/rfc3744.txt): ACL (some features missing).
|
|
||||||
* [RFC4709](http://www.ietf.org/rfc/rfc4709.txt): [DavMount](http://code.google.com/p/sabredav/wiki/DavMount).
|
| branch | status | minimum PHP version |
|
||||||
* [RFC4791](http://www.ietf.org/rfc/rfc4791.txt): CalDAV.
|
| ------------ | ------ | ------------------- |
|
||||||
* [RFC4918](http://www.ietf.org/rfc/rfc4918.txt): WebDAV revision.
|
| master | [](https://travis-ci.org/fruux/sabre-dav) | PHP 5.5 |
|
||||||
* [RFC5397](http://www.ietf.org/rfc/rfc5689.txt): current-user-principal.
|
| 3.0 | [](https://travis-ci.org/fruux/sabre-dav) | PHP 5.4 |
|
||||||
* [RFC5689](http://www.ietf.org/rfc/rfc5689.txt): Extended MKCOL.
|
| 2.1 | [](https://travis-ci.org/fruux/sabre-dav) | PHP 5.4 |
|
||||||
* [RFC5789](http://tools.ietf.org/html/rfc5789): PATCH method for HTTP.
|
| 2.0 | [](https://travis-ci.org/fruux/sabre-dav) | PHP 5.4 |
|
||||||
* [RFC6352](http://www.ietf.org/rfc/rfc6352.txt): CardDAV
|
| 1.8 | [](https://travis-ci.org/fruux/sabre-dav) | PHP 5.3 |
|
||||||
* [draft-daboo-carddav-directory-gateway](http://tools.ietf.org/html/draft-daboo-carddav-directory-gateway): CardDAV directory gateway
|
| 1.7 | [](https://travis-ci.org/fruux/sabre-dav) | PHP 5.3 |
|
||||||
* CalDAV ctag, CalDAV-proxy.
|
| 1.6 | [](https://travis-ci.org/fruux/sabre-dav) | PHP 5.3 |
|
||||||
|
|
||||||
|
Made at fruux
|
||||||
|
-------------
|
||||||
|
|
||||||
|
SabreDAV is being developed by [fruux](https://fruux.com/). Drop us a line for commercial services or enterprise support.
|
||||||
|
60
vendor/sabre/dav/bin/build.php
vendored
Normal file → Executable file
60
vendor/sabre/dav/bin/build.php
vendored
Normal file → Executable file
@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$tasks = [
|
$tasks = [
|
||||||
@ -9,10 +10,10 @@ $tasks = [
|
|||||||
'init', 'test', 'clean',
|
'init', 'test', 'clean',
|
||||||
],
|
],
|
||||||
'clean' => [],
|
'clean' => [],
|
||||||
'test' => [
|
'test' => [
|
||||||
'composerupdate',
|
'composerupdate',
|
||||||
],
|
],
|
||||||
'init' => [],
|
'init' => [],
|
||||||
'composerupdate' => [],
|
'composerupdate' => [],
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -35,9 +36,9 @@ if (!isset($tasks[$currentTask])) {
|
|||||||
$newTaskList = [];
|
$newTaskList = [];
|
||||||
$oldTaskList = [$currentTask => true];
|
$oldTaskList = [$currentTask => true];
|
||||||
|
|
||||||
while(count($oldTaskList)>0) {
|
while (count($oldTaskList) > 0) {
|
||||||
|
|
||||||
foreach($oldTaskList as $task=>$foo) {
|
foreach ($oldTaskList as $task => $foo) {
|
||||||
|
|
||||||
if (!isset($tasks[$task])) {
|
if (!isset($tasks[$task])) {
|
||||||
echo "Dependency not found: " . $task, "\n";
|
echo "Dependency not found: " . $task, "\n";
|
||||||
@ -46,7 +47,7 @@ while(count($oldTaskList)>0) {
|
|||||||
$dependencies = $tasks[$task];
|
$dependencies = $tasks[$task];
|
||||||
|
|
||||||
$fullFilled = true;
|
$fullFilled = true;
|
||||||
foreach($dependencies as $dependency) {
|
foreach ($dependencies as $dependency) {
|
||||||
if (isset($newTaskList[$dependency])) {
|
if (isset($newTaskList[$dependency])) {
|
||||||
// Already in the fulfilled task list.
|
// Already in the fulfilled task list.
|
||||||
continue;
|
continue;
|
||||||
@ -65,7 +66,7 @@ while(count($oldTaskList)>0) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(array_keys($newTaskList) as $task) {
|
foreach (array_keys($newTaskList) as $task) {
|
||||||
|
|
||||||
echo "task: " . $task, "\n";
|
echo "task: " . $task, "\n";
|
||||||
call_user_func($task);
|
call_user_func($task);
|
||||||
@ -100,7 +101,7 @@ function composerupdate() {
|
|||||||
|
|
||||||
global $baseDir;
|
global $baseDir;
|
||||||
echo " Updating composer packages to latest version\n\n";
|
echo " Updating composer packages to latest version\n\n";
|
||||||
system('cd ' . $baseDir . '; composer update --dev');
|
system('cd ' . $baseDir . '; composer update');
|
||||||
}
|
}
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
@ -120,12 +121,51 @@ function test() {
|
|||||||
function buildzip() {
|
function buildzip() {
|
||||||
|
|
||||||
global $baseDir, $version;
|
global $baseDir, $version;
|
||||||
echo " Asking composer to download sabre/dav $version\n\n";
|
echo " Generating composer.json\n";
|
||||||
system("composer create-project --no-dev sabre/dav build/SabreDAV $version", $code);
|
|
||||||
if ($code!==0) {
|
$input = json_decode(file_get_contents(__DIR__ . '/../composer.json'), true);
|
||||||
|
$newComposer = [
|
||||||
|
"require" => $input['require'],
|
||||||
|
"config" => [
|
||||||
|
"bin-dir" => "./bin",
|
||||||
|
],
|
||||||
|
"prefer-stable" => true,
|
||||||
|
"minimum-stability" => "alpha",
|
||||||
|
];
|
||||||
|
unset(
|
||||||
|
$newComposer['require']['sabre/vobject'],
|
||||||
|
$newComposer['require']['sabre/http'],
|
||||||
|
$newComposer['require']['sabre/uri'],
|
||||||
|
$newComposer['require']['sabre/event']
|
||||||
|
);
|
||||||
|
$newComposer['require']['sabre/dav'] = $version;
|
||||||
|
mkdir('build/SabreDAV');
|
||||||
|
file_put_contents('build/SabreDAV/composer.json', json_encode($newComposer, JSON_PRETTY_PRINT));
|
||||||
|
|
||||||
|
echo " Downloading dependencies\n";
|
||||||
|
system("cd build/SabreDAV; composer install -n", $code);
|
||||||
|
if ($code !== 0) {
|
||||||
echo "Composer reported error code $code\n";
|
echo "Composer reported error code $code\n";
|
||||||
die(1);
|
die(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
echo " Removing pointless files\n";
|
||||||
|
unlink('build/SabreDAV/composer.json');
|
||||||
|
unlink('build/SabreDAV/composer.lock');
|
||||||
|
|
||||||
|
echo " Moving important files to the root of the project\n";
|
||||||
|
|
||||||
|
$fileNames = [
|
||||||
|
'CHANGELOG.md',
|
||||||
|
'LICENSE',
|
||||||
|
'README.md',
|
||||||
|
'examples',
|
||||||
|
];
|
||||||
|
foreach ($fileNames as $fileName) {
|
||||||
|
echo " $fileName\n";
|
||||||
|
rename('build/SabreDAV/vendor/sabre/dav/' . $fileName, 'build/SabreDAV/' . $fileName);
|
||||||
|
}
|
||||||
|
|
||||||
// <zip destfile="build/SabreDAV-${sabredav.version}.zip" basedir="build/SabreDAV" prefix="SabreDAV/" />
|
// <zip destfile="build/SabreDAV-${sabredav.version}.zip" basedir="build/SabreDAV" prefix="SabreDAV/" />
|
||||||
|
|
||||||
echo "\n";
|
echo "\n";
|
||||||
|
54
vendor/sabre/dav/bin/migrateto17.php
vendored
54
vendor/sabre/dav/bin/migrateto17.php
vendored
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
echo "SabreDAV migrate script for version 1.7\n";
|
echo "SabreDAV migrate script for version 1.7\n";
|
||||||
|
|
||||||
if ($argc<2) {
|
if ($argc < 2) {
|
||||||
|
|
||||||
echo <<<HELLO
|
echo <<<HELLO
|
||||||
|
|
||||||
@ -35,12 +35,12 @@ HELLO;
|
|||||||
|
|
||||||
// There's a bunch of places where the autoloader could be, so we'll try all of
|
// There's a bunch of places where the autoloader could be, so we'll try all of
|
||||||
// them.
|
// them.
|
||||||
$paths = array(
|
$paths = [
|
||||||
__DIR__ . '/../vendor/autoload.php',
|
__DIR__ . '/../vendor/autoload.php',
|
||||||
__DIR__ . '/../../../autoload.php',
|
__DIR__ . '/../../../autoload.php',
|
||||||
);
|
];
|
||||||
|
|
||||||
foreach($paths as $path) {
|
foreach ($paths as $path) {
|
||||||
if (file_exists($path)) {
|
if (file_exists($path)) {
|
||||||
include $path;
|
include $path;
|
||||||
break;
|
break;
|
||||||
@ -48,8 +48,8 @@ foreach($paths as $path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$dsn = $argv[1];
|
$dsn = $argv[1];
|
||||||
$user = isset($argv[2])?$argv[2]:null;
|
$user = isset($argv[2]) ? $argv[2] : null;
|
||||||
$pass = isset($argv[3])?$argv[3]:null;
|
$pass = isset($argv[3]) ? $argv[3] : null;
|
||||||
|
|
||||||
echo "Connecting to database: " . $dsn . "\n";
|
echo "Connecting to database: " . $dsn . "\n";
|
||||||
|
|
||||||
@ -67,32 +67,32 @@ if (!$row) {
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$requiredFields = array(
|
$requiredFields = [
|
||||||
'id',
|
'id',
|
||||||
'calendardata',
|
'calendardata',
|
||||||
'uri',
|
'uri',
|
||||||
'calendarid',
|
'calendarid',
|
||||||
'lastmodified',
|
'lastmodified',
|
||||||
);
|
];
|
||||||
|
|
||||||
foreach($requiredFields as $requiredField) {
|
foreach ($requiredFields as $requiredField) {
|
||||||
if (!array_key_exists($requiredField,$row)) {
|
if (!array_key_exists($requiredField, $row)) {
|
||||||
echo "Error: The current 'calendarobjects' table was missing a field we expected to exist.\n";
|
echo "Error: The current 'calendarobjects' table was missing a field we expected to exist.\n";
|
||||||
echo "For safety reasons, this process is stopped.\n";
|
echo "For safety reasons, this process is stopped.\n";
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$fields17 = array(
|
$fields17 = [
|
||||||
'etag',
|
'etag',
|
||||||
'size',
|
'size',
|
||||||
'componenttype',
|
'componenttype',
|
||||||
'firstoccurence',
|
'firstoccurence',
|
||||||
'lastoccurence',
|
'lastoccurence',
|
||||||
);
|
];
|
||||||
|
|
||||||
$found = 0;
|
$found = 0;
|
||||||
foreach($fields17 as $field) {
|
foreach ($fields17 as $field) {
|
||||||
if (array_key_exists($field, $row)) {
|
if (array_key_exists($field, $row)) {
|
||||||
$found++;
|
$found++;
|
||||||
}
|
}
|
||||||
@ -102,7 +102,7 @@ if ($found === 0) {
|
|||||||
echo "The database had the 1.6 schema. Table will now be altered.\n";
|
echo "The database had the 1.6 schema. Table will now be altered.\n";
|
||||||
echo "This may take some time for large tables\n";
|
echo "This may take some time for large tables\n";
|
||||||
|
|
||||||
switch($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) {
|
switch ($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) {
|
||||||
|
|
||||||
case 'mysql' :
|
case 'mysql' :
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ $stmt = $pdo->prepare('UPDATE calendarobjects SET etag = ?, size = ?, componentt
|
|||||||
echo "Total records found: " . $result->rowCount() . "\n";
|
echo "Total records found: " . $result->rowCount() . "\n";
|
||||||
$done = 0;
|
$done = 0;
|
||||||
$total = $result->rowCount();
|
$total = $result->rowCount();
|
||||||
while($row = $result->fetch()) {
|
while ($row = $result->fetch()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$newData = getDenormalizedData($row['calendardata']);
|
$newData = getDenormalizedData($row['calendardata']);
|
||||||
@ -161,14 +161,14 @@ while($row = $result->fetch()) {
|
|||||||
echo "This record is ignored, you should inspect it to see if there's anything wrong.\n===\n";
|
echo "This record is ignored, you should inspect it to see if there's anything wrong.\n===\n";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$stmt->execute(array(
|
$stmt->execute([
|
||||||
$newData['etag'],
|
$newData['etag'],
|
||||||
$newData['size'],
|
$newData['size'],
|
||||||
$newData['componentType'],
|
$newData['componentType'],
|
||||||
$newData['firstOccurence'],
|
$newData['firstOccurence'],
|
||||||
$newData['lastOccurence'],
|
$newData['lastOccurence'],
|
||||||
$row['id'],
|
$row['id'],
|
||||||
));
|
]);
|
||||||
$done++;
|
$done++;
|
||||||
|
|
||||||
if ($done % 500 === 0) {
|
if ($done % 500 === 0) {
|
||||||
@ -188,7 +188,7 @@ if (array_key_exists('transparent', $row)) {
|
|||||||
|
|
||||||
echo "Adding the 'transparent' field to the calendars table\n";
|
echo "Adding the 'transparent' field to the calendars table\n";
|
||||||
|
|
||||||
switch($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) {
|
switch ($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) {
|
||||||
|
|
||||||
case 'mysql' :
|
case 'mysql' :
|
||||||
$pdo->exec("ALTER TABLE calendars ADD transparent TINYINT(1) NOT NULL DEFAULT '0'");
|
$pdo->exec("ALTER TABLE calendars ADD transparent TINYINT(1) NOT NULL DEFAULT '0'");
|
||||||
@ -229,8 +229,8 @@ function getDenormalizedData($calendarData) {
|
|||||||
$component = null;
|
$component = null;
|
||||||
$firstOccurence = null;
|
$firstOccurence = null;
|
||||||
$lastOccurence = null;
|
$lastOccurence = null;
|
||||||
foreach($vObject->getComponents() as $component) {
|
foreach ($vObject->getComponents() as $component) {
|
||||||
if ($component->name!=='VTIMEZONE') {
|
if ($component->name !== 'VTIMEZONE') {
|
||||||
$componentType = $component->name;
|
$componentType = $component->name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -256,13 +256,13 @@ function getDenormalizedData($calendarData) {
|
|||||||
$lastOccurence = $firstOccurence;
|
$lastOccurence = $firstOccurence;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$it = new \Sabre\VObject\RecurrenceIterator($vObject, (string)$component->UID);
|
$it = new \Sabre\VObject\Recur\EventIterator($vObject, (string)$component->UID);
|
||||||
$maxDate = new DateTime(\Sabre\CalDAV\Backend\PDO::MAX_DATE);
|
$maxDate = new DateTime(\Sabre\CalDAV\Backend\PDO::MAX_DATE);
|
||||||
if ($it->isInfinite()) {
|
if ($it->isInfinite()) {
|
||||||
$lastOccurence = $maxDate->getTimeStamp();
|
$lastOccurence = $maxDate->getTimeStamp();
|
||||||
} else {
|
} else {
|
||||||
$end = $it->getDtEnd();
|
$end = $it->getDtEnd();
|
||||||
while($it->valid() && $end < $maxDate) {
|
while ($it->valid() && $end < $maxDate) {
|
||||||
$end = $it->getDtEnd();
|
$end = $it->getDtEnd();
|
||||||
$it->next();
|
$it->next();
|
||||||
|
|
||||||
@ -273,12 +273,12 @@ function getDenormalizedData($calendarData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return array(
|
return [
|
||||||
'etag' => md5($calendarData),
|
'etag' => md5($calendarData),
|
||||||
'size' => strlen($calendarData),
|
'size' => strlen($calendarData),
|
||||||
'componentType' => $componentType,
|
'componentType' => $componentType,
|
||||||
'firstOccurence' => $firstOccurence,
|
'firstOccurence' => $firstOccurence,
|
||||||
'lastOccurence' => $lastOccurence,
|
'lastOccurence' => $lastOccurence,
|
||||||
);
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
453
vendor/sabre/dav/bin/migrateto20.php
vendored
Executable file
453
vendor/sabre/dav/bin/migrateto20.php
vendored
Executable file
@ -0,0 +1,453 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
echo "SabreDAV migrate script for version 2.0\n";
|
||||||
|
|
||||||
|
if ($argc < 2) {
|
||||||
|
|
||||||
|
echo <<<HELLO
|
||||||
|
|
||||||
|
This script help you migrate from a pre-2.0 database to 2.0 and later
|
||||||
|
|
||||||
|
The 'calendars', 'addressbooks' and 'cards' tables will be upgraded, and new
|
||||||
|
tables (calendarchanges, addressbookchanges, propertystorage) will be added.
|
||||||
|
|
||||||
|
If you don't use the default PDO CalDAV or CardDAV backend, it's pointless to
|
||||||
|
run this script.
|
||||||
|
|
||||||
|
Keep in mind that ALTER TABLE commands will be executed. If you have a large
|
||||||
|
dataset this may mean that this process takes a while.
|
||||||
|
|
||||||
|
Lastly: Make a back-up first. This script has been tested, but the amount of
|
||||||
|
potential variants are extremely high, so it's impossible to deal with every
|
||||||
|
possible situation.
|
||||||
|
|
||||||
|
In the worst case, you will lose all your data. This is not an overstatement.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
php {$argv[0]} [pdo-dsn] [username] [password]
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
php {$argv[0]} "mysql:host=localhost;dbname=sabredav" root password
|
||||||
|
php {$argv[0]} sqlite:data/sabredav.db
|
||||||
|
|
||||||
|
HELLO;
|
||||||
|
|
||||||
|
exit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's a bunch of places where the autoloader could be, so we'll try all of
|
||||||
|
// them.
|
||||||
|
$paths = [
|
||||||
|
__DIR__ . '/../vendor/autoload.php',
|
||||||
|
__DIR__ . '/../../../autoload.php',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($paths as $path) {
|
||||||
|
if (file_exists($path)) {
|
||||||
|
include $path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$dsn = $argv[1];
|
||||||
|
$user = isset($argv[2]) ? $argv[2] : null;
|
||||||
|
$pass = isset($argv[3]) ? $argv[3] : null;
|
||||||
|
|
||||||
|
echo "Connecting to database: " . $dsn . "\n";
|
||||||
|
|
||||||
|
$pdo = new PDO($dsn, $user, $pass);
|
||||||
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
|
||||||
|
case 'mysql' :
|
||||||
|
echo "Detected MySQL.\n";
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
echo "Detected SQLite.\n";
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
echo "Error: unsupported driver: " . $driver . "\n";
|
||||||
|
die(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (['calendar', 'addressbook'] as $itemType) {
|
||||||
|
|
||||||
|
$tableName = $itemType . 's';
|
||||||
|
$tableNameOld = $tableName . '_old';
|
||||||
|
$changesTable = $itemType . 'changes';
|
||||||
|
|
||||||
|
echo "Upgrading '$tableName'\n";
|
||||||
|
|
||||||
|
// The only cross-db way to do this, is to just fetch a single record.
|
||||||
|
$row = $pdo->query("SELECT * FROM $tableName LIMIT 1")->fetch();
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
|
||||||
|
echo "No records were found in the '$tableName' table.\n";
|
||||||
|
echo "\n";
|
||||||
|
echo "We're going to rename the old table to $tableNameOld (just in case).\n";
|
||||||
|
echo "and re-create the new table.\n";
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec("RENAME TABLE $tableName TO $tableNameOld");
|
||||||
|
switch ($itemType) {
|
||||||
|
case 'calendar' :
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE calendars (
|
||||||
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
principaluri VARCHAR(100),
|
||||||
|
displayname VARCHAR(100),
|
||||||
|
uri VARCHAR(200),
|
||||||
|
synctoken INT(11) UNSIGNED NOT NULL DEFAULT '1',
|
||||||
|
description TEXT,
|
||||||
|
calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
|
calendarcolor VARCHAR(10),
|
||||||
|
timezone TEXT,
|
||||||
|
components VARCHAR(20),
|
||||||
|
transparent TINYINT(1) NOT NULL DEFAULT '0',
|
||||||
|
UNIQUE(principaluri, uri)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||||
|
");
|
||||||
|
break;
|
||||||
|
case 'addressbook' :
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE addressbooks (
|
||||||
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
principaluri VARCHAR(255),
|
||||||
|
displayname VARCHAR(255),
|
||||||
|
uri VARCHAR(200),
|
||||||
|
description TEXT,
|
||||||
|
synctoken INT(11) UNSIGNED NOT NULL DEFAULT '1',
|
||||||
|
UNIQUE(principaluri, uri)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||||
|
");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'sqlite' :
|
||||||
|
|
||||||
|
$pdo->exec("ALTER TABLE $tableName RENAME TO $tableNameOld");
|
||||||
|
|
||||||
|
switch ($itemType) {
|
||||||
|
case 'calendar' :
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE calendars (
|
||||||
|
id integer primary key asc,
|
||||||
|
principaluri text,
|
||||||
|
displayname text,
|
||||||
|
uri text,
|
||||||
|
synctoken integer,
|
||||||
|
description text,
|
||||||
|
calendarorder integer,
|
||||||
|
calendarcolor text,
|
||||||
|
timezone text,
|
||||||
|
components text,
|
||||||
|
transparent bool
|
||||||
|
);
|
||||||
|
");
|
||||||
|
break;
|
||||||
|
case 'addressbook' :
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE addressbooks (
|
||||||
|
id integer primary key asc,
|
||||||
|
principaluri text,
|
||||||
|
displayname text,
|
||||||
|
uri text,
|
||||||
|
description text,
|
||||||
|
synctoken integer
|
||||||
|
);
|
||||||
|
");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
echo "Creation of 2.0 $tableName table is complete\n";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Checking if there's a synctoken field already.
|
||||||
|
if (array_key_exists('synctoken', $row)) {
|
||||||
|
echo "The 'synctoken' field already exists in the $tableName table.\n";
|
||||||
|
echo "It's likely you already upgraded, so we're simply leaving\n";
|
||||||
|
echo "the $tableName table alone\n";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
echo "1.8 table schema detected\n";
|
||||||
|
switch ($driver) {
|
||||||
|
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec("ALTER TABLE $tableName ADD synctoken INT(11) UNSIGNED NOT NULL DEFAULT '1'");
|
||||||
|
$pdo->exec("ALTER TABLE $tableName DROP ctag");
|
||||||
|
$pdo->exec("UPDATE $tableName SET synctoken = '1'");
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
$pdo->exec("ALTER TABLE $tableName ADD synctoken integer");
|
||||||
|
$pdo->exec("UPDATE $tableName SET synctoken = '1'");
|
||||||
|
echo "Note: there's no easy way to remove fields in sqlite.\n";
|
||||||
|
echo "The ctag field is no longer used, but it's kept in place\n";
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Upgraded '$tableName' to 2.0 schema.\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo->query("SELECT * FROM $changesTable LIMIT 1");
|
||||||
|
|
||||||
|
echo "'$changesTable' already exists. Assuming that this part of the\n";
|
||||||
|
echo "upgrade was already completed.\n";
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "Creating '$changesTable' table.\n";
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE $changesTable (
|
||||||
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
uri VARCHAR(200) NOT NULL,
|
||||||
|
synctoken INT(11) UNSIGNED NOT NULL,
|
||||||
|
{$itemType}id INT(11) UNSIGNED NOT NULL,
|
||||||
|
operation TINYINT(1) NOT NULL,
|
||||||
|
INDEX {$itemType}id_synctoken ({$itemType}id, synctoken)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||||
|
|
||||||
|
");
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
$pdo->exec("
|
||||||
|
|
||||||
|
CREATE TABLE $changesTable (
|
||||||
|
id integer primary key asc,
|
||||||
|
uri text,
|
||||||
|
synctoken integer,
|
||||||
|
{$itemType}id integer,
|
||||||
|
operation bool
|
||||||
|
);
|
||||||
|
|
||||||
|
");
|
||||||
|
$pdo->exec("CREATE INDEX {$itemType}id_synctoken ON $changesTable ({$itemType}id, synctoken);");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo->query("SELECT * FROM calendarsubscriptions LIMIT 1");
|
||||||
|
|
||||||
|
echo "'calendarsubscriptions' already exists. Assuming that this part of the\n";
|
||||||
|
echo "upgrade was already completed.\n";
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "Creating calendarsubscriptions table.\n";
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE calendarsubscriptions (
|
||||||
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
uri VARCHAR(200) NOT NULL,
|
||||||
|
principaluri VARCHAR(100) NOT NULL,
|
||||||
|
source TEXT,
|
||||||
|
displayname VARCHAR(100),
|
||||||
|
refreshrate VARCHAR(10),
|
||||||
|
calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
|
calendarcolor VARCHAR(10),
|
||||||
|
striptodos TINYINT(1) NULL,
|
||||||
|
stripalarms TINYINT(1) NULL,
|
||||||
|
stripattachments TINYINT(1) NULL,
|
||||||
|
lastmodified INT(11) UNSIGNED,
|
||||||
|
UNIQUE(principaluri, uri)
|
||||||
|
);
|
||||||
|
");
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
$pdo->exec("
|
||||||
|
|
||||||
|
CREATE TABLE calendarsubscriptions (
|
||||||
|
id integer primary key asc,
|
||||||
|
uri text,
|
||||||
|
principaluri text,
|
||||||
|
source text,
|
||||||
|
displayname text,
|
||||||
|
refreshrate text,
|
||||||
|
calendarorder integer,
|
||||||
|
calendarcolor text,
|
||||||
|
striptodos bool,
|
||||||
|
stripalarms bool,
|
||||||
|
stripattachments bool,
|
||||||
|
lastmodified int
|
||||||
|
);
|
||||||
|
");
|
||||||
|
|
||||||
|
$pdo->exec("CREATE INDEX principaluri_uri ON calendarsubscriptions (principaluri, uri);");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo->query("SELECT * FROM propertystorage LIMIT 1");
|
||||||
|
|
||||||
|
echo "'propertystorage' already exists. Assuming that this part of the\n";
|
||||||
|
echo "upgrade was already completed.\n";
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "Creating propertystorage table.\n";
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE propertystorage (
|
||||||
|
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
path VARBINARY(1024) NOT NULL,
|
||||||
|
name VARBINARY(100) NOT NULL,
|
||||||
|
value MEDIUMBLOB
|
||||||
|
);
|
||||||
|
");
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE UNIQUE INDEX path_property ON propertystorage (path(600), name(100));
|
||||||
|
");
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE propertystorage (
|
||||||
|
id integer primary key asc,
|
||||||
|
path TEXT,
|
||||||
|
name TEXT,
|
||||||
|
value TEXT
|
||||||
|
);
|
||||||
|
");
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE UNIQUE INDEX path_property ON propertystorage (path, name);
|
||||||
|
");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Upgrading cards table to 2.0 schema\n";
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$create = false;
|
||||||
|
$row = $pdo->query("SELECT * FROM cards LIMIT 1")->fetch();
|
||||||
|
if (!$row) {
|
||||||
|
$random = mt_rand(1000, 9999);
|
||||||
|
echo "There was no data in the cards table, so we're re-creating it\n";
|
||||||
|
echo "The old table will be renamed to cards_old$random, just in case.\n";
|
||||||
|
|
||||||
|
$create = true;
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec("RENAME TABLE cards TO cards_old$random");
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
$pdo->exec("ALTER TABLE cards RENAME TO cards_old$random");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
|
||||||
|
echo "Exception while checking cards table. Assuming that the table does not yet exist.\n";
|
||||||
|
echo "Debug: ", $e->getMessage(), "\n";
|
||||||
|
$create = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($create) {
|
||||||
|
switch ($driver) {
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE cards (
|
||||||
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
addressbookid INT(11) UNSIGNED NOT NULL,
|
||||||
|
carddata MEDIUMBLOB,
|
||||||
|
uri VARCHAR(200),
|
||||||
|
lastmodified INT(11) UNSIGNED,
|
||||||
|
etag VARBINARY(32),
|
||||||
|
size INT(11) UNSIGNED NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||||
|
|
||||||
|
");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'sqlite' :
|
||||||
|
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE cards (
|
||||||
|
id integer primary key asc,
|
||||||
|
addressbookid integer,
|
||||||
|
carddata blob,
|
||||||
|
uri text,
|
||||||
|
lastmodified integer,
|
||||||
|
etag text,
|
||||||
|
size integer
|
||||||
|
);
|
||||||
|
");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch ($driver) {
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec("
|
||||||
|
ALTER TABLE cards
|
||||||
|
ADD etag VARBINARY(32),
|
||||||
|
ADD size INT(11) UNSIGNED NOT NULL;
|
||||||
|
");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'sqlite' :
|
||||||
|
|
||||||
|
$pdo->exec("
|
||||||
|
ALTER TABLE cards ADD etag text;
|
||||||
|
ALTER TABLE cards ADD size integer;
|
||||||
|
");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
echo "Reading all old vcards and populating etag and size fields.\n";
|
||||||
|
$result = $pdo->query('SELECT id, carddata FROM cards');
|
||||||
|
$stmt = $pdo->prepare('UPDATE cards SET etag = ?, size = ? WHERE id = ?');
|
||||||
|
while ($row = $result->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$stmt->execute([
|
||||||
|
md5($row['carddata']),
|
||||||
|
strlen($row['carddata']),
|
||||||
|
$row['id']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Upgrade to 2.0 schema completed.\n";
|
180
vendor/sabre/dav/bin/migrateto21.php
vendored
Executable file
180
vendor/sabre/dav/bin/migrateto21.php
vendored
Executable file
@ -0,0 +1,180 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
echo "SabreDAV migrate script for version 2.1\n";
|
||||||
|
|
||||||
|
if ($argc < 2) {
|
||||||
|
|
||||||
|
echo <<<HELLO
|
||||||
|
|
||||||
|
This script help you migrate from a pre-2.1 database to 2.1.
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
The 'calendarobjects' table will be upgraded.
|
||||||
|
'schedulingobjects' will be created.
|
||||||
|
|
||||||
|
If you don't use the default PDO CalDAV or CardDAV backend, it's pointless to
|
||||||
|
run this script.
|
||||||
|
|
||||||
|
Keep in mind that ALTER TABLE commands will be executed. If you have a large
|
||||||
|
dataset this may mean that this process takes a while.
|
||||||
|
|
||||||
|
Lastly: Make a back-up first. This script has been tested, but the amount of
|
||||||
|
potential variants are extremely high, so it's impossible to deal with every
|
||||||
|
possible situation.
|
||||||
|
|
||||||
|
In the worst case, you will lose all your data. This is not an overstatement.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
php {$argv[0]} [pdo-dsn] [username] [password]
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
php {$argv[0]} "mysql:host=localhost;dbname=sabredav" root password
|
||||||
|
php {$argv[0]} sqlite:data/sabredav.db
|
||||||
|
|
||||||
|
HELLO;
|
||||||
|
|
||||||
|
exit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's a bunch of places where the autoloader could be, so we'll try all of
|
||||||
|
// them.
|
||||||
|
$paths = [
|
||||||
|
__DIR__ . '/../vendor/autoload.php',
|
||||||
|
__DIR__ . '/../../../autoload.php',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($paths as $path) {
|
||||||
|
if (file_exists($path)) {
|
||||||
|
include $path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$dsn = $argv[1];
|
||||||
|
$user = isset($argv[2]) ? $argv[2] : null;
|
||||||
|
$pass = isset($argv[3]) ? $argv[3] : null;
|
||||||
|
|
||||||
|
echo "Connecting to database: " . $dsn . "\n";
|
||||||
|
|
||||||
|
$pdo = new PDO($dsn, $user, $pass);
|
||||||
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
|
||||||
|
case 'mysql' :
|
||||||
|
echo "Detected MySQL.\n";
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
echo "Detected SQLite.\n";
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
echo "Error: unsupported driver: " . $driver . "\n";
|
||||||
|
die(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Upgrading 'calendarobjects'\n";
|
||||||
|
$addUid = false;
|
||||||
|
try {
|
||||||
|
$result = $pdo->query('SELECT * FROM calendarobjects LIMIT 1');
|
||||||
|
$row = $result->fetch(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
echo "No data in table. Going to try to add the uid field anyway.\n";
|
||||||
|
$addUid = true;
|
||||||
|
} elseif (array_key_exists('uid', $row)) {
|
||||||
|
echo "uid field exists. Assuming that this part of the migration has\n";
|
||||||
|
echo "Already been completed.\n";
|
||||||
|
} else {
|
||||||
|
echo "2.0 schema detected.\n";
|
||||||
|
$addUid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "Could not find a calendarobjects table. Skipping this part of the\n";
|
||||||
|
echo "upgrade.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($addUid) {
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec('ALTER TABLE calendarobjects ADD uid VARCHAR(200)');
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
$pdo->exec('ALTER TABLE calendarobjects ADD uid TEXT');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $pdo->query('SELECT id, calendardata FROM calendarobjects');
|
||||||
|
$stmt = $pdo->prepare('UPDATE calendarobjects SET uid = ? WHERE id = ?');
|
||||||
|
$counter = 0;
|
||||||
|
|
||||||
|
while ($row = $result->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
$vobj = \Sabre\VObject\Reader::read($row['calendardata']);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
echo "Warning! Item with id $row[id] could not be parsed!\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$uid = null;
|
||||||
|
$item = $vobj->getBaseComponent();
|
||||||
|
if (!isset($item->UID)) {
|
||||||
|
echo "Warning! Item with id $item[id] does NOT have a UID property and this is required.\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$uid = (string)$item->UID;
|
||||||
|
$stmt->execute([$uid, $row['id']]);
|
||||||
|
$counter++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Creating 'schedulingobjects'\n";
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec('CREATE TABLE IF NOT EXISTS schedulingobjects
|
||||||
|
(
|
||||||
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
principaluri VARCHAR(255),
|
||||||
|
calendardata MEDIUMBLOB,
|
||||||
|
uri VARCHAR(200),
|
||||||
|
lastmodified INT(11) UNSIGNED,
|
||||||
|
etag VARCHAR(32),
|
||||||
|
size INT(11) UNSIGNED NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||||
|
');
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'sqlite' :
|
||||||
|
$pdo->exec('CREATE TABLE IF NOT EXISTS schedulingobjects (
|
||||||
|
id integer primary key asc,
|
||||||
|
principaluri text,
|
||||||
|
calendardata blob,
|
||||||
|
uri text,
|
||||||
|
lastmodified integer,
|
||||||
|
etag text,
|
||||||
|
size integer
|
||||||
|
)
|
||||||
|
');
|
||||||
|
break;
|
||||||
|
$pdo->exec('
|
||||||
|
CREATE INDEX principaluri_uri ON calendarsubscriptions (principaluri, uri);
|
||||||
|
');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done.\n";
|
||||||
|
|
||||||
|
echo "Upgrade to 2.1 schema completed.\n";
|
171
vendor/sabre/dav/bin/migrateto30.php
vendored
Executable file
171
vendor/sabre/dav/bin/migrateto30.php
vendored
Executable file
@ -0,0 +1,171 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
echo "SabreDAV migrate script for version 3.0\n";
|
||||||
|
|
||||||
|
if ($argc < 2) {
|
||||||
|
|
||||||
|
echo <<<HELLO
|
||||||
|
|
||||||
|
This script help you migrate from a pre-3.0 database to 3.0 and later
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
* The propertystorage table has changed to allow storage of complex
|
||||||
|
properties.
|
||||||
|
* the vcardurl field in the principals table is no more. This was moved to
|
||||||
|
the propertystorage table.
|
||||||
|
|
||||||
|
Keep in mind that ALTER TABLE commands will be executed. If you have a large
|
||||||
|
dataset this may mean that this process takes a while.
|
||||||
|
|
||||||
|
Lastly: Make a back-up first. This script has been tested, but the amount of
|
||||||
|
potential variants are extremely high, so it's impossible to deal with every
|
||||||
|
possible situation.
|
||||||
|
|
||||||
|
In the worst case, you will lose all your data. This is not an overstatement.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
php {$argv[0]} [pdo-dsn] [username] [password]
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
php {$argv[0]} "mysql:host=localhost;dbname=sabredav" root password
|
||||||
|
php {$argv[0]} sqlite:data/sabredav.db
|
||||||
|
|
||||||
|
HELLO;
|
||||||
|
|
||||||
|
exit();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's a bunch of places where the autoloader could be, so we'll try all of
|
||||||
|
// them.
|
||||||
|
$paths = [
|
||||||
|
__DIR__ . '/../vendor/autoload.php',
|
||||||
|
__DIR__ . '/../../../autoload.php',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($paths as $path) {
|
||||||
|
if (file_exists($path)) {
|
||||||
|
include $path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$dsn = $argv[1];
|
||||||
|
$user = isset($argv[2]) ? $argv[2] : null;
|
||||||
|
$pass = isset($argv[3]) ? $argv[3] : null;
|
||||||
|
|
||||||
|
echo "Connecting to database: " . $dsn . "\n";
|
||||||
|
|
||||||
|
$pdo = new PDO($dsn, $user, $pass);
|
||||||
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
|
||||||
|
case 'mysql' :
|
||||||
|
echo "Detected MySQL.\n";
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
echo "Detected SQLite.\n";
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
echo "Error: unsupported driver: " . $driver . "\n";
|
||||||
|
die(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Upgrading 'propertystorage'\n";
|
||||||
|
$addValueType = false;
|
||||||
|
try {
|
||||||
|
$result = $pdo->query('SELECT * FROM propertystorage LIMIT 1');
|
||||||
|
$row = $result->fetch(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
echo "No data in table. Going to re-create the table.\n";
|
||||||
|
$random = mt_rand(1000, 9999);
|
||||||
|
echo "Renaming propertystorage -> propertystorage_old$random and creating new table.\n";
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec('RENAME TABLE propertystorage TO propertystorage_old' . $random);
|
||||||
|
$pdo->exec('
|
||||||
|
CREATE TABLE propertystorage (
|
||||||
|
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
path VARBINARY(1024) NOT NULL,
|
||||||
|
name VARBINARY(100) NOT NULL,
|
||||||
|
valuetype INT UNSIGNED,
|
||||||
|
value MEDIUMBLOB
|
||||||
|
);
|
||||||
|
');
|
||||||
|
$pdo->exec('CREATE UNIQUE INDEX path_property_' . $random . ' ON propertystorage (path(600), name(100));');
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
$pdo->exec('ALTER TABLE propertystorage RENAME TO propertystorage_old' . $random);
|
||||||
|
$pdo->exec('
|
||||||
|
CREATE TABLE propertystorage (
|
||||||
|
id integer primary key asc,
|
||||||
|
path text,
|
||||||
|
name text,
|
||||||
|
valuetype integer,
|
||||||
|
value blob
|
||||||
|
);');
|
||||||
|
|
||||||
|
$pdo->exec('CREATE UNIQUE INDEX path_property_' . $random . ' ON propertystorage (path, name);');
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
} elseif (array_key_exists('valuetype', $row)) {
|
||||||
|
echo "valuetype field exists. Assuming that this part of the migration has\n";
|
||||||
|
echo "Already been completed.\n";
|
||||||
|
} else {
|
||||||
|
echo "2.1 schema detected. Going to perform upgrade.\n";
|
||||||
|
$addValueType = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "Could not find a propertystorage table. Skipping this part of the\n";
|
||||||
|
echo "upgrade.\n";
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($addValueType) {
|
||||||
|
|
||||||
|
switch ($driver) {
|
||||||
|
case 'mysql' :
|
||||||
|
$pdo->exec('ALTER TABLE propertystorage ADD valuetype INT UNSIGNED');
|
||||||
|
break;
|
||||||
|
case 'sqlite' :
|
||||||
|
$pdo->exec('ALTER TABLE propertystorage ADD valuetype INT');
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->exec('UPDATE propertystorage SET valuetype = 1 WHERE valuetype IS NULL ');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Migrating vcardurl\n";
|
||||||
|
|
||||||
|
$result = $pdo->query('SELECT id, uri, vcardurl FROM principals WHERE vcardurl IS NOT NULL');
|
||||||
|
$stmt1 = $pdo->prepare('INSERT INTO propertystorage (path, name, valuetype, value) VALUES (?, ?, 3, ?)');
|
||||||
|
|
||||||
|
while ($row = $result->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
|
||||||
|
// Inserting the new record
|
||||||
|
$stmt1->execute([
|
||||||
|
'addressbooks/' . basename($row['uri']),
|
||||||
|
'{http://calendarserver.org/ns/}me-card',
|
||||||
|
serialize(new Sabre\DAV\Xml\Property\Href($row['vcardurl']))
|
||||||
|
]);
|
||||||
|
|
||||||
|
echo serialize(new Sabre\DAV\Xml\Property\Href($row['vcardurl']));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Done.\n";
|
||||||
|
echo "Upgrade to 3.0 schema completed.\n";
|
@ -6,7 +6,7 @@
|
|||||||
# http://www.rooftopsolutions.nl/
|
# http://www.rooftopsolutions.nl/
|
||||||
#
|
#
|
||||||
# This utility is distributed along with SabreDAV
|
# This utility is distributed along with SabreDAV
|
||||||
# license: http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
# license: http://sabre.io/license/ Modified BSD License
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
@ -16,16 +16,16 @@ def getfreespace(path):
|
|||||||
stat = os.statvfs(path)
|
stat = os.statvfs(path)
|
||||||
return stat.f_frsize * stat.f_bavail
|
return stat.f_frsize * stat.f_bavail
|
||||||
|
|
||||||
def getbytesleft(path,treshold):
|
def getbytesleft(path,threshold):
|
||||||
return getfreespace(path)-treshold
|
return getfreespace(path)-threshold
|
||||||
|
|
||||||
def run(cacheDir, treshold, sleep=5, simulate=False, min_erase = 0):
|
def run(cacheDir, threshold, sleep=5, simulate=False, min_erase = 0):
|
||||||
|
|
||||||
bytes = getbytesleft(cacheDir,treshold)
|
bytes = getbytesleft(cacheDir,threshold)
|
||||||
if (bytes>0):
|
if (bytes>0):
|
||||||
print "Bytes to go before we hit treshhold:", bytes
|
print "Bytes to go before we hit threshold:", bytes
|
||||||
else:
|
else:
|
||||||
print "Treshold exceeded with:", -bytes, "bytes"
|
print "Threshold exceeded with:", -bytes, "bytes"
|
||||||
dir = os.listdir(cacheDir)
|
dir = os.listdir(cacheDir)
|
||||||
dir2 = []
|
dir2 = []
|
||||||
for file in dir:
|
for file in dir:
|
||||||
@ -46,7 +46,7 @@ def run(cacheDir, treshold, sleep=5, simulate=False, min_erase = 0):
|
|||||||
left = min_erase
|
left = min_erase
|
||||||
|
|
||||||
# If the min_erase setting is lower than the amount of bytes over
|
# If the min_erase setting is lower than the amount of bytes over
|
||||||
# the treshold, we use that number instead.
|
# the threshold, we use that number instead.
|
||||||
if left < -bytes :
|
if left < -bytes :
|
||||||
left = -bytes
|
left = -bytes
|
||||||
|
|
||||||
@ -72,8 +72,8 @@ def run(cacheDir, treshold, sleep=5, simulate=False, min_erase = 0):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = OptionParser(
|
parser = OptionParser(
|
||||||
version="naturalselecton v0.3",
|
version="naturalselection v0.3",
|
||||||
description="Cache directory manager. Deletes cache entries based on accesstime and free space tresholds.\n" +
|
description="Cache directory manager. Deletes cache entries based on accesstime and free space thresholds.\n" +
|
||||||
"This utility is distributed alongside SabreDAV.",
|
"This utility is distributed alongside SabreDAV.",
|
||||||
usage="usage: %prog [options] cacheDirectory",
|
usage="usage: %prog [options] cacheDirectory",
|
||||||
)
|
)
|
||||||
@ -98,15 +98,15 @@ def main():
|
|||||||
default=5
|
default=5
|
||||||
)
|
)
|
||||||
parser.add_option(
|
parser.add_option(
|
||||||
'-l','--treshold',
|
'-l','--threshold',
|
||||||
help="Treshhold in bytes (default = 10737418240, which is 10GB)",
|
help="Threshold in bytes (default = 10737418240, which is 10GB)",
|
||||||
type="int",
|
type="int",
|
||||||
dest="treshold",
|
dest="threshold",
|
||||||
default=10737418240
|
default=10737418240
|
||||||
)
|
)
|
||||||
parser.add_option(
|
parser.add_option(
|
||||||
'-m', '--min-erase',
|
'-m', '--min-erase',
|
||||||
help="Minimum number of bytes to erase when the treshold is reached. " +
|
help="Minimum number of bytes to erase when the threshold is reached. " +
|
||||||
"Setting this option higher will reduce the amount of times the cache directory will need to be scanned. " +
|
"Setting this option higher will reduce the amount of times the cache directory will need to be scanned. " +
|
||||||
"(the default is 1073741824, which is 1GB.)",
|
"(the default is 1073741824, which is 1GB.)",
|
||||||
type="int",
|
type="int",
|
||||||
@ -130,7 +130,7 @@ def main():
|
|||||||
cacheDir,
|
cacheDir,
|
||||||
sleep=options.sleep,
|
sleep=options.sleep,
|
||||||
simulate=options.simulate,
|
simulate=options.simulate,
|
||||||
treshold=options.treshold,
|
threshold=options.threshold,
|
||||||
min_erase=options.min_erase
|
min_erase=options.min_erase
|
||||||
)
|
)
|
||||||
if runs>0:
|
if runs>0:
|
10
vendor/sabre/dav/bin/sabredav.php
vendored
10
vendor/sabre/dav/bin/sabredav.php
vendored
@ -8,7 +8,7 @@ class CliLog {
|
|||||||
|
|
||||||
function __construct() {
|
function __construct() {
|
||||||
|
|
||||||
$this->stream = fopen('php://stdout','w');
|
$this->stream = fopen('php://stdout', 'w');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,19 +20,19 @@ class CliLog {
|
|||||||
|
|
||||||
$log = new CliLog();
|
$log = new CliLog();
|
||||||
|
|
||||||
if (php_sapi_name()!=='cli-server') {
|
if (php_sapi_name() !== 'cli-server') {
|
||||||
die("This script is intended to run on the built-in php webserver");
|
die("This script is intended to run on the built-in php webserver");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finding composer
|
// Finding composer
|
||||||
|
|
||||||
|
|
||||||
$paths = array(
|
$paths = [
|
||||||
__DIR__ . '/../vendor/autoload.php',
|
__DIR__ . '/../vendor/autoload.php',
|
||||||
__DIR__ . '/../../../autoload.php',
|
__DIR__ . '/../../../autoload.php',
|
||||||
);
|
];
|
||||||
|
|
||||||
foreach($paths as $path) {
|
foreach ($paths as $path) {
|
||||||
if (file_exists($path)) {
|
if (file_exists($path)) {
|
||||||
include $path;
|
include $path;
|
||||||
break;
|
break;
|
||||||
|
13
vendor/sabre/dav/examples/addressbookserver.php
vendored
13
vendor/sabre/dav/examples/addressbookserver.php
vendored
@ -17,10 +17,10 @@ $baseUri = '/';
|
|||||||
|
|
||||||
/* Database */
|
/* Database */
|
||||||
$pdo = new PDO('sqlite:data/db.sqlite');
|
$pdo = new PDO('sqlite:data/db.sqlite');
|
||||||
$pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
//Mapping PHP errors to exceptions
|
//Mapping PHP errors to exceptions
|
||||||
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
|
function exception_error_handler($errno, $errstr, $errfile, $errline) {
|
||||||
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
|
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||||
}
|
}
|
||||||
set_error_handler("exception_error_handler");
|
set_error_handler("exception_error_handler");
|
||||||
@ -35,22 +35,23 @@ $carddavBackend = new Sabre\CardDAV\Backend\PDO($pdo);
|
|||||||
//$caldavBackend = new Sabre\CalDAV\Backend\PDO($pdo);
|
//$caldavBackend = new Sabre\CalDAV\Backend\PDO($pdo);
|
||||||
|
|
||||||
// Setting up the directory tree //
|
// Setting up the directory tree //
|
||||||
$nodes = array(
|
$nodes = [
|
||||||
new Sabre\DAVACL\PrincipalCollection($principalBackend),
|
new Sabre\DAVACL\PrincipalCollection($principalBackend),
|
||||||
// new Sabre\CalDAV\CalendarRootNode($authBackend, $caldavBackend),
|
// new Sabre\CalDAV\CalendarRoot($authBackend, $caldavBackend),
|
||||||
new Sabre\CardDAV\AddressBookRoot($principalBackend, $carddavBackend),
|
new Sabre\CardDAV\AddressBookRoot($principalBackend, $carddavBackend),
|
||||||
);
|
];
|
||||||
|
|
||||||
// The object tree needs in turn to be passed to the server class
|
// The object tree needs in turn to be passed to the server class
|
||||||
$server = new Sabre\DAV\Server($nodes);
|
$server = new Sabre\DAV\Server($nodes);
|
||||||
$server->setBaseUri($baseUri);
|
$server->setBaseUri($baseUri);
|
||||||
|
|
||||||
// Plugins
|
// Plugins
|
||||||
$server->addPlugin(new Sabre\DAV\Auth\Plugin($authBackend,'SabreDAV'));
|
$server->addPlugin(new Sabre\DAV\Auth\Plugin($authBackend));
|
||||||
$server->addPlugin(new Sabre\DAV\Browser\Plugin());
|
$server->addPlugin(new Sabre\DAV\Browser\Plugin());
|
||||||
//$server->addPlugin(new Sabre\CalDAV\Plugin());
|
//$server->addPlugin(new Sabre\CalDAV\Plugin());
|
||||||
$server->addPlugin(new Sabre\CardDAV\Plugin());
|
$server->addPlugin(new Sabre\CardDAV\Plugin());
|
||||||
$server->addPlugin(new Sabre\DAVACL\Plugin());
|
$server->addPlugin(new Sabre\DAVACL\Plugin());
|
||||||
|
$server->addPlugin(new Sabre\DAV\Sync\Plugin());
|
||||||
|
|
||||||
// And off we go!
|
// And off we go!
|
||||||
$server->exec();
|
$server->exec();
|
||||||
|
26
vendor/sabre/dav/examples/basicauth.php
vendored
26
vendor/sabre/dav/examples/basicauth.php
vendored
@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// !!!! Make sure the Sabre directory is in the include_path !!!
|
|
||||||
// example:
|
|
||||||
// set_include_path('lib/' . PATH_SEPARATOR . get_include_path());
|
|
||||||
|
|
||||||
// settings
|
|
||||||
date_default_timezone_set('Canada/Eastern');
|
|
||||||
|
|
||||||
// Files we need
|
|
||||||
require_once 'vendor/autoload.php';
|
|
||||||
|
|
||||||
$u = 'admin';
|
|
||||||
$p = '1234';
|
|
||||||
|
|
||||||
$auth = new \Sabre\HTTP\BasicAuth();
|
|
||||||
|
|
||||||
$result = $auth->getUserPass();
|
|
||||||
|
|
||||||
if (!$result || $result[0]!=$u || $result[1]!=$p) {
|
|
||||||
|
|
||||||
$auth->requireLogin();
|
|
||||||
echo "Authentication required\n";
|
|
||||||
die();
|
|
||||||
|
|
||||||
}
|
|
25
vendor/sabre/dav/examples/digestauth.php
vendored
25
vendor/sabre/dav/examples/digestauth.php
vendored
@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// !!!! Make sure the Sabre directory is in the include_path !!!
|
|
||||||
// example:
|
|
||||||
// set_include_path('lib/' . PATH_SEPARATOR . get_include_path());
|
|
||||||
|
|
||||||
// settings
|
|
||||||
date_default_timezone_set('Canada/Eastern');
|
|
||||||
|
|
||||||
// Files we need
|
|
||||||
require_once 'vendor/autoload.php';
|
|
||||||
|
|
||||||
$u = 'admin';
|
|
||||||
$p = '1234';
|
|
||||||
|
|
||||||
$auth = new \Sabre\HTTP\DigestAuth();
|
|
||||||
$auth->init();
|
|
||||||
|
|
||||||
if ($auth->getUsername() != $u || !$auth->validatePassword($p)) {
|
|
||||||
|
|
||||||
$auth->requireLogin();
|
|
||||||
echo "Authentication required\n";
|
|
||||||
die();
|
|
||||||
|
|
||||||
}
|
|
123
vendor/sabre/dav/examples/simplefsserver.php
vendored
123
vendor/sabre/dav/examples/simplefsserver.php
vendored
@ -1,123 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
// !!!! Make sure the Sabre directory is in the include_path !!!
|
|
||||||
// example:
|
|
||||||
// set_include_path('lib/' . PATH_SEPARATOR . get_include_path());
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
This example demonstrates a simple way to create your own virtual filesystems.
|
|
||||||
By extending the _File and Directory classes, you can easily create a tree
|
|
||||||
based on various datasources.
|
|
||||||
|
|
||||||
The most obvious example is the filesystem itself. A more complete and documented
|
|
||||||
example can be found in:
|
|
||||||
|
|
||||||
lib/Sabre/DAV/FS/Node.php
|
|
||||||
lib/Sabre/DAV/FS/Directory.php
|
|
||||||
lib/Sabre/DAV/FS/File.php
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// settings
|
|
||||||
date_default_timezone_set('Canada/Eastern');
|
|
||||||
$publicDir = 'public';
|
|
||||||
|
|
||||||
// Files we need
|
|
||||||
require_once 'vendor/autoload.php';
|
|
||||||
|
|
||||||
class MyCollection extends Sabre\DAV\Collection {
|
|
||||||
|
|
||||||
private $myPath;
|
|
||||||
|
|
||||||
function __construct($myPath) {
|
|
||||||
|
|
||||||
$this->myPath = $myPath;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function getChildren() {
|
|
||||||
|
|
||||||
$children = array();
|
|
||||||
// Loop through the directory, and create objects for each node
|
|
||||||
foreach(scandir($this->myPath) as $node) {
|
|
||||||
|
|
||||||
// Ignoring files staring with .
|
|
||||||
if ($node[0]==='.') continue;
|
|
||||||
|
|
||||||
$children[] = $this->getChild($node);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $children;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function getChild($name) {
|
|
||||||
|
|
||||||
$path = $this->myPath . '/' . $name;
|
|
||||||
|
|
||||||
// We have to throw a NotFound exception if the file didn't exist
|
|
||||||
if (!file\exists($this->myPath)) throw new \Sabre\DAV\Exception\NotFound('The file with name: ' . $name . ' could not be found');
|
|
||||||
// Some added security
|
|
||||||
|
|
||||||
if ($name[0]=='.') throw new \Sabre\DAV\Exception\Forbidden('Access denied');
|
|
||||||
|
|
||||||
if (is_dir($path)) {
|
|
||||||
|
|
||||||
return new \MyCollection($name);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
return new \MyFile($path);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function getName() {
|
|
||||||
|
|
||||||
return basename($this->myPath);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyFile extends \Sabre\DAV\File {
|
|
||||||
|
|
||||||
private $myPath;
|
|
||||||
|
|
||||||
function __construct($myPath) {
|
|
||||||
|
|
||||||
$this->myPath = $myPath;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function getName() {
|
|
||||||
|
|
||||||
return basename($this->myPath);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function get() {
|
|
||||||
|
|
||||||
return fopen($this->myPath,'r');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSize() {
|
|
||||||
|
|
||||||
return filesize($this->myPath);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure there is a directory in your current directory named 'public'. We will be exposing that directory to WebDAV
|
|
||||||
$rootNode = new \MyCollection($publicDir);
|
|
||||||
|
|
||||||
// The rootNode needs to be passed to the server object.
|
|
||||||
$server = new \Sabre\DAV\Server($rootNode);
|
|
||||||
|
|
||||||
// And off we go!
|
|
||||||
$server->exec();
|
|
@ -1,18 +1,28 @@
|
|||||||
CREATE TABLE addressbooks (
|
CREATE TABLE addressbooks (
|
||||||
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
principaluri VARCHAR(255),
|
principaluri VARBINARY(255),
|
||||||
displayname VARCHAR(255),
|
displayname VARCHAR(255),
|
||||||
uri VARCHAR(200),
|
uri VARBINARY(200),
|
||||||
description TEXT,
|
description TEXT,
|
||||||
ctag INT(11) UNSIGNED NOT NULL DEFAULT '1',
|
synctoken INT(11) UNSIGNED NOT NULL DEFAULT '1',
|
||||||
UNIQUE(principaluri, uri)
|
UNIQUE(principaluri(100), uri(100))
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
CREATE TABLE cards (
|
CREATE TABLE cards (
|
||||||
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
addressbookid INT(11) UNSIGNED NOT NULL,
|
addressbookid INT(11) UNSIGNED NOT NULL,
|
||||||
carddata MEDIUMBLOB,
|
carddata MEDIUMBLOB,
|
||||||
uri VARCHAR(200),
|
uri VARBINARY(200),
|
||||||
lastmodified INT(11) UNSIGNED
|
lastmodified INT(11) UNSIGNED,
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
etag VARBINARY(32),
|
||||||
|
size INT(11) UNSIGNED NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE addressbookchanges (
|
||||||
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
uri VARBINARY(200) NOT NULL,
|
||||||
|
synctoken INT(11) UNSIGNED NOT NULL,
|
||||||
|
addressbookid INT(11) UNSIGNED NOT NULL,
|
||||||
|
operation TINYINT(1) NOT NULL,
|
||||||
|
INDEX addressbookid_synctoken (addressbookid, synctoken)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
@ -1,28 +1,64 @@
|
|||||||
CREATE TABLE calendarobjects (
|
CREATE TABLE calendarobjects (
|
||||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
calendardata MEDIUMBLOB,
|
calendardata MEDIUMBLOB,
|
||||||
uri VARCHAR(200),
|
uri VARBINARY(200),
|
||||||
calendarid INTEGER UNSIGNED NOT NULL,
|
calendarid INTEGER UNSIGNED NOT NULL,
|
||||||
lastmodified INT(11) UNSIGNED,
|
lastmodified INT(11) UNSIGNED,
|
||||||
etag VARCHAR(32),
|
etag VARBINARY(32),
|
||||||
size INT(11) UNSIGNED NOT NULL,
|
size INT(11) UNSIGNED NOT NULL,
|
||||||
componenttype VARCHAR(8),
|
componenttype VARBINARY(8),
|
||||||
firstoccurence INT(11) UNSIGNED,
|
firstoccurence INT(11) UNSIGNED,
|
||||||
lastoccurence INT(11) UNSIGNED,
|
lastoccurence INT(11) UNSIGNED,
|
||||||
|
uid VARBINARY(200),
|
||||||
UNIQUE(calendarid, uri)
|
UNIQUE(calendarid, uri)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
CREATE TABLE calendars (
|
CREATE TABLE calendars (
|
||||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
principaluri VARCHAR(100),
|
principaluri VARBINARY(100),
|
||||||
displayname VARCHAR(100),
|
displayname VARCHAR(100),
|
||||||
uri VARCHAR(200),
|
uri VARBINARY(200),
|
||||||
ctag INTEGER UNSIGNED NOT NULL DEFAULT '0',
|
synctoken INTEGER UNSIGNED NOT NULL DEFAULT '1',
|
||||||
description TEXT,
|
description TEXT,
|
||||||
calendarorder INTEGER UNSIGNED NOT NULL DEFAULT '0',
|
calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
calendarcolor VARCHAR(10),
|
calendarcolor VARBINARY(10),
|
||||||
timezone TEXT,
|
timezone TEXT,
|
||||||
components VARCHAR(20),
|
components VARBINARY(21),
|
||||||
transparent TINYINT(1) NOT NULL DEFAULT '0',
|
transparent TINYINT(1) NOT NULL DEFAULT '0',
|
||||||
UNIQUE(principaluri, uri)
|
UNIQUE(principaluri, uri)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE calendarchanges (
|
||||||
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
uri VARBINARY(200) NOT NULL,
|
||||||
|
synctoken INT(11) UNSIGNED NOT NULL,
|
||||||
|
calendarid INT(11) UNSIGNED NOT NULL,
|
||||||
|
operation TINYINT(1) NOT NULL,
|
||||||
|
INDEX calendarid_synctoken (calendarid, synctoken)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE calendarsubscriptions (
|
||||||
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
uri VARBINARY(200) NOT NULL,
|
||||||
|
principaluri VARBINARY(100) NOT NULL,
|
||||||
|
source TEXT,
|
||||||
|
displayname VARCHAR(100),
|
||||||
|
refreshrate VARCHAR(10),
|
||||||
|
calendarorder INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
|
calendarcolor VARBINARY(10),
|
||||||
|
striptodos TINYINT(1) NULL,
|
||||||
|
stripalarms TINYINT(1) NULL,
|
||||||
|
stripattachments TINYINT(1) NULL,
|
||||||
|
lastmodified INT(11) UNSIGNED,
|
||||||
|
UNIQUE(principaluri, uri)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE schedulingobjects (
|
||||||
|
id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
principaluri VARBINARY(255),
|
||||||
|
calendardata MEDIUMBLOB,
|
||||||
|
uri VARBINARY(200),
|
||||||
|
lastmodified INT(11) UNSIGNED,
|
||||||
|
etag VARBINARY(32),
|
||||||
|
size INT(11) UNSIGNED NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
@ -3,11 +3,10 @@ CREATE TABLE locks (
|
|||||||
owner VARCHAR(100),
|
owner VARCHAR(100),
|
||||||
timeout INTEGER UNSIGNED,
|
timeout INTEGER UNSIGNED,
|
||||||
created INTEGER,
|
created INTEGER,
|
||||||
token VARCHAR(100),
|
token VARBINARY(100),
|
||||||
scope TINYINT,
|
scope TINYINT,
|
||||||
depth TINYINT,
|
depth TINYINT,
|
||||||
uri VARCHAR(1000),
|
uri VARBINARY(1000),
|
||||||
INDEX(token),
|
INDEX(token),
|
||||||
INDEX(uri)
|
INDEX(uri(100))
|
||||||
);
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
CREATE TABLE principals (
|
CREATE TABLE principals (
|
||||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
uri VARCHAR(200) NOT NULL,
|
uri VARBINARY(200) NOT NULL,
|
||||||
email VARCHAR(80),
|
email VARBINARY(80),
|
||||||
displayname VARCHAR(80),
|
displayname VARCHAR(80),
|
||||||
vcardurl VARCHAR(255),
|
|
||||||
UNIQUE(uri)
|
UNIQUE(uri)
|
||||||
);
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
CREATE TABLE groupmembers (
|
CREATE TABLE groupmembers (
|
||||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
principal_id INTEGER UNSIGNED NOT NULL,
|
principal_id INTEGER UNSIGNED NOT NULL,
|
||||||
member_id INTEGER UNSIGNED NOT NULL,
|
member_id INTEGER UNSIGNED NOT NULL,
|
||||||
UNIQUE(principal_id, member_id)
|
UNIQUE(principal_id, member_id)
|
||||||
);
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO principals (uri,email,displayname) VALUES
|
INSERT INTO principals (uri,email,displayname) VALUES
|
||||||
('principals/admin', 'admin@example.org','Administrator'),
|
('principals/admin', 'admin@example.org','Administrator'),
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
username VARCHAR(50),
|
username VARBINARY(50),
|
||||||
digesta1 VARCHAR(32),
|
digesta1 VARBINARY(32),
|
||||||
UNIQUE(username)
|
UNIQUE(username)
|
||||||
);
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
INSERT INTO users (username,digesta1) VALUES
|
INSERT INTO users (username,digesta1) VALUES
|
||||||
('admin', '87fd274b7b6c01e48d7c2f965da8ddf7');
|
('admin', '87fd274b7b6c01e48d7c2f965da8ddf7');
|
||||||
|
@ -4,7 +4,7 @@ CREATE TABLE addressbooks (
|
|||||||
displayname VARCHAR(255),
|
displayname VARCHAR(255),
|
||||||
uri VARCHAR(200),
|
uri VARCHAR(200),
|
||||||
description TEXT,
|
description TEXT,
|
||||||
ctag INTEGER NOT NULL DEFAULT 1
|
synctoken INTEGER NOT NULL DEFAULT 1
|
||||||
);
|
);
|
||||||
|
|
||||||
ALTER TABLE ONLY addressbooks
|
ALTER TABLE ONLY addressbooks
|
||||||
@ -18,7 +18,9 @@ CREATE TABLE cards (
|
|||||||
addressbookid INTEGER NOT NULL,
|
addressbookid INTEGER NOT NULL,
|
||||||
carddata TEXT,
|
carddata TEXT,
|
||||||
uri VARCHAR(200),
|
uri VARCHAR(200),
|
||||||
lastmodified INTEGER
|
lastmodified INTEGER,
|
||||||
|
etag VARCHAR(32),
|
||||||
|
size INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
ALTER TABLE ONLY cards
|
ALTER TABLE ONLY cards
|
||||||
@ -31,3 +33,20 @@ ALTER TABLE ONLY cards
|
|||||||
ADD CONSTRAINT cards_addressbookid_fkey FOREIGN KEY (addressbookid) REFERENCES addressbooks(id)
|
ADD CONSTRAINT cards_addressbookid_fkey FOREIGN KEY (addressbookid) REFERENCES addressbooks(id)
|
||||||
ON DELETE CASCADE;
|
ON DELETE CASCADE;
|
||||||
|
|
||||||
|
CREATE TABLE addressbookchanges (
|
||||||
|
id SERIAL NOT NULL,
|
||||||
|
uri VARCHAR(200) NOT NULL,
|
||||||
|
synctoken INTEGER NOT NULL,
|
||||||
|
addressbookid INTEGER NOT NULL,
|
||||||
|
operation SMALLINT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY addressbookchanges
|
||||||
|
ADD CONSTRAINT addressbookchanges_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
CREATE INDEX addressbookchanges_addressbookid_synctoken_ix
|
||||||
|
ON addressbookchanges USING btree (addressbookid, synctoken);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY addressbookchanges
|
||||||
|
ADD CONSTRAINT addressbookchanges_addressbookid_fkey FOREIGN KEY (addressbookid) REFERENCES addressbooks(id)
|
||||||
|
ON DELETE CASCADE;
|
||||||
|
@ -3,12 +3,13 @@ CREATE TABLE calendars (
|
|||||||
principaluri VARCHAR(100),
|
principaluri VARCHAR(100),
|
||||||
displayname VARCHAR(100),
|
displayname VARCHAR(100),
|
||||||
uri VARCHAR(200),
|
uri VARCHAR(200),
|
||||||
ctag INTEGER NOT NULL DEFAULT 0,
|
synctoken INTEGER NOT NULL DEFAULT 1,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
calendarorder INTEGER NOT NULL DEFAULT 0,
|
calendarorder INTEGER NOT NULL DEFAULT 0,
|
||||||
calendarcolor VARCHAR(10),
|
calendarcolor VARCHAR(10),
|
||||||
timezone TEXT,
|
timezone TEXT,
|
||||||
components VARCHAR(20),
|
components VARCHAR(20),
|
||||||
|
uid VARCHAR(200),
|
||||||
transparent SMALLINT NOT NULL DEFAULT '0'
|
transparent SMALLINT NOT NULL DEFAULT '0'
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -20,15 +21,16 @@ CREATE UNIQUE INDEX calendars_ukey
|
|||||||
|
|
||||||
CREATE TABLE calendarobjects (
|
CREATE TABLE calendarobjects (
|
||||||
id SERIAL NOT NULL,
|
id SERIAL NOT NULL,
|
||||||
calendarid INTEGER NOT NULL,
|
|
||||||
calendardata TEXT,
|
calendardata TEXT,
|
||||||
uri VARCHAR(200),
|
uri VARCHAR(200),
|
||||||
|
calendarid INTEGER NOT NULL,
|
||||||
|
lastmodified INTEGER,
|
||||||
etag VARCHAR(32),
|
etag VARCHAR(32),
|
||||||
size INTEGER NOT NULL,
|
size INTEGER NOT NULL,
|
||||||
componenttype VARCHAR(8),
|
componenttype VARCHAR(8),
|
||||||
lastmodified INTEGER,
|
|
||||||
firstoccurence INTEGER,
|
firstoccurence INTEGER,
|
||||||
lastoccurence INTEGER
|
lastoccurence INTEGER,
|
||||||
|
uid VARCHAR(200)
|
||||||
);
|
);
|
||||||
|
|
||||||
ALTER TABLE ONLY calendarobjects
|
ALTER TABLE ONLY calendarobjects
|
||||||
@ -40,3 +42,52 @@ CREATE UNIQUE INDEX calendarobjects_ukey
|
|||||||
ALTER TABLE ONLY calendarobjects
|
ALTER TABLE ONLY calendarobjects
|
||||||
ADD CONSTRAINT calendarobjects_calendarid_fkey FOREIGN KEY (calendarid) REFERENCES calendars(id)
|
ADD CONSTRAINT calendarobjects_calendarid_fkey FOREIGN KEY (calendarid) REFERENCES calendars(id)
|
||||||
ON DELETE CASCADE;
|
ON DELETE CASCADE;
|
||||||
|
|
||||||
|
CREATE TABLE calendarsubscriptions (
|
||||||
|
id SERIAL NOT NULL,
|
||||||
|
uri VARCHAR(200) NOT NULL,
|
||||||
|
principaluri VARCHAR(100) NOT NULL,
|
||||||
|
source TEXT,
|
||||||
|
displayname VARCHAR(100),
|
||||||
|
refreshrate VARCHAR(10),
|
||||||
|
calendarorder INTEGER NOT NULL DEFAULT 0,
|
||||||
|
calendarcolor VARCHAR(10),
|
||||||
|
striptodos SMALLINT NULL,
|
||||||
|
stripalarms SMALLINT NULL,
|
||||||
|
stripattachments SMALLINT NULL,
|
||||||
|
lastmodified INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY calendarsubscriptions
|
||||||
|
ADD CONSTRAINT calendarsubscriptions_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX calendarsubscriptions_ukey
|
||||||
|
ON calendarsubscriptions USING btree (principaluri, uri);
|
||||||
|
|
||||||
|
CREATE TABLE calendarchanges (
|
||||||
|
id SERIAL NOT NULL,
|
||||||
|
uri VARCHAR(200) NOT NULL,
|
||||||
|
synctoken INTEGER NOT NULL,
|
||||||
|
calendarid INTEGER NOT NULL,
|
||||||
|
operation SMALLINT NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY calendarchanges
|
||||||
|
ADD CONSTRAINT calendarchanges_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
CREATE INDEX calendarchanges_calendarid_synctoken_ix
|
||||||
|
ON calendarchanges USING btree (calendarid, synctoken);
|
||||||
|
|
||||||
|
ALTER TABLE ONLY calendarchanges
|
||||||
|
ADD CONSTRAINT calendarchanges_calendar_fk FOREIGN KEY (calendarid) REFERENCES calendars(id)
|
||||||
|
ON DELETE CASCADE;
|
||||||
|
|
||||||
|
CREATE TABLE schedulingobjects (
|
||||||
|
id SERIAL NOT NULL,
|
||||||
|
principaluri VARCHAR(255),
|
||||||
|
calendardata BYTEA,
|
||||||
|
uri VARCHAR(200),
|
||||||
|
lastmodified INTEGER,
|
||||||
|
etag VARCHAR(32),
|
||||||
|
size INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
12
vendor/sabre/dav/examples/sql/pgsql.locks.sql
vendored
12
vendor/sabre/dav/examples/sql/pgsql.locks.sql
vendored
@ -4,10 +4,16 @@ CREATE TABLE locks (
|
|||||||
timeout INTEGER,
|
timeout INTEGER,
|
||||||
created INTEGER,
|
created INTEGER,
|
||||||
token VARCHAR(100),
|
token VARCHAR(100),
|
||||||
scope smallint,
|
scope SMALLINT,
|
||||||
depth smallint,
|
depth SMALLINT,
|
||||||
uri text
|
uri TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
ALTER TABLE ONLY locks
|
ALTER TABLE ONLY locks
|
||||||
ADD CONSTRAINT locks_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT locks_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
CREATE INDEX locks_token_ix
|
||||||
|
ON locks USING btree (token);
|
||||||
|
|
||||||
|
CREATE INDEX locks_uri_ix
|
||||||
|
ON locks USING btree (uri);
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
CREATE TABLE principals (
|
CREATE TABLE principals (
|
||||||
id SERIAL NOT NULL,
|
id SERIAL NOT NULL,
|
||||||
uri VARCHAR(100) NOT NULL,
|
uri VARCHAR(200) NOT NULL,
|
||||||
email VARCHAR(80),
|
email VARCHAR(80),
|
||||||
displayname VARCHAR(80),
|
displayname VARCHAR(80)
|
||||||
vcardurl VARCHAR(255)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ALTER TABLE ONLY principals
|
ALTER TABLE ONLY principals
|
||||||
@ -28,10 +27,9 @@ ALTER TABLE ONLY groupmembers
|
|||||||
ADD CONSTRAINT groupmembers_principal_id_fkey FOREIGN KEY (principal_id) REFERENCES principals(id)
|
ADD CONSTRAINT groupmembers_principal_id_fkey FOREIGN KEY (principal_id) REFERENCES principals(id)
|
||||||
ON DELETE CASCADE;
|
ON DELETE CASCADE;
|
||||||
|
|
||||||
-- Is this correct correct link ... or not?
|
ALTER TABLE ONLY groupmembers
|
||||||
-- ALTER TABLE ONLY groupmembers
|
ADD CONSTRAINT groupmembers_member_id_id_fkey FOREIGN KEY (member_id) REFERENCES principals(id)
|
||||||
-- ADD CONSTRAINT groupmembers_member_id_id_fkey FOREIGN KEY (member_id) REFERENCES users(id)
|
ON DELETE CASCADE;
|
||||||
-- ON DELETE CASCADE;
|
|
||||||
|
|
||||||
INSERT INTO principals (uri,email,displayname) VALUES
|
INSERT INTO principals (uri,email,displayname) VALUES
|
||||||
('principals/admin', 'admin@example.org','Administrator'),
|
('principals/admin', 'admin@example.org','Administrator'),
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id SERIAL NOT NULL,
|
id SERIAL NOT NULL,
|
||||||
username VARCHAR(50),
|
username VARCHAR(50),
|
||||||
digesta1 VARCHAR(32),
|
digesta1 VARCHAR(32)
|
||||||
UNIQUE(username)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
ALTER TABLE ONLY users
|
ALTER TABLE ONLY users
|
||||||
|
@ -1,17 +1,28 @@
|
|||||||
CREATE TABLE addressbooks (
|
CREATE TABLE addressbooks (
|
||||||
id integer primary key asc,
|
id integer primary key asc NOT NULL,
|
||||||
principaluri text,
|
principaluri text NOT NULL,
|
||||||
displayname text,
|
displayname text,
|
||||||
uri text,
|
uri text NOT NULL,
|
||||||
description text,
|
description text,
|
||||||
ctag integer
|
synctoken integer DEFAULT 1 NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE cards (
|
CREATE TABLE cards (
|
||||||
id integer primary key asc,
|
id integer primary key asc NOT NULL,
|
||||||
addressbookid integer,
|
addressbookid integer NOT NULL,
|
||||||
carddata blob,
|
carddata blob,
|
||||||
uri text,
|
uri text NOT NULL,
|
||||||
lastmodified integer
|
lastmodified integer,
|
||||||
|
etag text,
|
||||||
|
size integer
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE addressbookchanges (
|
||||||
|
id integer primary key asc NOT NULL,
|
||||||
|
uri text,
|
||||||
|
synctoken integer NOT NULL,
|
||||||
|
addressbookid integer NOT NULL,
|
||||||
|
operation integer NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX addressbookid_synctoken ON addressbookchanges (addressbookid, synctoken);
|
||||||
|
@ -1,26 +1,64 @@
|
|||||||
CREATE TABLE calendarobjects (
|
CREATE TABLE calendarobjects (
|
||||||
id integer primary key asc,
|
id integer primary key asc NOT NULL,
|
||||||
calendardata blob,
|
calendardata blob NOT NULL,
|
||||||
uri text,
|
uri text NOT NULL,
|
||||||
calendarid integer,
|
calendarid integer NOT NULL,
|
||||||
lastmodified integer,
|
lastmodified integer NOT NULL,
|
||||||
etag text,
|
etag text NOT NULL,
|
||||||
size integer,
|
size integer NOT NULL,
|
||||||
componenttype text,
|
componenttype text,
|
||||||
firstoccurence integer,
|
firstoccurence integer,
|
||||||
lastoccurence integer
|
lastoccurence integer,
|
||||||
|
uid text
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE calendars (
|
CREATE TABLE calendars (
|
||||||
id integer primary key asc,
|
id integer primary key asc NOT NULL,
|
||||||
principaluri text,
|
principaluri text NOT NULL,
|
||||||
displayname text,
|
displayname text,
|
||||||
uri text,
|
uri text NOT NULL,
|
||||||
ctag integer,
|
synctoken integer DEFAULT 1 NOT NULL,
|
||||||
description text,
|
description text,
|
||||||
calendarorder integer,
|
calendarorder integer,
|
||||||
calendarcolor text,
|
calendarcolor text,
|
||||||
timezone text,
|
timezone text,
|
||||||
components text,
|
components text NOT NULL,
|
||||||
transparent bool
|
transparent bool
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE calendarchanges (
|
||||||
|
id integer primary key asc NOT NULL,
|
||||||
|
uri text,
|
||||||
|
synctoken integer NOT NULL,
|
||||||
|
calendarid integer NOT NULL,
|
||||||
|
operation integer NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX calendarid_synctoken ON calendarchanges (calendarid, synctoken);
|
||||||
|
|
||||||
|
CREATE TABLE calendarsubscriptions (
|
||||||
|
id integer primary key asc NOT NULL,
|
||||||
|
uri text NOT NULL,
|
||||||
|
principaluri text NOT NULL,
|
||||||
|
source text NOT NULL,
|
||||||
|
displayname text,
|
||||||
|
refreshrate text,
|
||||||
|
calendarorder integer,
|
||||||
|
calendarcolor text,
|
||||||
|
striptodos bool,
|
||||||
|
stripalarms bool,
|
||||||
|
stripattachments bool,
|
||||||
|
lastmodified int
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE schedulingobjects (
|
||||||
|
id integer primary key asc NOT NULL,
|
||||||
|
principaluri text NOT NULL,
|
||||||
|
calendardata blob,
|
||||||
|
uri text NOT NULL,
|
||||||
|
lastmodified integer,
|
||||||
|
etag text NOT NULL,
|
||||||
|
size integer NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX principaluri_uri ON calendarsubscriptions (principaluri, uri);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
CREATE TABLE locks (
|
CREATE TABLE locks (
|
||||||
id integer primary key asc,
|
id integer primary key asc NOT NULL,
|
||||||
owner text,
|
owner text,
|
||||||
timeout integer,
|
timeout integer,
|
||||||
created integer,
|
created integer,
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
CREATE TABLE principals (
|
CREATE TABLE principals (
|
||||||
id INTEGER PRIMARY KEY ASC,
|
id INTEGER PRIMARY KEY ASC NOT NULL,
|
||||||
uri TEXT,
|
uri TEXT NOT NULL,
|
||||||
email TEXT,
|
email TEXT,
|
||||||
displayname TEXT,
|
displayname TEXT,
|
||||||
vcardurl TEXT,
|
|
||||||
UNIQUE(uri)
|
UNIQUE(uri)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE groupmembers (
|
CREATE TABLE groupmembers (
|
||||||
id INTEGER PRIMARY KEY ASC,
|
id INTEGER PRIMARY KEY ASC NOT NULL,
|
||||||
principal_id INTEGER,
|
principal_id INTEGER NOT NULL,
|
||||||
member_id INTEGER,
|
member_id INTEGER NOT NULL,
|
||||||
UNIQUE(principal_id, member_id)
|
UNIQUE(principal_id, member_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id integer primary key asc,
|
id integer primary key asc NOT NULL,
|
||||||
username TEXT,
|
username TEXT NOT NULL,
|
||||||
digesta1 TEXT,
|
digesta1 TEXT NOT NULL,
|
||||||
UNIQUE(username)
|
UNIQUE(username)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -23,10 +23,6 @@
|
|||||||
# This is also to prevent high memory usage
|
# This is also to prevent high memory usage
|
||||||
php_flag always_populate_raw_post_data off
|
php_flag always_populate_raw_post_data off
|
||||||
|
|
||||||
# This is almost a given, but magic quotes is *still* on on some
|
|
||||||
# linux distributions
|
|
||||||
php_flag magic_quotes_gpc off
|
|
||||||
|
|
||||||
# SabreDAV is not compatible with mbstring function overloading
|
# SabreDAV is not compatible with mbstring function overloading
|
||||||
php_flag mbstring.func_overload off
|
php_flag mbstring.func_overload off
|
||||||
|
|
||||||
|
226
vendor/sabre/dav/lib/CalDAV/Backend/AbstractBackend.php
vendored
Normal file
226
vendor/sabre/dav/lib/CalDAV/Backend/AbstractBackend.php
vendored
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Backend;
|
||||||
|
|
||||||
|
use Sabre\VObject;
|
||||||
|
use Sabre\CalDAV;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract Calendaring backend. Extend this class to create your own backends.
|
||||||
|
*
|
||||||
|
* Checkout the BackendInterface for all the methods that must be implemented.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
abstract class AbstractBackend implements BackendInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates properties for a calendar.
|
||||||
|
*
|
||||||
|
* The list of mutations is stored in a Sabre\DAV\PropPatch object.
|
||||||
|
* To do the actual updates, you must tell this object which properties
|
||||||
|
* you're going to process with the handle() method.
|
||||||
|
*
|
||||||
|
* Calling the handle method is like telling the PropPatch object "I
|
||||||
|
* promise I can handle updating this property".
|
||||||
|
*
|
||||||
|
* Read the PropPatch documenation for more info and examples.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param \Sabre\DAV\PropPatch $propPatch
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of calendar objects.
|
||||||
|
*
|
||||||
|
* This method should work identical to getCalendarObject, but instead
|
||||||
|
* return all the calendar objects in the list as an array.
|
||||||
|
*
|
||||||
|
* If the backend supports this, it may allow for some speed-ups.
|
||||||
|
*
|
||||||
|
* @param mixed $calendarId
|
||||||
|
* @param array $uris
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getMultipleCalendarObjects($calendarId, array $uris) {
|
||||||
|
|
||||||
|
return array_map(function($uri) use ($calendarId) {
|
||||||
|
return $this->getCalendarObject($calendarId, $uri);
|
||||||
|
}, $uris);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a calendar-query on the contents of this calendar.
|
||||||
|
*
|
||||||
|
* The calendar-query is defined in RFC4791 : CalDAV. Using the
|
||||||
|
* calendar-query it is possible for a client to request a specific set of
|
||||||
|
* object, based on contents of iCalendar properties, date-ranges and
|
||||||
|
* iCalendar component types (VTODO, VEVENT).
|
||||||
|
*
|
||||||
|
* This method should just return a list of (relative) urls that match this
|
||||||
|
* query.
|
||||||
|
*
|
||||||
|
* The list of filters are specified as an array. The exact array is
|
||||||
|
* documented by \Sabre\CalDAV\CalendarQueryParser.
|
||||||
|
*
|
||||||
|
* Note that it is extremely likely that getCalendarObject for every path
|
||||||
|
* returned from this method will be called almost immediately after. You
|
||||||
|
* may want to anticipate this to speed up these requests.
|
||||||
|
*
|
||||||
|
* This method provides a default implementation, which parses *all* the
|
||||||
|
* iCalendar objects in the specified calendar.
|
||||||
|
*
|
||||||
|
* This default may well be good enough for personal use, and calendars
|
||||||
|
* that aren't very large. But if you anticipate high usage, big calendars
|
||||||
|
* or high loads, you are strongly adviced to optimize certain paths.
|
||||||
|
*
|
||||||
|
* The best way to do so is override this method and to optimize
|
||||||
|
* specifically for 'common filters'.
|
||||||
|
*
|
||||||
|
* Requests that are extremely common are:
|
||||||
|
* * requests for just VEVENTS
|
||||||
|
* * requests for just VTODO
|
||||||
|
* * requests with a time-range-filter on either VEVENT or VTODO.
|
||||||
|
*
|
||||||
|
* ..and combinations of these requests. It may not be worth it to try to
|
||||||
|
* handle every possible situation and just rely on the (relatively
|
||||||
|
* easy to use) CalendarQueryValidator to handle the rest.
|
||||||
|
*
|
||||||
|
* Note that especially time-range-filters may be difficult to parse. A
|
||||||
|
* time-range filter specified on a VEVENT must for instance also handle
|
||||||
|
* recurrence rules correctly.
|
||||||
|
* A good example of how to interprete all these filters can also simply
|
||||||
|
* be found in \Sabre\CalDAV\CalendarQueryFilter. This class is as correct
|
||||||
|
* as possible, so it gives you a good idea on what type of stuff you need
|
||||||
|
* to think of.
|
||||||
|
*
|
||||||
|
* @param mixed $calendarId
|
||||||
|
* @param array $filters
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function calendarQuery($calendarId, array $filters) {
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
$objects = $this->getCalendarObjects($calendarId);
|
||||||
|
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
|
||||||
|
if ($this->validateFilterForObject($object, $filters)) {
|
||||||
|
$result[] = $object['uri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method validates if a filter (as passed to calendarQuery) matches
|
||||||
|
* the given object.
|
||||||
|
*
|
||||||
|
* @param array $object
|
||||||
|
* @param array $filters
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function validateFilterForObject(array $object, array $filters) {
|
||||||
|
|
||||||
|
// Unfortunately, setting the 'calendardata' here is optional. If
|
||||||
|
// it was excluded, we actually need another call to get this as
|
||||||
|
// well.
|
||||||
|
if (!isset($object['calendardata'])) {
|
||||||
|
$object = $this->getCalendarObject($object['calendarid'], $object['uri']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$vObject = VObject\Reader::read($object['calendardata']);
|
||||||
|
|
||||||
|
$validator = new CalDAV\CalendarQueryValidator();
|
||||||
|
$result = $validator->validate($vObject, $filters);
|
||||||
|
|
||||||
|
// Destroy circular references so PHP will GC the object.
|
||||||
|
$vObject->destroy();
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches through all of a users calendars and calendar objects to find
|
||||||
|
* an object with a specific UID.
|
||||||
|
*
|
||||||
|
* This method should return the path to this object, relative to the
|
||||||
|
* calendar home, so this path usually only contains two parts:
|
||||||
|
*
|
||||||
|
* calendarpath/objectpath.ics
|
||||||
|
*
|
||||||
|
* If the uid is not found, return null.
|
||||||
|
*
|
||||||
|
* This method should only consider * objects that the principal owns, so
|
||||||
|
* any calendars owned by other principals that also appear in this
|
||||||
|
* collection should be ignored.
|
||||||
|
*
|
||||||
|
* @param string $principalUri
|
||||||
|
* @param string $uid
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getCalendarObjectByUID($principalUri, $uid) {
|
||||||
|
|
||||||
|
// Note: this is a super slow naive implementation of this method. You
|
||||||
|
// are highly recommended to optimize it, if your backend allows it.
|
||||||
|
foreach ($this->getCalendarsForUser($principalUri) as $calendar) {
|
||||||
|
|
||||||
|
// We must ignore calendars owned by other principals.
|
||||||
|
if ($calendar['principaluri'] !== $principalUri) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore calendars that are shared.
|
||||||
|
if (isset($calendar['{http://sabredav.org/ns}owner-principal']) && $calendar['{http://sabredav.org/ns}owner-principal'] !== $principalUri) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = $this->calendarQuery(
|
||||||
|
$calendar['id'],
|
||||||
|
[
|
||||||
|
'name' => 'VCALENDAR',
|
||||||
|
'prop-filters' => [],
|
||||||
|
'comp-filters' => [
|
||||||
|
[
|
||||||
|
'name' => 'VEVENT',
|
||||||
|
'is-not-defined' => false,
|
||||||
|
'time-range' => null,
|
||||||
|
'comp-filters' => [],
|
||||||
|
'prop-filters' => [
|
||||||
|
[
|
||||||
|
'name' => 'UID',
|
||||||
|
'is-not-defined' => false,
|
||||||
|
'time-range' => null,
|
||||||
|
'text-match' => [
|
||||||
|
'value' => $uid,
|
||||||
|
'negate-condition' => false,
|
||||||
|
'collation' => 'i;octet',
|
||||||
|
],
|
||||||
|
'param-filters' => [],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
if ($results) {
|
||||||
|
// We have a match
|
||||||
|
return $calendar['uri'] . '/' . $results[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,7 @@ namespace Sabre\CalDAV\Backend;
|
|||||||
/**
|
/**
|
||||||
* Every CalDAV backend must at least implement this interface.
|
* Every CalDAV backend must at least implement this interface.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -17,7 +17,7 @@ interface BackendInterface {
|
|||||||
* Every project is an array with the following keys:
|
* Every project is an array with the following keys:
|
||||||
* * id, a unique id that will be used by other functions to modify the
|
* * id, a unique id that will be used by other functions to modify the
|
||||||
* calendar. This can be the same as the uri or a database key.
|
* calendar. This can be the same as the uri or a database key.
|
||||||
* * uri, which the basename of the uri with which the calendar is
|
* * uri, which is the basename of the uri with which the calendar is
|
||||||
* accessed.
|
* accessed.
|
||||||
* * principaluri. The owner of the calendar. Almost always the same as
|
* * principaluri. The owner of the calendar. Almost always the same as
|
||||||
* principalUri passed to this method.
|
* principalUri passed to this method.
|
||||||
@ -25,82 +25,74 @@ interface BackendInterface {
|
|||||||
* Furthermore it can contain webdav properties in clark notation. A very
|
* Furthermore it can contain webdav properties in clark notation. A very
|
||||||
* common one is '{DAV:}displayname'.
|
* common one is '{DAV:}displayname'.
|
||||||
*
|
*
|
||||||
|
* Many clients also require:
|
||||||
|
* {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
|
||||||
|
* For this property, you can just return an instance of
|
||||||
|
* Sabre\CalDAV\Property\SupportedCalendarComponentSet.
|
||||||
|
*
|
||||||
|
* If you return {http://sabredav.org/ns}read-only and set the value to 1,
|
||||||
|
* ACL will automatically be put in read-only mode.
|
||||||
|
*
|
||||||
* @param string $principalUri
|
* @param string $principalUri
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getCalendarsForUser($principalUri);
|
function getCalendarsForUser($principalUri);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new calendar for a principal.
|
* Creates a new calendar for a principal.
|
||||||
*
|
*
|
||||||
* If the creation was a success, an id must be returned that can be used to reference
|
* If the creation was a success, an id must be returned that can be used to
|
||||||
* this calendar in other methods, such as updateCalendar.
|
* reference this calendar in other methods, such as updateCalendar.
|
||||||
*
|
*
|
||||||
* @param string $principalUri
|
* @param string $principalUri
|
||||||
* @param string $calendarUri
|
* @param string $calendarUri
|
||||||
* @param array $properties
|
* @param array $properties
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function createCalendar($principalUri,$calendarUri,array $properties);
|
function createCalendar($principalUri, $calendarUri, array $properties);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates properties for a calendar.
|
* Updates properties for a calendar.
|
||||||
*
|
*
|
||||||
* The mutations array uses the propertyName in clark-notation as key,
|
* The list of mutations is stored in a Sabre\DAV\PropPatch object.
|
||||||
* and the array value for the property value. In the case a property
|
* To do the actual updates, you must tell this object which properties
|
||||||
* should be deleted, the property value will be null.
|
* you're going to process with the handle() method.
|
||||||
*
|
*
|
||||||
* This method must be atomic. If one property cannot be changed, the
|
* Calling the handle method is like telling the PropPatch object "I
|
||||||
* entire operation must fail.
|
* promise I can handle updating this property".
|
||||||
*
|
*
|
||||||
* If the operation was successful, true can be returned.
|
* Read the PropPatch documentation for more info and examples.
|
||||||
* If the operation failed, false can be returned.
|
|
||||||
*
|
*
|
||||||
* Deletion of a non-existent property is always successful.
|
* @param string $path
|
||||||
*
|
* @param \Sabre\DAV\PropPatch $propPatch
|
||||||
* Lastly, it is optional to return detailed information about any
|
* @return void
|
||||||
* failures. In this case an array should be returned with the following
|
|
||||||
* structure:
|
|
||||||
*
|
|
||||||
* array(
|
|
||||||
* 403 => array(
|
|
||||||
* '{DAV:}displayname' => null,
|
|
||||||
* ),
|
|
||||||
* 424 => array(
|
|
||||||
* '{DAV:}owner' => null,
|
|
||||||
* )
|
|
||||||
* )
|
|
||||||
*
|
|
||||||
* In this example it was forbidden to update {DAV:}displayname.
|
|
||||||
* (403 Forbidden), which in turn also caused {DAV:}owner to fail
|
|
||||||
* (424 Failed Dependency) because the request needs to be atomic.
|
|
||||||
*
|
|
||||||
* @param mixed $calendarId
|
|
||||||
* @param array $mutations
|
|
||||||
* @return bool|array
|
|
||||||
*/
|
*/
|
||||||
public function updateCalendar($calendarId, array $mutations);
|
function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a calendar and all it's objects
|
* Delete a calendar and all its objects
|
||||||
*
|
*
|
||||||
* @param mixed $calendarId
|
* @param mixed $calendarId
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function deleteCalendar($calendarId);
|
function deleteCalendar($calendarId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all calendar objects within a calendar.
|
* Returns all calendar objects within a calendar.
|
||||||
*
|
*
|
||||||
* Every item contains an array with the following keys:
|
* Every item contains an array with the following keys:
|
||||||
* * id - unique identifier which will be used for subsequent updates
|
|
||||||
* * calendardata - The iCalendar-compatible calendar data
|
* * calendardata - The iCalendar-compatible calendar data
|
||||||
* * uri - a unique key which will be used to construct the uri. This can be any arbitrary string.
|
* * uri - a unique key which will be used to construct the uri. This can
|
||||||
|
* be any arbitrary string, but making sure it ends with '.ics' is a
|
||||||
|
* good idea. This is only the basename, or filename, not the full
|
||||||
|
* path.
|
||||||
* * lastmodified - a timestamp of the last modification time
|
* * lastmodified - a timestamp of the last modification time
|
||||||
* * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
|
* * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
|
||||||
* ' "abcdef"')
|
* '"abcdef"')
|
||||||
* * calendarid - The calendarid as it was passed to this function.
|
|
||||||
* * size - The size of the calendar objects, in bytes.
|
* * size - The size of the calendar objects, in bytes.
|
||||||
|
* * component - optional, a string containing the type of object, such
|
||||||
|
* as 'vevent' or 'vtodo'. If specified, this will be used to populate
|
||||||
|
* the Content-Type header.
|
||||||
*
|
*
|
||||||
* Note that the etag is optional, but it's highly encouraged to return for
|
* Note that the etag is optional, but it's highly encouraged to return for
|
||||||
* speed reasons.
|
* speed reasons.
|
||||||
@ -116,12 +108,14 @@ interface BackendInterface {
|
|||||||
* @param mixed $calendarId
|
* @param mixed $calendarId
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getCalendarObjects($calendarId);
|
function getCalendarObjects($calendarId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns information from a single calendar object, based on it's object
|
* Returns information from a single calendar object, based on it's object
|
||||||
* uri.
|
* uri.
|
||||||
*
|
*
|
||||||
|
* The object uri is only the basename, or filename and not a full path.
|
||||||
|
*
|
||||||
* The returned array must have the same keys as getCalendarObjects. The
|
* The returned array must have the same keys as getCalendarObjects. The
|
||||||
* 'calendardata' object is required here though, while it's not required
|
* 'calendardata' object is required here though, while it's not required
|
||||||
* for getCalendarObjects.
|
* for getCalendarObjects.
|
||||||
@ -132,14 +126,30 @@ interface BackendInterface {
|
|||||||
* @param string $objectUri
|
* @param string $objectUri
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function getCalendarObject($calendarId,$objectUri);
|
function getCalendarObject($calendarId, $objectUri);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of calendar objects.
|
||||||
|
*
|
||||||
|
* This method should work identical to getCalendarObject, but instead
|
||||||
|
* return all the calendar objects in the list as an array.
|
||||||
|
*
|
||||||
|
* If the backend supports this, it may allow for some speed-ups.
|
||||||
|
*
|
||||||
|
* @param mixed $calendarId
|
||||||
|
* @param array $uris
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getMultipleCalendarObjects($calendarId, array $uris);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new calendar object.
|
* Creates a new calendar object.
|
||||||
*
|
*
|
||||||
* It is possible return an etag from this function, which will be used in
|
* The object uri is only the basename, or filename and not a full path.
|
||||||
* the response to this PUT request. Note that the ETag must be surrounded
|
*
|
||||||
* by double-quotes.
|
* It is possible to return an etag from this function, which will be used
|
||||||
|
* in the response to this PUT request. Note that the ETag must be
|
||||||
|
* surrounded by double-quotes.
|
||||||
*
|
*
|
||||||
* However, you should only really return this ETag if you don't mangle the
|
* However, you should only really return this ETag if you don't mangle the
|
||||||
* calendar-data. If the result of a subsequent GET to this object is not
|
* calendar-data. If the result of a subsequent GET to this object is not
|
||||||
@ -150,11 +160,13 @@ interface BackendInterface {
|
|||||||
* @param string $calendarData
|
* @param string $calendarData
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function createCalendarObject($calendarId,$objectUri,$calendarData);
|
function createCalendarObject($calendarId, $objectUri, $calendarData);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates an existing calendarobject, based on it's uri.
|
* Updates an existing calendarobject, based on it's uri.
|
||||||
*
|
*
|
||||||
|
* The object uri is only the basename, or filename and not a full path.
|
||||||
|
*
|
||||||
* It is possible return an etag from this function, which will be used in
|
* It is possible return an etag from this function, which will be used in
|
||||||
* the response to this PUT request. Note that the ETag must be surrounded
|
* the response to this PUT request. Note that the ETag must be surrounded
|
||||||
* by double-quotes.
|
* by double-quotes.
|
||||||
@ -168,16 +180,18 @@ interface BackendInterface {
|
|||||||
* @param string $calendarData
|
* @param string $calendarData
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function updateCalendarObject($calendarId,$objectUri,$calendarData);
|
function updateCalendarObject($calendarId, $objectUri, $calendarData);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes an existing calendar object.
|
* Deletes an existing calendar object.
|
||||||
*
|
*
|
||||||
|
* The object uri is only the basename, or filename and not a full path.
|
||||||
|
*
|
||||||
* @param mixed $calendarId
|
* @param mixed $calendarId
|
||||||
* @param string $objectUri
|
* @param string $objectUri
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function deleteCalendarObject($calendarId,$objectUri);
|
function deleteCalendarObject($calendarId, $objectUri);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a calendar-query on the contents of this calendar.
|
* Performs a calendar-query on the contents of this calendar.
|
||||||
@ -228,6 +242,27 @@ interface BackendInterface {
|
|||||||
* @param array $filters
|
* @param array $filters
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function calendarQuery($calendarId, array $filters);
|
function calendarQuery($calendarId, array $filters);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches through all of a users calendars and calendar objects to find
|
||||||
|
* an object with a specific UID.
|
||||||
|
*
|
||||||
|
* This method should return the path to this object, relative to the
|
||||||
|
* calendar home, so this path usually only contains two parts:
|
||||||
|
*
|
||||||
|
* calendarpath/objectpath.ics
|
||||||
|
*
|
||||||
|
* If the uid is not found, return null.
|
||||||
|
*
|
||||||
|
* This method should only consider * objects that the principal owns, so
|
||||||
|
* any calendars owned by other principals that also appear in this
|
||||||
|
* collection should be ignored.
|
||||||
|
*
|
||||||
|
* @param string $principalUri
|
||||||
|
* @param string $uid
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getCalendarObjectByUID($principalUri, $uid);
|
||||||
|
|
||||||
}
|
}
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Sabre\CalDAV\Backend;
|
namespace Sabre\CalDAV\Backend;
|
||||||
|
|
||||||
|
use Sabre\CalDAV\Xml\Notification\NotificationInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds caldav notification support to a backend.
|
* Adds caldav notification support to a backend.
|
||||||
*
|
*
|
||||||
@ -16,7 +18,7 @@ namespace Sabre\CalDAV\Backend;
|
|||||||
*
|
*
|
||||||
* The primary usecase is to allow for calendar-sharing.
|
* The primary usecase is to allow for calendar-sharing.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -25,13 +27,10 @@ interface NotificationSupport extends BackendInterface {
|
|||||||
/**
|
/**
|
||||||
* Returns a list of notifications for a given principal url.
|
* Returns a list of notifications for a given principal url.
|
||||||
*
|
*
|
||||||
* The returned array should only consist of implementations of
|
|
||||||
* \Sabre\CalDAV\Notifications\INotificationType.
|
|
||||||
*
|
|
||||||
* @param string $principalUri
|
* @param string $principalUri
|
||||||
* @return array
|
* @return NotificationInterface[]
|
||||||
*/
|
*/
|
||||||
public function getNotificationsForPrincipal($principalUri);
|
function getNotificationsForPrincipal($principalUri);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This deletes a specific notifcation.
|
* This deletes a specific notifcation.
|
||||||
@ -39,9 +38,9 @@ interface NotificationSupport extends BackendInterface {
|
|||||||
* This may be called by a client once it deems a notification handled.
|
* This may be called by a client once it deems a notification handled.
|
||||||
*
|
*
|
||||||
* @param string $principalUri
|
* @param string $principalUri
|
||||||
* @param \Sabre\CalDAV\Notifications\INotificationType $notification
|
* @param NotificationInterface $notification
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function deleteNotification($principalUri, \Sabre\CalDAV\Notifications\INotificationType $notification);
|
function deleteNotification($principalUri, NotificationInterface $notification);
|
||||||
|
|
||||||
}
|
}
|
1210
vendor/sabre/dav/lib/CalDAV/Backend/PDO.php
vendored
Normal file
1210
vendor/sabre/dav/lib/CalDAV/Backend/PDO.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
65
vendor/sabre/dav/lib/CalDAV/Backend/SchedulingSupport.php
vendored
Normal file
65
vendor/sabre/dav/lib/CalDAV/Backend/SchedulingSupport.php
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Backend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementing this interface adds CalDAV Scheduling support to your caldav
|
||||||
|
* server, as defined in rfc6638.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
interface SchedulingSupport extends BackendInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a single scheduling object for the inbox collection.
|
||||||
|
*
|
||||||
|
* The returned array should contain the following elements:
|
||||||
|
* * uri - A unique basename for the object. This will be used to
|
||||||
|
* construct a full uri.
|
||||||
|
* * calendardata - The iCalendar object
|
||||||
|
* * lastmodified - The last modification date. Can be an int for a unix
|
||||||
|
* timestamp, or a PHP DateTime object.
|
||||||
|
* * etag - A unique token that must change if the object changed.
|
||||||
|
* * size - The size of the object, in bytes.
|
||||||
|
*
|
||||||
|
* @param string $principalUri
|
||||||
|
* @param string $objectUri
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getSchedulingObject($principalUri, $objectUri);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all scheduling objects for the inbox collection.
|
||||||
|
*
|
||||||
|
* These objects should be returned as an array. Every item in the array
|
||||||
|
* should follow the same structure as returned from getSchedulingObject.
|
||||||
|
*
|
||||||
|
* The main difference is that 'calendardata' is optional.
|
||||||
|
*
|
||||||
|
* @param string $principalUri
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getSchedulingObjects($principalUri);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a scheduling object from the inbox collection.
|
||||||
|
*
|
||||||
|
* @param string $principalUri
|
||||||
|
* @param string $objectUri
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function deleteSchedulingObject($principalUri, $objectUri);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new scheduling object. This should land in a users' inbox.
|
||||||
|
*
|
||||||
|
* @param string $principalUri
|
||||||
|
* @param string $objectUri
|
||||||
|
* @param string $objectData
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function createSchedulingObject($principalUri, $objectUri, $objectData);
|
||||||
|
|
||||||
|
}
|
@ -70,7 +70,7 @@ namespace Sabre\CalDAV\Backend;
|
|||||||
* In the case of an invite, the sharee may reply with an 'accept' or
|
* In the case of an invite, the sharee may reply with an 'accept' or
|
||||||
* 'decline'. These are always represented by:
|
* 'decline'. These are always represented by:
|
||||||
*
|
*
|
||||||
* Sabre\CalDAV\Notifications\Notification\Invite
|
* Sabre\CalDAV\Notifications\Notification\InviteReply
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Calendar access by sharees
|
* Calendar access by sharees
|
||||||
@ -136,7 +136,7 @@ namespace Sabre\CalDAV\Backend;
|
|||||||
* * unpublished
|
* * unpublished
|
||||||
*
|
*
|
||||||
* If a calendar is published, the following property should be returned
|
* If a calendar is published, the following property should be returned
|
||||||
* for each calendar in getCalendarsForPrincipal.
|
* for each calendar in getCalendarsForUser.
|
||||||
*
|
*
|
||||||
* {http://calendarserver.org/ns/}publish-url
|
* {http://calendarserver.org/ns/}publish-url
|
||||||
*
|
*
|
||||||
@ -157,7 +157,7 @@ namespace Sabre\CalDAV\Backend;
|
|||||||
* ==============================================
|
* ==============================================
|
||||||
*
|
*
|
||||||
* If Sabre\CalDAV\Property\AllowedSharingModes is returned from
|
* If Sabre\CalDAV\Property\AllowedSharingModes is returned from
|
||||||
* getCalendarsByUser, this allows the server to specify whether either sharing,
|
* getCalendarsForUser, this allows the server to specify whether either sharing,
|
||||||
* or publishing is supported.
|
* or publishing is supported.
|
||||||
*
|
*
|
||||||
* This allows a client to determine in advance which features are available,
|
* This allows a client to determine in advance which features are available,
|
||||||
@ -165,7 +165,7 @@ namespace Sabre\CalDAV\Backend;
|
|||||||
* the backend, the SharingPlugin automatically injects it and assumes both
|
* the backend, the SharingPlugin automatically injects it and assumes both
|
||||||
* features are available.
|
* features are available.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
89
vendor/sabre/dav/lib/CalDAV/Backend/SubscriptionSupport.php
vendored
Normal file
89
vendor/sabre/dav/lib/CalDAV/Backend/SubscriptionSupport.php
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Backend;
|
||||||
|
|
||||||
|
use Sabre\DAV;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every CalDAV backend must at least implement this interface.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
interface SubscriptionSupport extends BackendInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of subscriptions for a principal.
|
||||||
|
*
|
||||||
|
* Every subscription is an array with the following keys:
|
||||||
|
* * id, a unique id that will be used by other functions to modify the
|
||||||
|
* subscription. This can be the same as the uri or a database key.
|
||||||
|
* * uri. This is just the 'base uri' or 'filename' of the subscription.
|
||||||
|
* * principaluri. The owner of the subscription. Almost always the same as
|
||||||
|
* principalUri passed to this method.
|
||||||
|
*
|
||||||
|
* Furthermore, all the subscription info must be returned too:
|
||||||
|
*
|
||||||
|
* 1. {DAV:}displayname
|
||||||
|
* 2. {http://apple.com/ns/ical/}refreshrate
|
||||||
|
* 3. {http://calendarserver.org/ns/}subscribed-strip-todos (omit if todos
|
||||||
|
* should not be stripped).
|
||||||
|
* 4. {http://calendarserver.org/ns/}subscribed-strip-alarms (omit if alarms
|
||||||
|
* should not be stripped).
|
||||||
|
* 5. {http://calendarserver.org/ns/}subscribed-strip-attachments (omit if
|
||||||
|
* attachments should not be stripped).
|
||||||
|
* 6. {http://calendarserver.org/ns/}source (Must be a
|
||||||
|
* Sabre\DAV\Property\Href).
|
||||||
|
* 7. {http://apple.com/ns/ical/}calendar-color
|
||||||
|
* 8. {http://apple.com/ns/ical/}calendar-order
|
||||||
|
* 9. {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set
|
||||||
|
* (should just be an instance of
|
||||||
|
* Sabre\CalDAV\Property\SupportedCalendarComponentSet, with a bunch of
|
||||||
|
* default components).
|
||||||
|
*
|
||||||
|
* @param string $principalUri
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getSubscriptionsForUser($principalUri);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new subscription for a principal.
|
||||||
|
*
|
||||||
|
* If the creation was a success, an id must be returned that can be used to reference
|
||||||
|
* this subscription in other methods, such as updateSubscription.
|
||||||
|
*
|
||||||
|
* @param string $principalUri
|
||||||
|
* @param string $uri
|
||||||
|
* @param array $properties
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function createSubscription($principalUri, $uri, array $properties);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a subscription
|
||||||
|
*
|
||||||
|
* The list of mutations is stored in a Sabre\DAV\PropPatch object.
|
||||||
|
* To do the actual updates, you must tell this object which properties
|
||||||
|
* you're going to process with the handle() method.
|
||||||
|
*
|
||||||
|
* Calling the handle method is like telling the PropPatch object "I
|
||||||
|
* promise I can handle updating this property".
|
||||||
|
*
|
||||||
|
* Read the PropPatch documenation for more info and examples.
|
||||||
|
*
|
||||||
|
* @param mixed $subscriptionId
|
||||||
|
* @param \Sabre\DAV\PropPatch $propPatch
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function updateSubscription($subscriptionId, DAV\PropPatch $propPatch);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a subscription.
|
||||||
|
*
|
||||||
|
* @param mixed $subscriptionId
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function deleteSubscription($subscriptionId);
|
||||||
|
|
||||||
|
}
|
81
vendor/sabre/dav/lib/CalDAV/Backend/SyncSupport.php
vendored
Normal file
81
vendor/sabre/dav/lib/CalDAV/Backend/SyncSupport.php
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Backend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebDAV-sync support for CalDAV backends.
|
||||||
|
*
|
||||||
|
* In order for backends to advertise support for WebDAV-sync, this interface
|
||||||
|
* must be implemented.
|
||||||
|
*
|
||||||
|
* Implementing this can result in a significant reduction of bandwidth and CPU
|
||||||
|
* time.
|
||||||
|
*
|
||||||
|
* For this to work, you _must_ return a {http://sabredav.org/ns}sync-token
|
||||||
|
* property from getCalendarsFromUser.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
interface SyncSupport extends BackendInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The getChanges method returns all the changes that have happened, since
|
||||||
|
* the specified syncToken in the specified calendar.
|
||||||
|
*
|
||||||
|
* This function should return an array, such as the following:
|
||||||
|
*
|
||||||
|
* [
|
||||||
|
* 'syncToken' => 'The current synctoken',
|
||||||
|
* 'added' => [
|
||||||
|
* 'new.txt',
|
||||||
|
* ],
|
||||||
|
* 'modified' => [
|
||||||
|
* 'modified.txt',
|
||||||
|
* ],
|
||||||
|
* 'deleted' => [
|
||||||
|
* 'foo.php.bak',
|
||||||
|
* 'old.txt'
|
||||||
|
* ]
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
* The returned syncToken property should reflect the *current* syncToken
|
||||||
|
* of the calendar, as reported in the {http://sabredav.org/ns}sync-token
|
||||||
|
* property This is * needed here too, to ensure the operation is atomic.
|
||||||
|
*
|
||||||
|
* If the $syncToken argument is specified as null, this is an initial
|
||||||
|
* sync, and all members should be reported.
|
||||||
|
*
|
||||||
|
* The modified property is an array of nodenames that have changed since
|
||||||
|
* the last token.
|
||||||
|
*
|
||||||
|
* The deleted property is an array with nodenames, that have been deleted
|
||||||
|
* from collection.
|
||||||
|
*
|
||||||
|
* The $syncLevel argument is basically the 'depth' of the report. If it's
|
||||||
|
* 1, you only have to report changes that happened only directly in
|
||||||
|
* immediate descendants. If it's 2, it should also include changes from
|
||||||
|
* the nodes below the child collections. (grandchildren)
|
||||||
|
*
|
||||||
|
* The $limit argument allows a client to specify how many results should
|
||||||
|
* be returned at most. If the limit is not specified, it should be treated
|
||||||
|
* as infinite.
|
||||||
|
*
|
||||||
|
* If the limit (infinite or not) is higher than you're willing to return,
|
||||||
|
* you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
|
||||||
|
*
|
||||||
|
* If the syncToken is expired (due to data cleanup) or unknown, you must
|
||||||
|
* return null.
|
||||||
|
*
|
||||||
|
* The limit is 'suggestive'. You are free to ignore it.
|
||||||
|
*
|
||||||
|
* @param string $calendarId
|
||||||
|
* @param string $syncToken
|
||||||
|
* @param int $syncLevel
|
||||||
|
* @param int $limit
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limit = null);
|
||||||
|
|
||||||
|
}
|
527
vendor/sabre/dav/lib/CalDAV/Calendar.php
vendored
Normal file
527
vendor/sabre/dav/lib/CalDAV/Calendar.php
vendored
Normal file
@ -0,0 +1,527 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV;
|
||||||
|
|
||||||
|
use Sabre\DAV;
|
||||||
|
use Sabre\DAVACL;
|
||||||
|
use Sabre\DAV\PropPatch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object represents a CalDAV calendar.
|
||||||
|
*
|
||||||
|
* A calendar can contain multiple TODO and or Events. These are represented
|
||||||
|
* as \Sabre\CalDAV\CalendarObject objects.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class Calendar implements ICalendar, DAV\IProperties, DAV\Sync\ISyncCollection, DAV\IMultiGet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an array with calendar information
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $calendarInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CalDAV backend
|
||||||
|
*
|
||||||
|
* @var Backend\BackendInterface
|
||||||
|
*/
|
||||||
|
protected $caldavBackend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param Backend\BackendInterface $caldavBackend
|
||||||
|
* @param array $calendarInfo
|
||||||
|
*/
|
||||||
|
function __construct(Backend\BackendInterface $caldavBackend, $calendarInfo) {
|
||||||
|
|
||||||
|
$this->caldavBackend = $caldavBackend;
|
||||||
|
$this->calendarInfo = $calendarInfo;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the calendar
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getName() {
|
||||||
|
|
||||||
|
return $this->calendarInfo['uri'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates properties on this node.
|
||||||
|
*
|
||||||
|
* This method received a PropPatch object, which contains all the
|
||||||
|
* information about the update.
|
||||||
|
*
|
||||||
|
* To update specific properties, call the 'handle' method on this object.
|
||||||
|
* Read the PropPatch documentation for more information.
|
||||||
|
*
|
||||||
|
* @param PropPatch $propPatch
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function propPatch(PropPatch $propPatch) {
|
||||||
|
|
||||||
|
return $this->caldavBackend->updateCalendar($this->calendarInfo['id'], $propPatch);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of properties
|
||||||
|
*
|
||||||
|
* @param array $requestedProperties
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getProperties($requestedProperties) {
|
||||||
|
|
||||||
|
$response = [];
|
||||||
|
|
||||||
|
foreach ($this->calendarInfo as $propName => $propValue) {
|
||||||
|
|
||||||
|
if ($propName[0] === '{')
|
||||||
|
$response[$propName] = $this->calendarInfo[$propName];
|
||||||
|
|
||||||
|
}
|
||||||
|
return $response;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a calendar object
|
||||||
|
*
|
||||||
|
* The contained calendar objects are for example Events or Todo's.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return \Sabre\CalDAV\ICalendarObject
|
||||||
|
*/
|
||||||
|
function getChild($name) {
|
||||||
|
|
||||||
|
$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name);
|
||||||
|
|
||||||
|
if (!$obj) throw new DAV\Exception\NotFound('Calendar object not found');
|
||||||
|
|
||||||
|
$obj['acl'] = $this->getChildACL();
|
||||||
|
|
||||||
|
return new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the full list of calendar objects
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getChildren() {
|
||||||
|
|
||||||
|
$objs = $this->caldavBackend->getCalendarObjects($this->calendarInfo['id']);
|
||||||
|
$children = [];
|
||||||
|
foreach ($objs as $obj) {
|
||||||
|
$obj['acl'] = $this->getChildACL();
|
||||||
|
$children[] = new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
|
||||||
|
}
|
||||||
|
return $children;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method receives a list of paths in it's first argument.
|
||||||
|
* It must return an array with Node objects.
|
||||||
|
*
|
||||||
|
* If any children are not found, you do not have to return them.
|
||||||
|
*
|
||||||
|
* @param string[] $paths
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getMultipleChildren(array $paths) {
|
||||||
|
|
||||||
|
$objs = $this->caldavBackend->getMultipleCalendarObjects($this->calendarInfo['id'], $paths);
|
||||||
|
$children = [];
|
||||||
|
foreach ($objs as $obj) {
|
||||||
|
$obj['acl'] = $this->getChildACL();
|
||||||
|
$children[] = new CalendarObject($this->caldavBackend, $this->calendarInfo, $obj);
|
||||||
|
}
|
||||||
|
return $children;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a child-node exists.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function childExists($name) {
|
||||||
|
|
||||||
|
$obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $name);
|
||||||
|
if (!$obj)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new directory
|
||||||
|
*
|
||||||
|
* We actually block this, as subdirectories are not allowed in calendars.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function createDirectory($name) {
|
||||||
|
|
||||||
|
throw new DAV\Exception\MethodNotAllowed('Creating collections in calendar objects is not allowed');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new file
|
||||||
|
*
|
||||||
|
* The contents of the new file must be a valid ICalendar string.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param resource $calendarData
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function createFile($name, $calendarData = null) {
|
||||||
|
|
||||||
|
if (is_resource($calendarData)) {
|
||||||
|
$calendarData = stream_get_contents($calendarData);
|
||||||
|
}
|
||||||
|
return $this->caldavBackend->createCalendarObject($this->calendarInfo['id'], $name, $calendarData);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the calendar.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function delete() {
|
||||||
|
|
||||||
|
$this->caldavBackend->deleteCalendar($this->calendarInfo['id']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renames the calendar. Note that most calendars use the
|
||||||
|
* {DAV:}displayname to display a name to display a name.
|
||||||
|
*
|
||||||
|
* @param string $newName
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function setName($newName) {
|
||||||
|
|
||||||
|
throw new DAV\Exception\MethodNotAllowed('Renaming calendars is not yet supported');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last modification date as a unix timestamp.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function getLastModified() {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the owner principal
|
||||||
|
*
|
||||||
|
* This must be a url to a principal, or null if there's no owner
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getOwner() {
|
||||||
|
|
||||||
|
return $this->calendarInfo['principaluri'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a group principal
|
||||||
|
*
|
||||||
|
* This must be a url to a principal, or null if there's no owner
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getGroup() {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of ACE's for this node.
|
||||||
|
*
|
||||||
|
* Each ACE has the following properties:
|
||||||
|
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
|
||||||
|
* currently the only supported privileges
|
||||||
|
* * 'principal', a url to the principal who owns the node
|
||||||
|
* * 'protected' (optional), indicating that this ACE is not allowed to
|
||||||
|
* be updated.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getACL() {
|
||||||
|
|
||||||
|
$acl = [
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner(),
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-read',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy',
|
||||||
|
'principal' => '{DAV:}authenticated',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
|
if (empty($this->calendarInfo['{http://sabredav.org/ns}read-only'])) {
|
||||||
|
$acl[] = [
|
||||||
|
'privilege' => '{DAV:}write',
|
||||||
|
'principal' => $this->getOwner(),
|
||||||
|
'protected' => true,
|
||||||
|
];
|
||||||
|
$acl[] = [
|
||||||
|
'privilege' => '{DAV:}write',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $acl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the ACL's for calendar objects in this calendar.
|
||||||
|
* The result of this method automatically gets passed to the
|
||||||
|
* calendar-object nodes in the calendar.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getChildACL() {
|
||||||
|
|
||||||
|
$acl = [
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner(),
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-read',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
||||||
|
if (empty($this->calendarInfo['{http://sabredav.org/ns}read-only'])) {
|
||||||
|
$acl[] = [
|
||||||
|
'privilege' => '{DAV:}write',
|
||||||
|
'principal' => $this->getOwner(),
|
||||||
|
'protected' => true,
|
||||||
|
];
|
||||||
|
$acl[] = [
|
||||||
|
'privilege' => '{DAV:}write',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
return $acl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the ACL
|
||||||
|
*
|
||||||
|
* This method will receive a list of new ACE's.
|
||||||
|
*
|
||||||
|
* @param array $acl
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function setACL(array $acl) {
|
||||||
|
|
||||||
|
throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of supported privileges for this node.
|
||||||
|
*
|
||||||
|
* The returned data structure is a list of nested privileges.
|
||||||
|
* See \Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
|
||||||
|
* standard structure.
|
||||||
|
*
|
||||||
|
* If null is returned from this method, the default privilege set is used,
|
||||||
|
* which is fine for most common usecases.
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
function getSupportedPrivilegeSet() {
|
||||||
|
|
||||||
|
$default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
|
||||||
|
|
||||||
|
// We need to inject 'read-free-busy' in the tree, aggregated under
|
||||||
|
// {DAV:}read.
|
||||||
|
foreach ($default['aggregates'] as &$agg) {
|
||||||
|
|
||||||
|
if ($agg['privilege'] !== '{DAV:}read') continue;
|
||||||
|
|
||||||
|
$agg['aggregates'][] = [
|
||||||
|
'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
return $default;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a calendar-query on the contents of this calendar.
|
||||||
|
*
|
||||||
|
* The calendar-query is defined in RFC4791 : CalDAV. Using the
|
||||||
|
* calendar-query it is possible for a client to request a specific set of
|
||||||
|
* object, based on contents of iCalendar properties, date-ranges and
|
||||||
|
* iCalendar component types (VTODO, VEVENT).
|
||||||
|
*
|
||||||
|
* This method should just return a list of (relative) urls that match this
|
||||||
|
* query.
|
||||||
|
*
|
||||||
|
* The list of filters are specified as an array. The exact array is
|
||||||
|
* documented by Sabre\CalDAV\CalendarQueryParser.
|
||||||
|
*
|
||||||
|
* @param array $filters
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function calendarQuery(array $filters) {
|
||||||
|
|
||||||
|
return $this->caldavBackend->calendarQuery($this->calendarInfo['id'], $filters);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the current sync-token for this collection.
|
||||||
|
* This can be any string.
|
||||||
|
*
|
||||||
|
* If null is returned from this function, the plugin assumes there's no
|
||||||
|
* sync information available.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getSyncToken() {
|
||||||
|
|
||||||
|
if (
|
||||||
|
$this->caldavBackend instanceof Backend\SyncSupport &&
|
||||||
|
isset($this->calendarInfo['{DAV:}sync-token'])
|
||||||
|
) {
|
||||||
|
return $this->calendarInfo['{DAV:}sync-token'];
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
$this->caldavBackend instanceof Backend\SyncSupport &&
|
||||||
|
isset($this->calendarInfo['{http://sabredav.org/ns}sync-token'])
|
||||||
|
) {
|
||||||
|
return $this->calendarInfo['{http://sabredav.org/ns}sync-token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The getChanges method returns all the changes that have happened, since
|
||||||
|
* the specified syncToken and the current collection.
|
||||||
|
*
|
||||||
|
* This function should return an array, such as the following:
|
||||||
|
*
|
||||||
|
* [
|
||||||
|
* 'syncToken' => 'The current synctoken',
|
||||||
|
* 'added' => [
|
||||||
|
* 'new.txt',
|
||||||
|
* ],
|
||||||
|
* 'modified' => [
|
||||||
|
* 'modified.txt',
|
||||||
|
* ],
|
||||||
|
* 'deleted' => [
|
||||||
|
* 'foo.php.bak',
|
||||||
|
* 'old.txt'
|
||||||
|
* ]
|
||||||
|
* ];
|
||||||
|
*
|
||||||
|
* The syncToken property should reflect the *current* syncToken of the
|
||||||
|
* collection, as reported getSyncToken(). This is needed here too, to
|
||||||
|
* ensure the operation is atomic.
|
||||||
|
*
|
||||||
|
* If the syncToken is specified as null, this is an initial sync, and all
|
||||||
|
* members should be reported.
|
||||||
|
*
|
||||||
|
* The modified property is an array of nodenames that have changed since
|
||||||
|
* the last token.
|
||||||
|
*
|
||||||
|
* The deleted property is an array with nodenames, that have been deleted
|
||||||
|
* from collection.
|
||||||
|
*
|
||||||
|
* The second argument is basically the 'depth' of the report. If it's 1,
|
||||||
|
* you only have to report changes that happened only directly in immediate
|
||||||
|
* descendants. If it's 2, it should also include changes from the nodes
|
||||||
|
* below the child collections. (grandchildren)
|
||||||
|
*
|
||||||
|
* The third (optional) argument allows a client to specify how many
|
||||||
|
* results should be returned at most. If the limit is not specified, it
|
||||||
|
* should be treated as infinite.
|
||||||
|
*
|
||||||
|
* If the limit (infinite or not) is higher than you're willing to return,
|
||||||
|
* you should throw a Sabre\DAV\Exception\TooMuchMatches() exception.
|
||||||
|
*
|
||||||
|
* If the syncToken is expired (due to data cleanup) or unknown, you must
|
||||||
|
* return null.
|
||||||
|
*
|
||||||
|
* The limit is 'suggestive'. You are free to ignore it.
|
||||||
|
*
|
||||||
|
* @param string $syncToken
|
||||||
|
* @param int $syncLevel
|
||||||
|
* @param int $limit
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getChanges($syncToken, $syncLevel, $limit = null) {
|
||||||
|
|
||||||
|
if (!$this->caldavBackend instanceof Backend\SyncSupport) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->caldavBackend->getChangesForCalendar(
|
||||||
|
$this->calendarInfo['id'],
|
||||||
|
$syncToken,
|
||||||
|
$syncLevel,
|
||||||
|
$limit
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,16 +3,24 @@
|
|||||||
namespace Sabre\CalDAV;
|
namespace Sabre\CalDAV;
|
||||||
|
|
||||||
use Sabre\DAV;
|
use Sabre\DAV;
|
||||||
|
use Sabre\DAV\Exception\NotFound;
|
||||||
|
use Sabre\DAV\MkCol;
|
||||||
use Sabre\DAVACL;
|
use Sabre\DAVACL;
|
||||||
|
use Sabre\HTTP\URLUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The UserCalenders class contains all calendars associated to one user
|
* The CalendarHome represents a node that is usually in a users'
|
||||||
|
* calendar-homeset.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* It contains all the users' calendars, and can optionally contain a
|
||||||
|
* notifications collection, calendar subscriptions, a users' inbox, and a
|
||||||
|
* users' outbox.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
class CalendarHome implements DAV\IExtendedCollection, DAVACL\IACL {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CalDAV backend
|
* CalDAV backend
|
||||||
@ -34,7 +42,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
* @param Backend\BackendInterface $caldavBackend
|
* @param Backend\BackendInterface $caldavBackend
|
||||||
* @param mixed $userUri
|
* @param mixed $userUri
|
||||||
*/
|
*/
|
||||||
public function __construct(Backend\BackendInterface $caldavBackend, $principalInfo) {
|
function __construct(Backend\BackendInterface $caldavBackend, $principalInfo) {
|
||||||
|
|
||||||
$this->caldavBackend = $caldavBackend;
|
$this->caldavBackend = $caldavBackend;
|
||||||
$this->principalInfo = $principalInfo;
|
$this->principalInfo = $principalInfo;
|
||||||
@ -46,9 +54,9 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() {
|
function getName() {
|
||||||
|
|
||||||
list(,$name) = DAV\URLUtil::splitPath($this->principalInfo['uri']);
|
list(, $name) = URLUtil::splitPath($this->principalInfo['uri']);
|
||||||
return $name;
|
return $name;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -59,7 +67,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setName($name) {
|
function setName($name) {
|
||||||
|
|
||||||
throw new DAV\Exception\Forbidden();
|
throw new DAV\Exception\Forbidden();
|
||||||
|
|
||||||
@ -70,7 +78,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function delete() {
|
function delete() {
|
||||||
|
|
||||||
throw new DAV\Exception\Forbidden();
|
throw new DAV\Exception\Forbidden();
|
||||||
|
|
||||||
@ -81,7 +89,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getLastModified() {
|
function getLastModified() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -96,7 +104,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
* @param resource $data
|
* @param resource $data
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function createFile($filename, $data=null) {
|
function createFile($filename, $data = null) {
|
||||||
|
|
||||||
throw new DAV\Exception\MethodNotAllowed('Creating new files in this collection is not supported');
|
throw new DAV\Exception\MethodNotAllowed('Creating new files in this collection is not supported');
|
||||||
|
|
||||||
@ -110,7 +118,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
* @param string $filename
|
* @param string $filename
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function createDirectory($filename) {
|
function createDirectory($filename) {
|
||||||
|
|
||||||
throw new DAV\Exception\MethodNotAllowed('Creating new collections in this collection is not supported');
|
throw new DAV\Exception\MethodNotAllowed('Creating new collections in this collection is not supported');
|
||||||
|
|
||||||
@ -120,17 +128,46 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
* Returns a single calendar, by name
|
* Returns a single calendar, by name
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @todo needs optimizing
|
|
||||||
* @return Calendar
|
* @return Calendar
|
||||||
*/
|
*/
|
||||||
public function getChild($name) {
|
function getChild($name) {
|
||||||
|
|
||||||
foreach($this->getChildren() as $child) {
|
// Special nodes
|
||||||
if ($name==$child->getName())
|
if ($name === 'inbox' && $this->caldavBackend instanceof Backend\SchedulingSupport) {
|
||||||
return $child;
|
return new Schedule\Inbox($this->caldavBackend, $this->principalInfo['uri']);
|
||||||
|
}
|
||||||
|
if ($name === 'outbox' && $this->caldavBackend instanceof Backend\SchedulingSupport) {
|
||||||
|
return new Schedule\Outbox($this->principalInfo['uri']);
|
||||||
|
}
|
||||||
|
if ($name === 'notifications' && $this->caldavBackend instanceof Backend\NotificationSupport) {
|
||||||
|
return new Notifications\Collection($this->caldavBackend, $this->principalInfo['uri']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calendars
|
||||||
|
foreach ($this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']) as $calendar) {
|
||||||
|
if ($calendar['uri'] === $name) {
|
||||||
|
if ($this->caldavBackend instanceof Backend\SharingSupport) {
|
||||||
|
if (isset($calendar['{http://calendarserver.org/ns/}shared-url'])) {
|
||||||
|
return new SharedCalendar($this->caldavBackend, $calendar);
|
||||||
|
} else {
|
||||||
|
return new ShareableCalendar($this->caldavBackend, $calendar);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Calendar($this->caldavBackend, $calendar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->caldavBackend instanceof Backend\SubscriptionSupport) {
|
||||||
|
foreach ($this->caldavBackend->getSubscriptionsForUser($this->principalInfo['uri']) as $subscription) {
|
||||||
|
if ($subscription['uri'] === $name) {
|
||||||
|
return new Subscriptions\Subscription($this->caldavBackend, $subscription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
throw new DAV\Exception\NotFound('Calendar with name \'' . $name . '\' could not be found');
|
|
||||||
|
throw new NotFound('Node with name \'' . $name . '\' could not be found');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,17 +175,15 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
* Checks if a calendar exists.
|
* Checks if a calendar exists.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @todo needs optimizing
|
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function childExists($name) {
|
function childExists($name) {
|
||||||
|
|
||||||
foreach($this->getChildren() as $child) {
|
|
||||||
if ($name==$child->getName())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
return !!$this->getChild($name);
|
||||||
|
} catch (NotFound $e) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,11 +192,11 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getChildren() {
|
function getChildren() {
|
||||||
|
|
||||||
$calendars = $this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']);
|
$calendars = $this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']);
|
||||||
$objs = array();
|
$objs = [];
|
||||||
foreach($calendars as $calendar) {
|
foreach ($calendars as $calendar) {
|
||||||
if ($this->caldavBackend instanceof Backend\SharingSupport) {
|
if ($this->caldavBackend instanceof Backend\SharingSupport) {
|
||||||
if (isset($calendar['{http://calendarserver.org/ns/}shared-url'])) {
|
if (isset($calendar['{http://calendarserver.org/ns/}shared-url'])) {
|
||||||
$objs[] = new SharedCalendar($this->caldavBackend, $calendar);
|
$objs[] = new SharedCalendar($this->caldavBackend, $calendar);
|
||||||
@ -172,28 +207,41 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
$objs[] = new Calendar($this->caldavBackend, $calendar);
|
$objs[] = new Calendar($this->caldavBackend, $calendar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$objs[] = new Schedule\Outbox($this->principalInfo['uri']);
|
|
||||||
|
if ($this->caldavBackend instanceof Backend\SchedulingSupport) {
|
||||||
|
$objs[] = new Schedule\Inbox($this->caldavBackend, $this->principalInfo['uri']);
|
||||||
|
$objs[] = new Schedule\Outbox($this->principalInfo['uri']);
|
||||||
|
}
|
||||||
|
|
||||||
// We're adding a notifications node, if it's supported by the backend.
|
// We're adding a notifications node, if it's supported by the backend.
|
||||||
if ($this->caldavBackend instanceof Backend\NotificationSupport) {
|
if ($this->caldavBackend instanceof Backend\NotificationSupport) {
|
||||||
$objs[] = new Notifications\Collection($this->caldavBackend, $this->principalInfo['uri']);
|
$objs[] = new Notifications\Collection($this->caldavBackend, $this->principalInfo['uri']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the backend supports subscriptions, we'll add those as well,
|
||||||
|
if ($this->caldavBackend instanceof Backend\SubscriptionSupport) {
|
||||||
|
foreach ($this->caldavBackend->getSubscriptionsForUser($this->principalInfo['uri']) as $subscription) {
|
||||||
|
$objs[] = new Subscriptions\Subscription($this->caldavBackend, $subscription);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $objs;
|
return $objs;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new calendar
|
* Creates a new calendar or subscription.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param array $resourceType
|
* @param MkCol $mkCol
|
||||||
* @param array $properties
|
* @throws DAV\Exception\InvalidResourceType
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function createExtendedCollection($name, array $resourceType, array $properties) {
|
function createExtendedCollection($name, MkCol $mkCol) {
|
||||||
|
|
||||||
$isCalendar = false;
|
$isCalendar = false;
|
||||||
foreach($resourceType as $rt) {
|
$isSubscription = false;
|
||||||
|
foreach ($mkCol->getResourceType() as $rt) {
|
||||||
switch ($rt) {
|
switch ($rt) {
|
||||||
case '{DAV:}collection' :
|
case '{DAV:}collection' :
|
||||||
case '{http://calendarserver.org/ns/}shared-owner' :
|
case '{http://calendarserver.org/ns/}shared-owner' :
|
||||||
@ -202,14 +250,30 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
case '{urn:ietf:params:xml:ns:caldav}calendar' :
|
case '{urn:ietf:params:xml:ns:caldav}calendar' :
|
||||||
$isCalendar = true;
|
$isCalendar = true;
|
||||||
break;
|
break;
|
||||||
|
case '{http://calendarserver.org/ns/}subscribed' :
|
||||||
|
$isSubscription = true;
|
||||||
|
break;
|
||||||
default :
|
default :
|
||||||
throw new DAV\Exception\InvalidResourceType('Unknown resourceType: ' . $rt);
|
throw new DAV\Exception\InvalidResourceType('Unknown resourceType: ' . $rt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$isCalendar) {
|
|
||||||
throw new DAV\Exception\InvalidResourceType('You can only create calendars in this collection');
|
$properties = $mkCol->getRemainingValues();
|
||||||
|
$mkCol->setRemainingResultCode(201);
|
||||||
|
|
||||||
|
if ($isSubscription) {
|
||||||
|
if (!$this->caldavBackend instanceof Backend\SubscriptionSupport) {
|
||||||
|
throw new DAV\Exception\InvalidResourceType('This backend does not support subscriptions');
|
||||||
|
}
|
||||||
|
$this->caldavBackend->createSubscription($this->principalInfo['uri'], $name, $properties);
|
||||||
|
|
||||||
|
} elseif ($isCalendar) {
|
||||||
|
$this->caldavBackend->createCalendar($this->principalInfo['uri'], $name, $properties);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new DAV\Exception\InvalidResourceType('You can only create calendars and subscriptions in this collection');
|
||||||
|
|
||||||
}
|
}
|
||||||
$this->caldavBackend->createCalendar($this->principalInfo['uri'], $name, $properties);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +284,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getOwner() {
|
function getOwner() {
|
||||||
|
|
||||||
return $this->principalInfo['uri'];
|
return $this->principalInfo['uri'];
|
||||||
|
|
||||||
@ -233,7 +297,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getGroup() {
|
function getGroup() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -251,36 +315,36 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getACL() {
|
function getACL() {
|
||||||
|
|
||||||
return array(
|
return [
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => $this->principalInfo['uri'],
|
'principal' => $this->principalInfo['uri'],
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}write',
|
'privilege' => '{DAV:}write',
|
||||||
'principal' => $this->principalInfo['uri'],
|
'principal' => $this->principalInfo['uri'],
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => $this->principalInfo['uri'] . '/calendar-proxy-write',
|
'principal' => $this->principalInfo['uri'] . '/calendar-proxy-write',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}write',
|
'privilege' => '{DAV:}write',
|
||||||
'principal' => $this->principalInfo['uri'] . '/calendar-proxy-write',
|
'principal' => $this->principalInfo['uri'] . '/calendar-proxy-write',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => $this->principalInfo['uri'] . '/calendar-proxy-read',
|
'principal' => $this->principalInfo['uri'] . '/calendar-proxy-read',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
|
|
||||||
);
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +356,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
* @param array $acl
|
* @param array $acl
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setACL(array $acl) {
|
function setACL(array $acl) {
|
||||||
|
|
||||||
throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
|
throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
|
||||||
|
|
||||||
@ -310,7 +374,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function getSupportedPrivilegeSet() {
|
function getSupportedPrivilegeSet() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -329,7 +393,7 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
* @param string $summary A description of the reply
|
* @param string $summary A description of the reply
|
||||||
* @return null|string
|
* @return null|string
|
||||||
*/
|
*/
|
||||||
public function shareReply($href, $status, $calendarUri, $inReplyTo, $summary = null) {
|
function shareReply($href, $status, $calendarUri, $inReplyTo, $summary = null) {
|
||||||
|
|
||||||
if (!$this->caldavBackend instanceof Backend\SharingSupport) {
|
if (!$this->caldavBackend instanceof Backend\SharingSupport) {
|
||||||
throw new DAV\Exception\NotImplemented('Sharing support is not implemented by this backend.');
|
throw new DAV\Exception\NotImplemented('Sharing support is not implemented by this backend.');
|
||||||
@ -339,4 +403,28 @@ class UserCalendars implements DAV\IExtendedCollection, DAVACL\IACL {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches through all of a users calendars and calendar objects to find
|
||||||
|
* an object with a specific UID.
|
||||||
|
*
|
||||||
|
* This method should return the path to this object, relative to the
|
||||||
|
* calendar home, so this path usually only contains two parts:
|
||||||
|
*
|
||||||
|
* calendarpath/objectpath.ics
|
||||||
|
*
|
||||||
|
* If the uid is not found, return null.
|
||||||
|
*
|
||||||
|
* This method should only consider * objects that the principal owns, so
|
||||||
|
* any calendars owned by other principals that also appear in this
|
||||||
|
* collection should be ignored.
|
||||||
|
*
|
||||||
|
* @param string $uid
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getCalendarObjectByUID($uid) {
|
||||||
|
|
||||||
|
return $this->caldavBackend->getCalendarObjectByUID($this->principalInfo['uri'], $uid);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ namespace Sabre\CalDAV;
|
|||||||
/**
|
/**
|
||||||
* The CalendarObject represents a single VEVENT or VTODO within a Calendar.
|
* The CalendarObject represents a single VEVENT or VTODO within a Calendar.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -35,17 +35,25 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
|
* The following properties may be passed within $objectData:
|
||||||
|
*
|
||||||
|
* * calendarid - This must refer to a calendarid from a caldavBackend
|
||||||
|
* * uri - A unique uri. Only the 'basename' must be passed.
|
||||||
|
* * calendardata (optional) - The iCalendar data
|
||||||
|
* * etag - (optional) The etag for this object, MUST be encloded with
|
||||||
|
* double-quotes.
|
||||||
|
* * size - (optional) The size of the data in bytes.
|
||||||
|
* * lastmodified - (optional) format as a unix timestamp.
|
||||||
|
* * acl - (optional) Use this to override the default ACL for the node.
|
||||||
|
*
|
||||||
* @param Backend\BackendInterface $caldavBackend
|
* @param Backend\BackendInterface $caldavBackend
|
||||||
* @param array $calendarInfo
|
* @param array $calendarInfo
|
||||||
* @param array $objectData
|
* @param array $objectData
|
||||||
*/
|
*/
|
||||||
public function __construct(Backend\BackendInterface $caldavBackend,array $calendarInfo,array $objectData) {
|
function __construct(Backend\BackendInterface $caldavBackend, array $calendarInfo, array $objectData) {
|
||||||
|
|
||||||
$this->caldavBackend = $caldavBackend;
|
$this->caldavBackend = $caldavBackend;
|
||||||
|
|
||||||
if (!isset($objectData['calendarid'])) {
|
|
||||||
throw new \InvalidArgumentException('The objectData argument must contain a \'calendarid\' property');
|
|
||||||
}
|
|
||||||
if (!isset($objectData['uri'])) {
|
if (!isset($objectData['uri'])) {
|
||||||
throw new \InvalidArgumentException('The objectData argument must contain an \'uri\' property');
|
throw new \InvalidArgumentException('The objectData argument must contain an \'uri\' property');
|
||||||
}
|
}
|
||||||
@ -60,7 +68,7 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() {
|
function getName() {
|
||||||
|
|
||||||
return $this->objectData['uri'];
|
return $this->objectData['uri'];
|
||||||
|
|
||||||
@ -71,12 +79,12 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function get() {
|
function get() {
|
||||||
|
|
||||||
// Pre-populating the 'calendardata' is optional, if we don't have it
|
// Pre-populating the 'calendardata' is optional, if we don't have it
|
||||||
// already we fetch it from the backend.
|
// already we fetch it from the backend.
|
||||||
if (!isset($this->objectData['calendardata'])) {
|
if (!isset($this->objectData['calendardata'])) {
|
||||||
$this->objectData = $this->caldavBackend->getCalendarObject($this->objectData['calendarid'], $this->objectData['uri']);
|
$this->objectData = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'], $this->objectData['uri']);
|
||||||
}
|
}
|
||||||
return $this->objectData['calendardata'];
|
return $this->objectData['calendardata'];
|
||||||
|
|
||||||
@ -88,12 +96,12 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
* @param string|resource $calendarData
|
* @param string|resource $calendarData
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function put($calendarData) {
|
function put($calendarData) {
|
||||||
|
|
||||||
if (is_resource($calendarData)) {
|
if (is_resource($calendarData)) {
|
||||||
$calendarData = stream_get_contents($calendarData);
|
$calendarData = stream_get_contents($calendarData);
|
||||||
}
|
}
|
||||||
$etag = $this->caldavBackend->updateCalendarObject($this->calendarInfo['id'],$this->objectData['uri'],$calendarData);
|
$etag = $this->caldavBackend->updateCalendarObject($this->calendarInfo['id'], $this->objectData['uri'], $calendarData);
|
||||||
$this->objectData['calendardata'] = $calendarData;
|
$this->objectData['calendardata'] = $calendarData;
|
||||||
$this->objectData['etag'] = $etag;
|
$this->objectData['etag'] = $etag;
|
||||||
|
|
||||||
@ -106,9 +114,9 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function delete() {
|
function delete() {
|
||||||
|
|
||||||
$this->caldavBackend->deleteCalendarObject($this->calendarInfo['id'],$this->objectData['uri']);
|
$this->caldavBackend->deleteCalendarObject($this->calendarInfo['id'], $this->objectData['uri']);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,9 +125,13 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getContentType() {
|
function getContentType() {
|
||||||
|
|
||||||
return 'text/calendar; charset=utf-8';
|
$mime = 'text/calendar; charset=utf-8';
|
||||||
|
if (isset($this->objectData['component']) && $this->objectData['component']) {
|
||||||
|
$mime .= '; component=' . $this->objectData['component'];
|
||||||
|
}
|
||||||
|
return $mime;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,12 +142,12 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getETag() {
|
function getETag() {
|
||||||
|
|
||||||
if (isset($this->objectData['etag'])) {
|
if (isset($this->objectData['etag'])) {
|
||||||
return $this->objectData['etag'];
|
return $this->objectData['etag'];
|
||||||
} else {
|
} else {
|
||||||
return '"' . md5($this->get()). '"';
|
return '"' . md5($this->get()) . '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -145,7 +157,7 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getLastModified() {
|
function getLastModified() {
|
||||||
|
|
||||||
return $this->objectData['lastmodified'];
|
return $this->objectData['lastmodified'];
|
||||||
|
|
||||||
@ -156,9 +168,9 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getSize() {
|
function getSize() {
|
||||||
|
|
||||||
if (array_key_exists('size',$this->objectData)) {
|
if (array_key_exists('size', $this->objectData)) {
|
||||||
return $this->objectData['size'];
|
return $this->objectData['size'];
|
||||||
} else {
|
} else {
|
||||||
return strlen($this->get());
|
return strlen($this->get());
|
||||||
@ -173,7 +185,7 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getOwner() {
|
function getOwner() {
|
||||||
|
|
||||||
return $this->calendarInfo['principaluri'];
|
return $this->calendarInfo['principaluri'];
|
||||||
|
|
||||||
@ -186,7 +198,7 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getGroup() {
|
function getGroup() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -204,7 +216,7 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getACL() {
|
function getACL() {
|
||||||
|
|
||||||
// An alternative acl may be specified in the object data.
|
// An alternative acl may be specified in the object data.
|
||||||
if (isset($this->objectData['acl'])) {
|
if (isset($this->objectData['acl'])) {
|
||||||
@ -212,34 +224,34 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The default ACL
|
// The default ACL
|
||||||
return array(
|
return [
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => $this->calendarInfo['principaluri'],
|
'principal' => $this->calendarInfo['principaluri'],
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}write',
|
'privilege' => '{DAV:}write',
|
||||||
'principal' => $this->calendarInfo['principaluri'],
|
'principal' => $this->calendarInfo['principaluri'],
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
|
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}write',
|
'privilege' => '{DAV:}write',
|
||||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
|
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read',
|
'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
|
|
||||||
);
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,7 +263,7 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
* @param array $acl
|
* @param array $acl
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setACL(array $acl) {
|
function setACL(array $acl) {
|
||||||
|
|
||||||
throw new \Sabre\DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
|
throw new \Sabre\DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported');
|
||||||
|
|
||||||
@ -269,11 +281,10 @@ class CalendarObject extends \Sabre\DAV\File implements ICalendarObject, \Sabre\
|
|||||||
*
|
*
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function getSupportedPrivilegeSet() {
|
function getSupportedPrivilegeSet() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +14,7 @@ use DateTime;
|
|||||||
* This is used to determine which icalendar objects should be returned for a
|
* This is used to determine which icalendar objects should be returned for a
|
||||||
* calendar-query REPORT request.
|
* calendar-query REPORT request.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -29,7 +29,7 @@ class CalendarQueryValidator {
|
|||||||
* @param array $filters
|
* @param array $filters
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function validate(VObject\Component $vObject,array $filters) {
|
function validate(VObject\Component\VCalendar $vObject, array $filters) {
|
||||||
|
|
||||||
// The top level object is always a component filter.
|
// The top level object is always a component filter.
|
||||||
// We'll parse it manually, as it's pretty simple.
|
// We'll parse it manually, as it's pretty simple.
|
||||||
@ -57,9 +57,9 @@ class CalendarQueryValidator {
|
|||||||
*/
|
*/
|
||||||
protected function validateCompFilters(VObject\Component $parent, array $filters) {
|
protected function validateCompFilters(VObject\Component $parent, array $filters) {
|
||||||
|
|
||||||
foreach($filters as $filter) {
|
foreach ($filters as $filter) {
|
||||||
|
|
||||||
$isDefined = isset($parent->$filter['name']);
|
$isDefined = isset($parent->{$filter['name']});
|
||||||
|
|
||||||
if ($filter['is-not-defined']) {
|
if ($filter['is-not-defined']) {
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ class CalendarQueryValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($filter['time-range']) {
|
if ($filter['time-range']) {
|
||||||
foreach($parent->$filter['name'] as $subComponent) {
|
foreach ($parent->{$filter['name']} as $subComponent) {
|
||||||
if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) {
|
if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) {
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ class CalendarQueryValidator {
|
|||||||
|
|
||||||
// If there are sub-filters, we need to find at least one component
|
// If there are sub-filters, we need to find at least one component
|
||||||
// for which the subfilters hold true.
|
// for which the subfilters hold true.
|
||||||
foreach($parent->$filter['name'] as $subComponent) {
|
foreach ($parent->{$filter['name']} as $subComponent) {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$this->validateCompFilters($subComponent, $filter['comp-filters']) &&
|
$this->validateCompFilters($subComponent, $filter['comp-filters']) &&
|
||||||
@ -126,9 +126,9 @@ class CalendarQueryValidator {
|
|||||||
*/
|
*/
|
||||||
protected function validatePropFilters(VObject\Component $parent, array $filters) {
|
protected function validatePropFilters(VObject\Component $parent, array $filters) {
|
||||||
|
|
||||||
foreach($filters as $filter) {
|
foreach ($filters as $filter) {
|
||||||
|
|
||||||
$isDefined = isset($parent->$filter['name']);
|
$isDefined = isset($parent->{$filter['name']});
|
||||||
|
|
||||||
if ($filter['is-not-defined']) {
|
if ($filter['is-not-defined']) {
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ class CalendarQueryValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($filter['time-range']) {
|
if ($filter['time-range']) {
|
||||||
foreach($parent->$filter['name'] as $subComponent) {
|
foreach ($parent->{$filter['name']} as $subComponent) {
|
||||||
if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) {
|
if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) {
|
||||||
continue 2;
|
continue 2;
|
||||||
}
|
}
|
||||||
@ -158,9 +158,9 @@ class CalendarQueryValidator {
|
|||||||
|
|
||||||
// If there are sub-filters, we need to find at least one property
|
// If there are sub-filters, we need to find at least one property
|
||||||
// for which the subfilters hold true.
|
// for which the subfilters hold true.
|
||||||
foreach($parent->$filter['name'] as $subComponent) {
|
foreach ($parent->{$filter['name']} as $subComponent) {
|
||||||
|
|
||||||
if(
|
if (
|
||||||
$this->validateParamFilters($subComponent, $filter['param-filters']) &&
|
$this->validateParamFilters($subComponent, $filter['param-filters']) &&
|
||||||
(!$filter['text-match'] || $this->validateTextMatch($subComponent, $filter['text-match']))
|
(!$filter['text-match'] || $this->validateTextMatch($subComponent, $filter['text-match']))
|
||||||
) {
|
) {
|
||||||
@ -196,7 +196,7 @@ class CalendarQueryValidator {
|
|||||||
*/
|
*/
|
||||||
protected function validateParamFilters(VObject\Property $parent, array $filters) {
|
protected function validateParamFilters(VObject\Property $parent, array $filters) {
|
||||||
|
|
||||||
foreach($filters as $filter) {
|
foreach ($filters as $filter) {
|
||||||
|
|
||||||
$isDefined = isset($parent[$filter['name']]);
|
$isDefined = isset($parent[$filter['name']]);
|
||||||
|
|
||||||
@ -217,30 +217,13 @@ class CalendarQueryValidator {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version_compare(VObject\Version::VERSION, '3.0.0beta1', '>=')) {
|
// If there are sub-filters, we need to find at least one parameter
|
||||||
|
// for which the subfilters hold true.
|
||||||
// If there are sub-filters, we need to find at least one parameter
|
foreach ($parent[$filter['name']]->getParts() as $paramPart) {
|
||||||
// for which the subfilters hold true.
|
|
||||||
foreach($parent[$filter['name']]->getParts() as $subParam) {
|
|
||||||
|
|
||||||
if($this->validateTextMatch($subParam,$filter['text-match'])) {
|
|
||||||
// We had a match, so this param-filter succeeds
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// If there are sub-filters, we need to find at least one parameter
|
|
||||||
// for which the subfilters hold true.
|
|
||||||
foreach($parent[$filter['name']] as $subParam) {
|
|
||||||
|
|
||||||
if($this->validateTextMatch($subParam,$filter['text-match'])) {
|
|
||||||
// We had a match, so this param-filter succeeds
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ($this->validateTextMatch($paramPart, $filter['text-match'])) {
|
||||||
|
// We had a match, so this param-filter succeeds
|
||||||
|
continue 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -270,7 +253,7 @@ class CalendarQueryValidator {
|
|||||||
protected function validateTextMatch($check, array $textMatch) {
|
protected function validateTextMatch($check, array $textMatch) {
|
||||||
|
|
||||||
if ($check instanceof VObject\Node) {
|
if ($check instanceof VObject\Node) {
|
||||||
$check = (string)$check;
|
$check = $check->getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
$isMatching = \Sabre\DAV\StringUtil::textMatch($check, $textMatch['value'], $textMatch['collation']);
|
$isMatching = \Sabre\DAV\StringUtil::textMatch($check, $textMatch['value'], $textMatch['collation']);
|
||||||
@ -299,7 +282,7 @@ class CalendarQueryValidator {
|
|||||||
$end = new DateTime('3000-01-01');
|
$end = new DateTime('3000-01-01');
|
||||||
}
|
}
|
||||||
|
|
||||||
switch($component->name) {
|
switch ($component->name) {
|
||||||
|
|
||||||
case 'VEVENT' :
|
case 'VEVENT' :
|
||||||
case 'VTODO' :
|
case 'VTODO' :
|
||||||
@ -318,8 +301,8 @@ class CalendarQueryValidator {
|
|||||||
if ($component->parent->name === 'VEVENT' && $component->parent->RRULE) {
|
if ($component->parent->name === 'VEVENT' && $component->parent->RRULE) {
|
||||||
|
|
||||||
// Fire up the iterator!
|
// Fire up the iterator!
|
||||||
$it = new VObject\RecurrenceIterator($component->parent->parent, (string)$component->parent->UID);
|
$it = new VObject\Recur\EventIterator($component->parent->parent, (string)$component->parent->UID);
|
||||||
while($it->valid()) {
|
while ($it->valid()) {
|
||||||
$expandedEvent = $it->getEventObject();
|
$expandedEvent = $it->getEventObject();
|
||||||
|
|
||||||
// We need to check from these expanded alarms, which
|
// We need to check from these expanded alarms, which
|
||||||
@ -327,7 +310,7 @@ class CalendarQueryValidator {
|
|||||||
// determine if we can 'give up' expanding events.
|
// determine if we can 'give up' expanding events.
|
||||||
$firstAlarm = null;
|
$firstAlarm = null;
|
||||||
if ($expandedEvent->VALARM !== null) {
|
if ($expandedEvent->VALARM !== null) {
|
||||||
foreach($expandedEvent->VALARM as $expandedAlarm) {
|
foreach ($expandedEvent->VALARM as $expandedAlarm) {
|
||||||
|
|
||||||
$effectiveTrigger = $expandedAlarm->getEffectiveTriggerTime();
|
$effectiveTrigger = $expandedAlarm->getEffectiveTriggerTime();
|
||||||
if ($expandedAlarm->isInTimeRange($start, $end)) {
|
if ($expandedAlarm->isInTimeRange($start, $end)) {
|
@ -10,11 +10,14 @@ use Sabre\DAVACL\PrincipalBackend;
|
|||||||
* This object is responsible for generating a list of calendar-homes for each
|
* This object is responsible for generating a list of calendar-homes for each
|
||||||
* user.
|
* user.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* This is the top-most node for the calendars tree. In most servers this class
|
||||||
|
* represents the "/calendars" path.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
class CalendarRootNode extends \Sabre\DAVACL\AbstractPrincipalCollection {
|
class CalendarRoot extends \Sabre\DAVACL\AbstractPrincipalCollection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CalDAV backend
|
* CalDAV backend
|
||||||
@ -37,7 +40,7 @@ class CalendarRootNode extends \Sabre\DAVACL\AbstractPrincipalCollection {
|
|||||||
* @param Backend\BackendInterface $caldavBackend
|
* @param Backend\BackendInterface $caldavBackend
|
||||||
* @param string $principalPrefix
|
* @param string $principalPrefix
|
||||||
*/
|
*/
|
||||||
public function __construct(PrincipalBackend\BackendInterface $principalBackend,Backend\BackendInterface $caldavBackend, $principalPrefix = 'principals') {
|
function __construct(PrincipalBackend\BackendInterface $principalBackend, Backend\BackendInterface $caldavBackend, $principalPrefix = 'principals') {
|
||||||
|
|
||||||
parent::__construct($principalBackend, $principalPrefix);
|
parent::__construct($principalBackend, $principalPrefix);
|
||||||
$this->caldavBackend = $caldavBackend;
|
$this->caldavBackend = $caldavBackend;
|
||||||
@ -52,7 +55,7 @@ class CalendarRootNode extends \Sabre\DAVACL\AbstractPrincipalCollection {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() {
|
function getName() {
|
||||||
|
|
||||||
return Plugin::CALENDAR_ROOT;
|
return Plugin::CALENDAR_ROOT;
|
||||||
|
|
||||||
@ -68,9 +71,9 @@ class CalendarRootNode extends \Sabre\DAVACL\AbstractPrincipalCollection {
|
|||||||
* @param array $principal
|
* @param array $principal
|
||||||
* @return \Sabre\DAV\INode
|
* @return \Sabre\DAV\INode
|
||||||
*/
|
*/
|
||||||
public function getChildForPrincipal(array $principal) {
|
function getChildForPrincipal(array $principal) {
|
||||||
|
|
||||||
return new UserCalendars($this->caldavBackend, $principal);
|
return new CalendarHome($this->caldavBackend, $principal);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ use Sabre\CalDAV;
|
|||||||
/**
|
/**
|
||||||
* InvalidComponentType
|
* InvalidComponentType
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -23,11 +23,11 @@ class InvalidComponentType extends DAV\Exception\Forbidden {
|
|||||||
* @param \DOMElement $errorNode
|
* @param \DOMElement $errorNode
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function serialize(DAV\Server $server, \DOMElement $errorNode) {
|
function serialize(DAV\Server $server, \DOMElement $errorNode) {
|
||||||
|
|
||||||
$doc = $errorNode->ownerDocument;
|
$doc = $errorNode->ownerDocument;
|
||||||
|
|
||||||
$np = $doc->createElementNS(CalDAV\Plugin::NS_CALDAV,'cal:supported-calendar-component');
|
$np = $doc->createElementNS(CalDAV\Plugin::NS_CALDAV, 'cal:supported-calendar-component');
|
||||||
$errorNode->appendChild($np);
|
$errorNode->appendChild($np);
|
||||||
|
|
||||||
}
|
}
|
366
vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php
vendored
Normal file
366
vendor/sabre/dav/lib/CalDAV/ICSExportPlugin.php
vendored
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV;
|
||||||
|
|
||||||
|
use DateTimeZone;
|
||||||
|
use Sabre\DAV;
|
||||||
|
use Sabre\VObject;
|
||||||
|
use Sabre\HTTP\RequestInterface;
|
||||||
|
use Sabre\HTTP\ResponseInterface;
|
||||||
|
use Sabre\DAV\Exception\BadRequest;
|
||||||
|
use DateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ICS Exporter
|
||||||
|
*
|
||||||
|
* This plugin adds the ability to export entire calendars as .ics files.
|
||||||
|
* This is useful for clients that don't support CalDAV yet. They often do
|
||||||
|
* support ics files.
|
||||||
|
*
|
||||||
|
* To use this, point a http client to a caldav calendar, and add ?expand to
|
||||||
|
* the url.
|
||||||
|
*
|
||||||
|
* Further options that can be added to the url:
|
||||||
|
* start=123456789 - Only return events after the given unix timestamp
|
||||||
|
* end=123245679 - Only return events from before the given unix timestamp
|
||||||
|
* expand=1 - Strip timezone information and expand recurring events.
|
||||||
|
* If you'd like to expand, you _must_ also specify start
|
||||||
|
* and end.
|
||||||
|
*
|
||||||
|
* By default this plugin returns data in the text/calendar format (iCalendar
|
||||||
|
* 2.0). If you'd like to receive jCal data instead, you can use an Accept
|
||||||
|
* header:
|
||||||
|
*
|
||||||
|
* Accept: application/calendar+json
|
||||||
|
*
|
||||||
|
* Alternatively, you can also specify this in the url using
|
||||||
|
* accept=application/calendar+json, or accept=jcal for short. If the url
|
||||||
|
* parameter and Accept header is specified, the url parameter wins.
|
||||||
|
*
|
||||||
|
* Note that specifying a start or end data implies that only events will be
|
||||||
|
* returned. VTODO and VJOURNAL will be stripped.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class ICSExportPlugin extends DAV\ServerPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to Server class
|
||||||
|
*
|
||||||
|
* @var \Sabre\DAV\Server
|
||||||
|
*/
|
||||||
|
protected $server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the plugin and registers event handlers
|
||||||
|
*
|
||||||
|
* @param \Sabre\DAV\Server $server
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function initialize(DAV\Server $server) {
|
||||||
|
|
||||||
|
$this->server = $server;
|
||||||
|
$server->on('method:GET', [$this, 'httpGet'], 90);
|
||||||
|
$server->on('browserButtonActions', function($path, $node, &$actions) {
|
||||||
|
if ($node instanceof ICalendar) {
|
||||||
|
$actions .= '<a href="' . htmlspecialchars($path, ENT_QUOTES, 'UTF-8') . '?export"><span class="oi" data-glyph="calendar"></span></a>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intercepts GET requests on calendar urls ending with ?export.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function httpGet(RequestInterface $request, ResponseInterface $response) {
|
||||||
|
|
||||||
|
$queryParams = $request->getQueryParameters();
|
||||||
|
if (!array_key_exists('export', $queryParams)) return;
|
||||||
|
|
||||||
|
$path = $request->getPath();
|
||||||
|
|
||||||
|
$node = $this->server->getProperties($path, [
|
||||||
|
'{DAV:}resourcetype',
|
||||||
|
'{DAV:}displayname',
|
||||||
|
'{http://sabredav.org/ns}sync-token',
|
||||||
|
'{DAV:}sync-token',
|
||||||
|
'{http://apple.com/ns/ical/}calendar-color',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!isset($node['{DAV:}resourcetype']) || !$node['{DAV:}resourcetype']->is('{' . Plugin::NS_CALDAV . '}calendar')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Marking the transactionType, for logging purposes.
|
||||||
|
$this->server->transactionType = 'get-calendar-export';
|
||||||
|
|
||||||
|
$properties = $node;
|
||||||
|
|
||||||
|
$start = null;
|
||||||
|
$end = null;
|
||||||
|
$expand = false;
|
||||||
|
$componentType = false;
|
||||||
|
if (isset($queryParams['start'])) {
|
||||||
|
if (!ctype_digit($queryParams['start'])) {
|
||||||
|
throw new BadRequest('The start= parameter must contain a unix timestamp');
|
||||||
|
}
|
||||||
|
$start = DateTime::createFromFormat('U', $queryParams['start']);
|
||||||
|
}
|
||||||
|
if (isset($queryParams['end'])) {
|
||||||
|
if (!ctype_digit($queryParams['end'])) {
|
||||||
|
throw new BadRequest('The end= parameter must contain a unix timestamp');
|
||||||
|
}
|
||||||
|
$end = DateTime::createFromFormat('U', $queryParams['end']);
|
||||||
|
}
|
||||||
|
if (isset($queryParams['expand']) && !!$queryParams['expand']) {
|
||||||
|
if (!$start || !$end) {
|
||||||
|
throw new BadRequest('If you\'d like to expand recurrences, you must specify both a start= and end= parameter.');
|
||||||
|
}
|
||||||
|
$expand = true;
|
||||||
|
$componentType = 'VEVENT';
|
||||||
|
}
|
||||||
|
if (isset($queryParams['componentType'])) {
|
||||||
|
if (!in_array($queryParams['componentType'], ['VEVENT', 'VTODO', 'VJOURNAL'])) {
|
||||||
|
throw new BadRequest('You are not allowed to search for components of type: ' . $queryParams['componentType'] . ' here');
|
||||||
|
}
|
||||||
|
$componentType = $queryParams['componentType'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$format = \Sabre\HTTP\Util::Negotiate(
|
||||||
|
$request->getHeader('Accept'),
|
||||||
|
[
|
||||||
|
'text/calendar',
|
||||||
|
'application/calendar+json',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($queryParams['accept'])) {
|
||||||
|
if ($queryParams['accept'] === 'application/calendar+json' || $queryParams['accept'] === 'jcal') {
|
||||||
|
$format = 'application/calendar+json';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$format) {
|
||||||
|
$format = 'text/calendar';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->generateResponse($path, $start, $end, $expand, $componentType, $format, $properties, $response);
|
||||||
|
|
||||||
|
// Returning false to break the event chain
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is responsible for generating the actual, full response.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param DateTime|null $start
|
||||||
|
* @param DateTime|null $end
|
||||||
|
* @param bool $expand
|
||||||
|
* @param string $componentType
|
||||||
|
* @param string $format
|
||||||
|
* @param array $properties
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
*/
|
||||||
|
protected function generateResponse($path, $start, $end, $expand, $componentType, $format, $properties, ResponseInterface $response) {
|
||||||
|
|
||||||
|
$calDataProp = '{' . Plugin::NS_CALDAV . '}calendar-data';
|
||||||
|
|
||||||
|
$blobs = [];
|
||||||
|
if ($start || $end || $componentType) {
|
||||||
|
|
||||||
|
// If there was a start or end filter, we need to enlist
|
||||||
|
// calendarQuery for speed.
|
||||||
|
$calendarNode = $this->server->tree->getNodeForPath($path);
|
||||||
|
$queryResult = $calendarNode->calendarQuery([
|
||||||
|
'name' => 'VCALENDAR',
|
||||||
|
'comp-filters' => [
|
||||||
|
[
|
||||||
|
'name' => $componentType,
|
||||||
|
'comp-filters' => [],
|
||||||
|
'prop-filters' => [],
|
||||||
|
'is-not-defined' => false,
|
||||||
|
'time-range' => [
|
||||||
|
'start' => $start,
|
||||||
|
'end' => $end,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'prop-filters' => [],
|
||||||
|
'is-not-defined' => false,
|
||||||
|
'time-range' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// queryResult is just a list of base urls. We need to prefix the
|
||||||
|
// calendar path.
|
||||||
|
$queryResult = array_map(
|
||||||
|
function($item) use ($path) {
|
||||||
|
return $path . '/' . $item;
|
||||||
|
},
|
||||||
|
$queryResult
|
||||||
|
);
|
||||||
|
$nodes = $this->server->getPropertiesForMultiplePaths($queryResult, [$calDataProp]);
|
||||||
|
unset($queryResult);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$nodes = $this->server->getPropertiesForPath($path, [$calDataProp], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flattening the arrays
|
||||||
|
foreach ($nodes as $node) {
|
||||||
|
if (isset($node[200][$calDataProp])) {
|
||||||
|
$blobs[$node['href']] = $node[200][$calDataProp];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($nodes);
|
||||||
|
|
||||||
|
$mergedCalendar = $this->mergeObjects(
|
||||||
|
$properties,
|
||||||
|
$blobs
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($expand) {
|
||||||
|
$calendarTimeZone = null;
|
||||||
|
// We're expanding, and for that we need to figure out the
|
||||||
|
// calendar's timezone.
|
||||||
|
$tzProp = '{' . Plugin::NS_CALDAV . '}calendar-timezone';
|
||||||
|
$tzResult = $this->server->getProperties($path, [$tzProp]);
|
||||||
|
if (isset($tzResult[$tzProp])) {
|
||||||
|
// This property contains a VCALENDAR with a single
|
||||||
|
// VTIMEZONE.
|
||||||
|
$vtimezoneObj = VObject\Reader::read($tzResult[$tzProp]);
|
||||||
|
$calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
|
||||||
|
// Destroy circular references to PHP will GC the object.
|
||||||
|
$vtimezoneObj->destroy();
|
||||||
|
unset($vtimezoneObj);
|
||||||
|
} else {
|
||||||
|
// Defaulting to UTC.
|
||||||
|
$calendarTimeZone = new DateTimeZone('UTC');
|
||||||
|
}
|
||||||
|
|
||||||
|
$mergedCalendar = $mergedCalendar->expand($start, $end, $calendarTimeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->setHeader('Content-Type', $format);
|
||||||
|
|
||||||
|
switch ($format) {
|
||||||
|
case 'text/calendar' :
|
||||||
|
$mergedCalendar = $mergedCalendar->serialize();
|
||||||
|
break;
|
||||||
|
case 'application/calendar+json' :
|
||||||
|
$mergedCalendar = json_encode($mergedCalendar->jsonSerialize());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->setStatus(200);
|
||||||
|
$response->setBody($mergedCalendar);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges all calendar objects, and builds one big iCalendar blob.
|
||||||
|
*
|
||||||
|
* @param array $properties Some CalDAV properties
|
||||||
|
* @param array $inputObjects
|
||||||
|
* @return VObject\Component\VCalendar
|
||||||
|
*/
|
||||||
|
function mergeObjects(array $properties, array $inputObjects) {
|
||||||
|
|
||||||
|
$calendar = new VObject\Component\VCalendar();
|
||||||
|
$calendar->version = '2.0';
|
||||||
|
if (DAV\Server::$exposeVersion) {
|
||||||
|
$calendar->prodid = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN';
|
||||||
|
} else {
|
||||||
|
$calendar->prodid = '-//SabreDAV//SabreDAV//EN';
|
||||||
|
}
|
||||||
|
if (isset($properties['{DAV:}displayname'])) {
|
||||||
|
$calendar->{'X-WR-CALNAME'} = $properties['{DAV:}displayname'];
|
||||||
|
}
|
||||||
|
if (isset($properties['{http://apple.com/ns/ical/}calendar-color'])) {
|
||||||
|
$calendar->{'X-APPLE-CALENDAR-COLOR'} = $properties['{http://apple.com/ns/ical/}calendar-color'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$collectedTimezones = [];
|
||||||
|
|
||||||
|
$timezones = [];
|
||||||
|
$objects = [];
|
||||||
|
|
||||||
|
foreach ($inputObjects as $href => $inputObject) {
|
||||||
|
|
||||||
|
$nodeComp = VObject\Reader::read($inputObject);
|
||||||
|
|
||||||
|
foreach ($nodeComp->children() as $child) {
|
||||||
|
|
||||||
|
switch ($child->name) {
|
||||||
|
case 'VEVENT' :
|
||||||
|
case 'VTODO' :
|
||||||
|
case 'VJOURNAL' :
|
||||||
|
$objects[] = clone $child;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// VTIMEZONE is special, because we need to filter out the duplicates
|
||||||
|
case 'VTIMEZONE' :
|
||||||
|
// Naively just checking tzid.
|
||||||
|
if (in_array((string)$child->TZID, $collectedTimezones)) continue;
|
||||||
|
|
||||||
|
$timezones[] = clone $child;
|
||||||
|
$collectedTimezones[] = $child->TZID;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// Destroy circular references to PHP will GC the object.
|
||||||
|
$nodeComp->destroy();
|
||||||
|
unset($nodeComp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($timezones as $tz) $calendar->add($tz);
|
||||||
|
foreach ($objects as $obj) $calendar->add($obj);
|
||||||
|
|
||||||
|
return $calendar;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a plugin name.
|
||||||
|
*
|
||||||
|
* Using this name other plugins will be able to access other plugins
|
||||||
|
* using \Sabre\DAV\Server::getPlugin
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getPluginName() {
|
||||||
|
|
||||||
|
return 'ics-export';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bunch of meta-data about the plugin.
|
||||||
|
*
|
||||||
|
* Providing this information is optional, and is mainly displayed by the
|
||||||
|
* Browser plugin.
|
||||||
|
*
|
||||||
|
* The description key in the returned array may contain html and will not
|
||||||
|
* be sanitized.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getPluginInfo() {
|
||||||
|
|
||||||
|
return [
|
||||||
|
'name' => $this->getPluginName(),
|
||||||
|
'description' => 'Adds the ability to export CalDAV calendars as a single iCalendar file.',
|
||||||
|
'link' => 'http://sabre.io/dav/ics-export-plugin/',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
18
vendor/sabre/dav/lib/CalDAV/ICalendar.php
vendored
Normal file
18
vendor/sabre/dav/lib/CalDAV/ICalendar.php
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV;
|
||||||
|
|
||||||
|
use Sabre\DAVACL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calendar interface
|
||||||
|
*
|
||||||
|
* Implement this interface to allow a node to be recognized as an calendar.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
interface ICalendar extends ICalendarObjectContainer, DAVACL\IACL {
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Sabre\CalDAV;
|
namespace Sabre\CalDAV;
|
||||||
|
|
||||||
use Sabre\DAV;
|
use Sabre\DAV;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,11 +12,10 @@ use Sabre\DAV;
|
|||||||
*
|
*
|
||||||
* Calendar objects are resources such as Events, Todo's or Journals.
|
* Calendar objects are resources such as Events, Todo's or Journals.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
interface ICalendarObject extends DAV\IFile {
|
interface ICalendarObject extends DAV\IFile {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,18 +1,21 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Sabre\CalDAV;
|
namespace Sabre\CalDAV;
|
||||||
use Sabre\DAV;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calendar interface
|
* This interface represents a node that may contain calendar objects.
|
||||||
*
|
*
|
||||||
* Implement this interface to allow a node to be recognized as an calendar.
|
* This is the shared parent for both the Inbox collection and calendars
|
||||||
|
* resources.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* In most cases you will likely want to look at ICalendar instead of this
|
||||||
|
* interface.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
interface ICalendar extends DAV\ICollection {
|
interface ICalendarObjectContainer extends \Sabre\DAV\ICollection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a calendar-query on the contents of this calendar.
|
* Performs a calendar-query on the contents of this calendar.
|
||||||
@ -31,6 +34,6 @@ interface ICalendar extends DAV\ICollection {
|
|||||||
* @param array $filters
|
* @param array $filters
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function calendarQuery(array $filters);
|
function calendarQuery(array $filters);
|
||||||
|
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ namespace Sabre\CalDAV;
|
|||||||
/**
|
/**
|
||||||
* This interface represents a Calendar that can be shared with other users.
|
* This interface represents a Calendar that can be shared with other users.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
@ -5,7 +5,7 @@ namespace Sabre\CalDAV;
|
|||||||
/**
|
/**
|
||||||
* This interface represents a Calendar that is shared by a different user.
|
* This interface represents a Calendar that is shared by a different user.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
@ -16,7 +16,7 @@ use Sabre\DAVACL;
|
|||||||
* This collection should only return Sabre\CalDAV\Notifications\INode nodes as
|
* This collection should only return Sabre\CalDAV\Notifications\INode nodes as
|
||||||
* its children.
|
* its children.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -42,7 +42,7 @@ class Collection extends DAV\Collection implements ICollection, DAVACL\IACL {
|
|||||||
* @param CalDAV\Backend\NotificationSupport $caldavBackend
|
* @param CalDAV\Backend\NotificationSupport $caldavBackend
|
||||||
* @param string $principalUri
|
* @param string $principalUri
|
||||||
*/
|
*/
|
||||||
public function __construct(CalDAV\Backend\NotificationSupport $caldavBackend, $principalUri) {
|
function __construct(CalDAV\Backend\NotificationSupport $caldavBackend, $principalUri) {
|
||||||
|
|
||||||
$this->caldavBackend = $caldavBackend;
|
$this->caldavBackend = $caldavBackend;
|
||||||
$this->principalUri = $principalUri;
|
$this->principalUri = $principalUri;
|
||||||
@ -54,12 +54,12 @@ class Collection extends DAV\Collection implements ICollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getChildren() {
|
function getChildren() {
|
||||||
|
|
||||||
$children = array();
|
$children = [];
|
||||||
$notifications = $this->caldavBackend->getNotificationsForPrincipal($this->principalUri);
|
$notifications = $this->caldavBackend->getNotificationsForPrincipal($this->principalUri);
|
||||||
|
|
||||||
foreach($notifications as $notification) {
|
foreach ($notifications as $notification) {
|
||||||
|
|
||||||
$children[] = new Node(
|
$children[] = new Node(
|
||||||
$this->caldavBackend,
|
$this->caldavBackend,
|
||||||
@ -77,7 +77,7 @@ class Collection extends DAV\Collection implements ICollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() {
|
function getName() {
|
||||||
|
|
||||||
return 'notifications';
|
return 'notifications';
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ class Collection extends DAV\Collection implements ICollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getOwner() {
|
function getOwner() {
|
||||||
|
|
||||||
return $this->principalUri;
|
return $this->principalUri;
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ class Collection extends DAV\Collection implements ICollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getGroup() {
|
function getGroup() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -121,20 +121,20 @@ class Collection extends DAV\Collection implements ICollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getACL() {
|
function getACL() {
|
||||||
|
|
||||||
return array(
|
return [
|
||||||
array(
|
[
|
||||||
'principal' => $this->getOwner(),
|
'principal' => $this->getOwner(),
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'principal' => $this->getOwner(),
|
'principal' => $this->getOwner(),
|
||||||
'privilege' => '{DAV:}write',
|
'privilege' => '{DAV:}write',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
)
|
]
|
||||||
);
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ class Collection extends DAV\Collection implements ICollection, DAVACL\IACL {
|
|||||||
* @param array $acl
|
* @param array $acl
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setACL(array $acl) {
|
function setACL(array $acl) {
|
||||||
|
|
||||||
throw new DAV\Exception\NotImplemented('Updating ACLs is not implemented here');
|
throw new DAV\Exception\NotImplemented('Updating ACLs is not implemented here');
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ class Collection extends DAV\Collection implements ICollection, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function getSupportedPrivilegeSet() {
|
function getSupportedPrivilegeSet() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -14,11 +14,10 @@ use Sabre\DAV;
|
|||||||
* This collection should only return Sabre\CalDAV\Notifications\INode nodes as
|
* This collection should only return Sabre\CalDAV\Notifications\INode nodes as
|
||||||
* its children.
|
* its children.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
interface ICollection extends DAV\ICollection {
|
interface ICollection extends DAV\ICollection {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -12,7 +12,7 @@ namespace Sabre\CalDAV\Notifications;
|
|||||||
* For a complete example, check out the Notification class, which contains
|
* For a complete example, check out the Notification class, which contains
|
||||||
* some helper functions.
|
* some helper functions.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
@ -4,6 +4,7 @@ namespace Sabre\CalDAV\Notifications;
|
|||||||
|
|
||||||
use Sabre\DAV;
|
use Sabre\DAV;
|
||||||
use Sabre\CalDAV;
|
use Sabre\CalDAV;
|
||||||
|
use Sabre\CalDAV\Xml\Notification\NotificationInterface;
|
||||||
use Sabre\DAVACL;
|
use Sabre\DAVACL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,8 +13,8 @@ use Sabre\DAVACL;
|
|||||||
* The signature is mostly identical to that of Sabre\DAV\IFile, but the get() method
|
* The signature is mostly identical to that of Sabre\DAV\IFile, but the get() method
|
||||||
* MUST return an xml document that matches the requirements of the
|
* MUST return an xml document that matches the requirements of the
|
||||||
* 'caldav-notifications.txt' spec.
|
* 'caldav-notifications.txt' spec.
|
||||||
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -45,9 +46,9 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @param CalDAV\Backend\NotificationSupport $caldavBackend
|
* @param CalDAV\Backend\NotificationSupport $caldavBackend
|
||||||
* @param string $principalUri
|
* @param string $principalUri
|
||||||
* @param CalDAV\Notifications\INotificationType $notification
|
* @param NotificationInterface $notification
|
||||||
*/
|
*/
|
||||||
public function __construct(CalDAV\Backend\NotificationSupport $caldavBackend, $principalUri, INotificationType $notification) {
|
function __construct(CalDAV\Backend\NotificationSupport $caldavBackend, $principalUri, NotificationInterface $notification) {
|
||||||
|
|
||||||
$this->caldavBackend = $caldavBackend;
|
$this->caldavBackend = $caldavBackend;
|
||||||
$this->principalUri = $principalUri;
|
$this->principalUri = $principalUri;
|
||||||
@ -60,7 +61,7 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return id
|
* @return id
|
||||||
*/
|
*/
|
||||||
public function getName() {
|
function getName() {
|
||||||
|
|
||||||
return $this->notification->getId() . '.xml';
|
return $this->notification->getId() . '.xml';
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getETag() {
|
function getETag() {
|
||||||
|
|
||||||
return $this->notification->getETag();
|
return $this->notification->getETag();
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return INotificationType
|
* @return INotificationType
|
||||||
*/
|
*/
|
||||||
public function getNotificationType() {
|
function getNotificationType() {
|
||||||
|
|
||||||
return $this->notification;
|
return $this->notification;
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function delete() {
|
function delete() {
|
||||||
|
|
||||||
$this->caldavBackend->deleteNotification($this->getOwner(), $this->notification);
|
$this->caldavBackend->deleteNotification($this->getOwner(), $this->notification);
|
||||||
|
|
||||||
@ -109,7 +110,7 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getOwner() {
|
function getOwner() {
|
||||||
|
|
||||||
return $this->principalUri;
|
return $this->principalUri;
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getGroup() {
|
function getGroup() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -140,20 +141,20 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getACL() {
|
function getACL() {
|
||||||
|
|
||||||
return array(
|
return [
|
||||||
array(
|
[
|
||||||
'principal' => $this->getOwner(),
|
'principal' => $this->getOwner(),
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'principal' => $this->getOwner(),
|
'principal' => $this->getOwner(),
|
||||||
'privilege' => '{DAV:}write',
|
'privilege' => '{DAV:}write',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
)
|
]
|
||||||
);
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +166,7 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
|
|||||||
* @param array $acl
|
* @param array $acl
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setACL(array $acl) {
|
function setACL(array $acl) {
|
||||||
|
|
||||||
throw new DAV\Exception\NotImplemented('Updating ACLs is not implemented here');
|
throw new DAV\Exception\NotImplemented('Updating ACLs is not implemented here');
|
||||||
|
|
||||||
@ -183,7 +184,7 @@ class Node extends DAV\File implements INode, DAVACL\IACL {
|
|||||||
*
|
*
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function getSupportedPrivilegeSet() {
|
function getSupportedPrivilegeSet() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
180
vendor/sabre/dav/lib/CalDAV/Notifications/Plugin.php
vendored
Normal file
180
vendor/sabre/dav/lib/CalDAV/Notifications/Plugin.php
vendored
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Notifications;
|
||||||
|
|
||||||
|
use Sabre\DAV;
|
||||||
|
use Sabre\DAV\PropFind;
|
||||||
|
use Sabre\DAV\INode as BaseINode;
|
||||||
|
use Sabre\DAV\ServerPlugin;
|
||||||
|
use Sabre\DAV\Server;
|
||||||
|
use Sabre\DAVACL;
|
||||||
|
use Sabre\HTTP\RequestInterface;
|
||||||
|
use Sabre\HTTP\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifications plugin
|
||||||
|
*
|
||||||
|
* This plugin implements several features required by the caldav-notification
|
||||||
|
* draft specification.
|
||||||
|
*
|
||||||
|
* Before version 2.1.0 this functionality was part of Sabre\CalDAV\Plugin but
|
||||||
|
* this has since been split up.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class Plugin extends ServerPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the namespace for the proprietary calendarserver extensions
|
||||||
|
*/
|
||||||
|
const NS_CALENDARSERVER = 'http://calendarserver.org/ns/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to the main server object.
|
||||||
|
*
|
||||||
|
* @var Server
|
||||||
|
*/
|
||||||
|
protected $server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a plugin name.
|
||||||
|
*
|
||||||
|
* Using this name other plugins will be able to access other plugins
|
||||||
|
* using \Sabre\DAV\Server::getPlugin
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getPluginName() {
|
||||||
|
|
||||||
|
return 'notifications';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This initializes the plugin.
|
||||||
|
*
|
||||||
|
* This function is called by Sabre\DAV\Server, after
|
||||||
|
* addPlugin is called.
|
||||||
|
*
|
||||||
|
* This method should set up the required event subscriptions.
|
||||||
|
*
|
||||||
|
* @param Server $server
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function initialize(Server $server) {
|
||||||
|
|
||||||
|
$this->server = $server;
|
||||||
|
$server->on('method:GET', [$this, 'httpGet'], 90);
|
||||||
|
$server->on('propFind', [$this, 'propFind']);
|
||||||
|
|
||||||
|
$server->xml->namespaceMap[self::NS_CALENDARSERVER] = 'cs';
|
||||||
|
$server->resourceTypeMapping['\\Sabre\\CalDAV\\Notifications\\ICollection'] = '{' . self::NS_CALENDARSERVER . '}notification';
|
||||||
|
|
||||||
|
array_push($server->protectedProperties,
|
||||||
|
'{' . self::NS_CALENDARSERVER . '}notification-URL',
|
||||||
|
'{' . self::NS_CALENDARSERVER . '}notificationtype'
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PropFind
|
||||||
|
*
|
||||||
|
* @param PropFind $propFind
|
||||||
|
* @param BaseINode $node
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function propFind(PropFind $propFind, BaseINode $node) {
|
||||||
|
|
||||||
|
$caldavPlugin = $this->server->getPlugin('caldav');
|
||||||
|
|
||||||
|
if ($node instanceof DAVACL\IPrincipal) {
|
||||||
|
|
||||||
|
$principalUrl = $node->getPrincipalUrl();
|
||||||
|
|
||||||
|
// notification-URL property
|
||||||
|
$propFind->handle('{' . self::NS_CALENDARSERVER . '}notification-URL', function() use ($principalUrl, $caldavPlugin) {
|
||||||
|
|
||||||
|
$notificationPath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl) . '/notifications/';
|
||||||
|
return new DAV\Xml\Property\Href($notificationPath);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node instanceof INode) {
|
||||||
|
|
||||||
|
$propFind->handle(
|
||||||
|
'{' . self::NS_CALENDARSERVER . '}notificationtype',
|
||||||
|
[$node, 'getNotificationType']
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event is triggered before the usual GET request handler.
|
||||||
|
*
|
||||||
|
* We use this to intercept GET calls to notification nodes, and return the
|
||||||
|
* proper response.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function httpGet(RequestInterface $request, ResponseInterface $response) {
|
||||||
|
|
||||||
|
$path = $request->getPath();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$node = $this->server->tree->getNodeForPath($path);
|
||||||
|
} catch (DAV\Exception\NotFound $e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$node instanceof INode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
$writer = $this->server->xml->getWriter();
|
||||||
|
$writer->contextUri = $this->server->getBaseUri();
|
||||||
|
$writer->openMemory();
|
||||||
|
$writer->startDocument('1.0', 'UTF-8');
|
||||||
|
$writer->startElement('{http://calendarserver.org/ns/}notification');
|
||||||
|
$node->getNotificationType()->xmlSerializeFull($writer);
|
||||||
|
$writer->endElement();
|
||||||
|
|
||||||
|
$response->setHeader('Content-Type', 'application/xml');
|
||||||
|
$response->setHeader('ETag', $node->getETag());
|
||||||
|
$response->setStatus(200);
|
||||||
|
$response->setBody($writer->outputMemory());
|
||||||
|
|
||||||
|
// Return false to break the event chain.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bunch of meta-data about the plugin.
|
||||||
|
*
|
||||||
|
* Providing this information is optional, and is mainly displayed by the
|
||||||
|
* Browser plugin.
|
||||||
|
*
|
||||||
|
* The description key in the returned array may contain html and will not
|
||||||
|
* be sanitized.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getPluginInfo() {
|
||||||
|
|
||||||
|
return [
|
||||||
|
'name' => $this->getPluginName(),
|
||||||
|
'description' => 'Adds support for caldav-notifications, which is required to enable caldav-sharing.',
|
||||||
|
'link' => 'http://sabre.io/dav/caldav-sharing/',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1025
vendor/sabre/dav/lib/CalDAV/Plugin.php
vendored
Normal file
1025
vendor/sabre/dav/lib/CalDAV/Plugin.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Sabre\CalDAV\Principal;
|
namespace Sabre\CalDAV\Principal;
|
||||||
|
|
||||||
use Sabre\DAVACL;
|
use Sabre\DAVACL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,11 +12,11 @@ use Sabre\DAVACL;
|
|||||||
* calendar-proxy-write sub-principals, as defined by the caldav-proxy
|
* calendar-proxy-write sub-principals, as defined by the caldav-proxy
|
||||||
* specification.
|
* specification.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
class Collection extends DAVACL\AbstractPrincipalCollection {
|
class Collection extends DAVACL\PrincipalCollection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a child object based on principal information
|
* Returns a child object based on principal information
|
||||||
@ -23,7 +24,7 @@ class Collection extends DAVACL\AbstractPrincipalCollection {
|
|||||||
* @param array $principalInfo
|
* @param array $principalInfo
|
||||||
* @return User
|
* @return User
|
||||||
*/
|
*/
|
||||||
public function getChildForPrincipal(array $principalInfo) {
|
function getChildForPrincipal(array $principalInfo) {
|
||||||
|
|
||||||
return new User($this->principalBackend, $principalInfo);
|
return new User($this->principalBackend, $principalInfo);
|
||||||
|
|
@ -10,7 +10,7 @@ use Sabre\DAVACL;
|
|||||||
* Any principal node implementing this interface will be picked up as a 'proxy
|
* Any principal node implementing this interface will be picked up as a 'proxy
|
||||||
* principal group'.
|
* principal group'.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
@ -10,7 +10,7 @@ use Sabre\DAVACL;
|
|||||||
* Any principal node implementing this interface will be picked up as a 'proxy
|
* Any principal node implementing this interface will be picked up as a 'proxy
|
||||||
* principal group'.
|
* principal group'.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Sabre\CalDAV\Principal;
|
namespace Sabre\CalDAV\Principal;
|
||||||
|
|
||||||
use Sabre\DAVACL;
|
use Sabre\DAVACL;
|
||||||
use Sabre\DAV;
|
use Sabre\DAV;
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ use Sabre\DAV;
|
|||||||
* This is needed to implement 'Calendar delegation' support. This class is
|
* This is needed to implement 'Calendar delegation' support. This class is
|
||||||
* instantiated by User.
|
* instantiated by User.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -39,7 +40,7 @@ class ProxyRead implements IProxyRead {
|
|||||||
* @param DAVACL\PrincipalBackend\BackendInterface $principalBackend
|
* @param DAVACL\PrincipalBackend\BackendInterface $principalBackend
|
||||||
* @param array $principalInfo
|
* @param array $principalInfo
|
||||||
*/
|
*/
|
||||||
public function __construct(DAVACL\PrincipalBackend\BackendInterface $principalBackend, array $principalInfo) {
|
function __construct(DAVACL\PrincipalBackend\BackendInterface $principalBackend, array $principalInfo) {
|
||||||
|
|
||||||
$this->principalInfo = $principalInfo;
|
$this->principalInfo = $principalInfo;
|
||||||
$this->principalBackend = $principalBackend;
|
$this->principalBackend = $principalBackend;
|
||||||
@ -51,7 +52,7 @@ class ProxyRead implements IProxyRead {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() {
|
function getName() {
|
||||||
|
|
||||||
return 'calendar-proxy-read';
|
return 'calendar-proxy-read';
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ class ProxyRead implements IProxyRead {
|
|||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
public function getLastModified() {
|
function getLastModified() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ class ProxyRead implements IProxyRead {
|
|||||||
* @throws DAV\Exception\Forbidden
|
* @throws DAV\Exception\Forbidden
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function delete() {
|
function delete() {
|
||||||
|
|
||||||
throw new DAV\Exception\Forbidden('Permission denied to delete node');
|
throw new DAV\Exception\Forbidden('Permission denied to delete node');
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ class ProxyRead implements IProxyRead {
|
|||||||
* @param string $name The new name
|
* @param string $name The new name
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setName($name) {
|
function setName($name) {
|
||||||
|
|
||||||
throw new DAV\Exception\Forbidden('Permission denied to rename file');
|
throw new DAV\Exception\Forbidden('Permission denied to rename file');
|
||||||
|
|
||||||
@ -101,9 +102,9 @@ class ProxyRead implements IProxyRead {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getAlternateUriSet() {
|
function getAlternateUriSet() {
|
||||||
|
|
||||||
return array();
|
return [];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ class ProxyRead implements IProxyRead {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getPrincipalUrl() {
|
function getPrincipalUrl() {
|
||||||
|
|
||||||
return $this->principalInfo['uri'] . '/' . $this->getName();
|
return $this->principalInfo['uri'] . '/' . $this->getName();
|
||||||
|
|
||||||
@ -126,7 +127,7 @@ class ProxyRead implements IProxyRead {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getGroupMemberSet() {
|
function getGroupMemberSet() {
|
||||||
|
|
||||||
return $this->principalBackend->getGroupMemberSet($this->getPrincipalUrl());
|
return $this->principalBackend->getGroupMemberSet($this->getPrincipalUrl());
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ class ProxyRead implements IProxyRead {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getGroupMembership() {
|
function getGroupMembership() {
|
||||||
|
|
||||||
return $this->principalBackend->getGroupMembership($this->getPrincipalUrl());
|
return $this->principalBackend->getGroupMembership($this->getPrincipalUrl());
|
||||||
|
|
||||||
@ -157,7 +158,7 @@ class ProxyRead implements IProxyRead {
|
|||||||
* @param array $principals
|
* @param array $principals
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setGroupMemberSet(array $principals) {
|
function setGroupMemberSet(array $principals) {
|
||||||
|
|
||||||
$this->principalBackend->setGroupMemberSet($this->getPrincipalUrl(), $principals);
|
$this->principalBackend->setGroupMemberSet($this->getPrincipalUrl(), $principals);
|
||||||
|
|
||||||
@ -171,7 +172,7 @@ class ProxyRead implements IProxyRead {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getDisplayName() {
|
function getDisplayName() {
|
||||||
|
|
||||||
return $this->getName();
|
return $this->getName();
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Sabre\CalDAV\Principal;
|
namespace Sabre\CalDAV\Principal;
|
||||||
|
|
||||||
use Sabre\DAVACL;
|
use Sabre\DAVACL;
|
||||||
use Sabre\DAV;
|
use Sabre\DAV;
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ use Sabre\DAV;
|
|||||||
* This is needed to implement 'Calendar delegation' support. This class is
|
* This is needed to implement 'Calendar delegation' support. This class is
|
||||||
* instantiated by User.
|
* instantiated by User.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -39,7 +40,7 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
* @param DAVACL\PrincipalBackend\BackendInterface $principalBackend
|
* @param DAVACL\PrincipalBackend\BackendInterface $principalBackend
|
||||||
* @param array $principalInfo
|
* @param array $principalInfo
|
||||||
*/
|
*/
|
||||||
public function __construct(DAVACL\PrincipalBackend\BackendInterface $principalBackend, array $principalInfo) {
|
function __construct(DAVACL\PrincipalBackend\BackendInterface $principalBackend, array $principalInfo) {
|
||||||
|
|
||||||
$this->principalInfo = $principalInfo;
|
$this->principalInfo = $principalInfo;
|
||||||
$this->principalBackend = $principalBackend;
|
$this->principalBackend = $principalBackend;
|
||||||
@ -51,7 +52,7 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() {
|
function getName() {
|
||||||
|
|
||||||
return 'calendar-proxy-write';
|
return 'calendar-proxy-write';
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
*
|
*
|
||||||
* @return null
|
* @return null
|
||||||
*/
|
*/
|
||||||
public function getLastModified() {
|
function getLastModified() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
* @throws DAV\Exception\Forbidden
|
* @throws DAV\Exception\Forbidden
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function delete() {
|
function delete() {
|
||||||
|
|
||||||
throw new DAV\Exception\Forbidden('Permission denied to delete node');
|
throw new DAV\Exception\Forbidden('Permission denied to delete node');
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
* @param string $name The new name
|
* @param string $name The new name
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setName($name) {
|
function setName($name) {
|
||||||
|
|
||||||
throw new DAV\Exception\Forbidden('Permission denied to rename file');
|
throw new DAV\Exception\Forbidden('Permission denied to rename file');
|
||||||
|
|
||||||
@ -101,9 +102,9 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getAlternateUriSet() {
|
function getAlternateUriSet() {
|
||||||
|
|
||||||
return array();
|
return [];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getPrincipalUrl() {
|
function getPrincipalUrl() {
|
||||||
|
|
||||||
return $this->principalInfo['uri'] . '/' . $this->getName();
|
return $this->principalInfo['uri'] . '/' . $this->getName();
|
||||||
|
|
||||||
@ -126,7 +127,7 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getGroupMemberSet() {
|
function getGroupMemberSet() {
|
||||||
|
|
||||||
return $this->principalBackend->getGroupMemberSet($this->getPrincipalUrl());
|
return $this->principalBackend->getGroupMemberSet($this->getPrincipalUrl());
|
||||||
|
|
||||||
@ -140,7 +141,7 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getGroupMembership() {
|
function getGroupMembership() {
|
||||||
|
|
||||||
return $this->principalBackend->getGroupMembership($this->getPrincipalUrl());
|
return $this->principalBackend->getGroupMembership($this->getPrincipalUrl());
|
||||||
|
|
||||||
@ -157,7 +158,7 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
* @param array $principals
|
* @param array $principals
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setGroupMemberSet(array $principals) {
|
function setGroupMemberSet(array $principals) {
|
||||||
|
|
||||||
$this->principalBackend->setGroupMemberSet($this->getPrincipalUrl(), $principals);
|
$this->principalBackend->setGroupMemberSet($this->getPrincipalUrl(), $principals);
|
||||||
|
|
||||||
@ -171,7 +172,7 @@ class ProxyWrite implements IProxyWrite {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getDisplayName() {
|
function getDisplayName() {
|
||||||
|
|
||||||
return $this->getName();
|
return $this->getName();
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Sabre\CalDAV\Principal;
|
namespace Sabre\CalDAV\Principal;
|
||||||
|
|
||||||
use Sabre\DAV;
|
use Sabre\DAV;
|
||||||
use Sabre\DAVACL;
|
use Sabre\DAVACL;
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ use Sabre\DAVACL;
|
|||||||
* collection and returns the caldav-proxy-read and caldav-proxy-write child
|
* collection and returns the caldav-proxy-read and caldav-proxy-write child
|
||||||
* principals.
|
* principals.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -25,7 +26,7 @@ class User extends DAVACL\Principal implements DAV\ICollection {
|
|||||||
* @throws DAV\Exception\Forbidden
|
* @throws DAV\Exception\Forbidden
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function createFile($name, $data = null) {
|
function createFile($name, $data = null) {
|
||||||
|
|
||||||
throw new DAV\Exception\Forbidden('Permission denied to create file (filename ' . $name . ')');
|
throw new DAV\Exception\Forbidden('Permission denied to create file (filename ' . $name . ')');
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ class User extends DAVACL\Principal implements DAV\ICollection {
|
|||||||
* @throws DAV\Exception\Forbidden
|
* @throws DAV\Exception\Forbidden
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function createDirectory($name) {
|
function createDirectory($name) {
|
||||||
|
|
||||||
throw new DAV\Exception\Forbidden('Permission denied to create directory');
|
throw new DAV\Exception\Forbidden('Permission denied to create directory');
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ class User extends DAVACL\Principal implements DAV\ICollection {
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @return DAV\INode
|
* @return DAV\INode
|
||||||
*/
|
*/
|
||||||
public function getChild($name) {
|
function getChild($name) {
|
||||||
|
|
||||||
$principal = $this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/' . $name);
|
$principal = $this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/' . $name);
|
||||||
if (!$principal) {
|
if (!$principal) {
|
||||||
@ -69,11 +70,11 @@ class User extends DAVACL\Principal implements DAV\ICollection {
|
|||||||
/**
|
/**
|
||||||
* Returns an array with all the child nodes
|
* Returns an array with all the child nodes
|
||||||
*
|
*
|
||||||
* @return DAV\INode[]
|
* @return DAV\INode[]
|
||||||
*/
|
*/
|
||||||
public function getChildren() {
|
function getChildren() {
|
||||||
|
|
||||||
$r = array();
|
$r = [];
|
||||||
if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-read')) {
|
if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-read')) {
|
||||||
$r[] = new ProxyRead($this->principalBackend, $this->principalProperties);
|
$r[] = new ProxyRead($this->principalBackend, $this->principalProperties);
|
||||||
}
|
}
|
||||||
@ -91,7 +92,7 @@ class User extends DAVACL\Principal implements DAV\ICollection {
|
|||||||
* @param string $name
|
* @param string $name
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function childExists($name) {
|
function childExists($name) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->getChild($name);
|
$this->getChild($name);
|
||||||
@ -114,19 +115,19 @@ class User extends DAVACL\Principal implements DAV\ICollection {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getACL() {
|
function getACL() {
|
||||||
|
|
||||||
$acl = parent::getACL();
|
$acl = parent::getACL();
|
||||||
$acl[] = array(
|
$acl[] = [
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => $this->principalProperties['uri'] . '/calendar-proxy-read',
|
'principal' => $this->principalProperties['uri'] . '/calendar-proxy-read',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
);
|
];
|
||||||
$acl[] = array(
|
$acl[] = [
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => $this->principalProperties['uri'] . '/calendar-proxy-write',
|
'principal' => $this->principalProperties['uri'] . '/calendar-proxy-write',
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
);
|
];
|
||||||
return $acl;
|
return $acl;
|
||||||
|
|
||||||
}
|
}
|
15
vendor/sabre/dav/lib/CalDAV/Schedule/IInbox.php
vendored
Normal file
15
vendor/sabre/dav/lib/CalDAV/Schedule/IInbox.php
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Schedule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface to have a node be recognized as a CalDAV scheduling
|
||||||
|
* inbox.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
interface IInbox extends \Sabre\CalDAV\ICalendarObjectContainer, \Sabre\DAVACL\IACL {
|
||||||
|
|
||||||
|
}
|
190
vendor/sabre/dav/lib/CalDAV/Schedule/IMipPlugin.php
vendored
Normal file
190
vendor/sabre/dav/lib/CalDAV/Schedule/IMipPlugin.php
vendored
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Schedule;
|
||||||
|
|
||||||
|
use Sabre\DAV;
|
||||||
|
use Sabre\VObject\ITip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iMIP handler.
|
||||||
|
*
|
||||||
|
* This class is responsible for sending out iMIP messages. iMIP is the
|
||||||
|
* email-based transport for iTIP. iTIP deals with scheduling operations for
|
||||||
|
* iCalendar objects.
|
||||||
|
*
|
||||||
|
* If you want to customize the email that gets sent out, you can do so by
|
||||||
|
* extending this class and overriding the sendMessage method.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class IMipPlugin extends DAV\ServerPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email address used in From: header.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $senderEmail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ITipMessage
|
||||||
|
*
|
||||||
|
* @var ITip\Message
|
||||||
|
*/
|
||||||
|
protected $itipMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the email handler.
|
||||||
|
*
|
||||||
|
* @param string $senderEmail. The 'senderEmail' is the email that shows up
|
||||||
|
* in the 'From:' address. This should
|
||||||
|
* generally be some kind of no-reply email
|
||||||
|
* address you own.
|
||||||
|
*/
|
||||||
|
function __construct($senderEmail) {
|
||||||
|
|
||||||
|
$this->senderEmail = $senderEmail;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This initializes the plugin.
|
||||||
|
*
|
||||||
|
* This function is called by Sabre\DAV\Server, after
|
||||||
|
* addPlugin is called.
|
||||||
|
*
|
||||||
|
* This method should set up the required event subscriptions.
|
||||||
|
*
|
||||||
|
* @param DAV\Server $server
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function initialize(DAV\Server $server) {
|
||||||
|
|
||||||
|
$server->on('schedule', [$this, 'schedule'], 120);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a plugin name.
|
||||||
|
*
|
||||||
|
* Using this name other plugins will be able to access other plugins
|
||||||
|
* using \Sabre\DAV\Server::getPlugin
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getPluginName() {
|
||||||
|
|
||||||
|
return 'imip';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the 'schedule' event.
|
||||||
|
*
|
||||||
|
* @param ITip\Message $iTipMessage
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function schedule(ITip\Message $iTipMessage) {
|
||||||
|
|
||||||
|
// Not sending any emails if the system considers the update
|
||||||
|
// insignificant.
|
||||||
|
if (!$iTipMessage->significantChange) {
|
||||||
|
if (!$iTipMessage->scheduleStatus) {
|
||||||
|
$iTipMessage->scheduleStatus = '1.0;We got the message, but it\'s not significant enough to warrant an email';
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$summary = $iTipMessage->message->VEVENT->SUMMARY;
|
||||||
|
|
||||||
|
if (parse_url($iTipMessage->sender, PHP_URL_SCHEME) !== 'mailto')
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (parse_url($iTipMessage->recipient, PHP_URL_SCHEME) !== 'mailto')
|
||||||
|
return;
|
||||||
|
|
||||||
|
$sender = substr($iTipMessage->sender, 7);
|
||||||
|
$recipient = substr($iTipMessage->recipient, 7);
|
||||||
|
|
||||||
|
if ($iTipMessage->senderName) {
|
||||||
|
$sender = $iTipMessage->senderName . ' <' . $sender . '>';
|
||||||
|
}
|
||||||
|
if ($iTipMessage->recipientName) {
|
||||||
|
$recipient = $iTipMessage->recipientName . ' <' . $recipient . '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$subject = 'SabreDAV iTIP message';
|
||||||
|
switch (strtoupper($iTipMessage->method)) {
|
||||||
|
case 'REPLY' :
|
||||||
|
$subject = 'Re: ' . $summary;
|
||||||
|
break;
|
||||||
|
case 'REQUEST' :
|
||||||
|
$subject = $summary;
|
||||||
|
break;
|
||||||
|
case 'CANCEL' :
|
||||||
|
$subject = 'Cancelled: ' . $summary;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = [
|
||||||
|
'Reply-To: ' . $sender,
|
||||||
|
'From: ' . $this->senderEmail,
|
||||||
|
'Content-Type: text/calendar; charset=UTF-8; method=' . $iTipMessage->method,
|
||||||
|
];
|
||||||
|
if (DAV\Server::$exposeVersion) {
|
||||||
|
$headers[] = 'X-Sabre-Version: ' . DAV\Version::VERSION;
|
||||||
|
}
|
||||||
|
$this->mail(
|
||||||
|
$recipient,
|
||||||
|
$subject,
|
||||||
|
$iTipMessage->message->serialize(),
|
||||||
|
$headers
|
||||||
|
);
|
||||||
|
$iTipMessage->scheduleStatus = '1.1; Scheduling message is sent via iMip';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
// This is deemed untestable in a reasonable manner
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is responsible for sending the actual email.
|
||||||
|
*
|
||||||
|
* @param string $to Recipient email address
|
||||||
|
* @param string $subject Subject of the email
|
||||||
|
* @param string $body iCalendar body
|
||||||
|
* @param array $headers List of headers
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function mail($to, $subject, $body, array $headers) {
|
||||||
|
|
||||||
|
mail($to, $subject, $body, implode("\r\n", $headers));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bunch of meta-data about the plugin.
|
||||||
|
*
|
||||||
|
* Providing this information is optional, and is mainly displayed by the
|
||||||
|
* Browser plugin.
|
||||||
|
*
|
||||||
|
* The description key in the returned array may contain html and will not
|
||||||
|
* be sanitized.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getPluginInfo() {
|
||||||
|
|
||||||
|
return [
|
||||||
|
'name' => $this->getPluginName(),
|
||||||
|
'description' => 'Email delivery (rfc6037) for CalDAV scheduling',
|
||||||
|
'link' => 'http://sabre.io/dav/scheduling/',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,11 +6,10 @@ namespace Sabre\CalDAV\Schedule;
|
|||||||
* Implement this interface to have a node be recognized as a CalDAV scheduling
|
* Implement this interface to have a node be recognized as a CalDAV scheduling
|
||||||
* outbox.
|
* outbox.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
interface IOutbox extends \Sabre\DAV\ICollection, \Sabre\DAVACL\IACL {
|
interface IOutbox extends \Sabre\DAV\ICollection, \Sabre\DAVACL\IACL {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
13
vendor/sabre/dav/lib/CalDAV/Schedule/ISchedulingObject.php
vendored
Normal file
13
vendor/sabre/dav/lib/CalDAV/Schedule/ISchedulingObject.php
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Schedule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SchedulingObject represents a scheduling object in the Inbox collection
|
||||||
|
*
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
*/
|
||||||
|
interface ISchedulingObject extends \Sabre\CalDAV\ICalendarObject {
|
||||||
|
|
||||||
|
}
|
261
vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php
vendored
Normal file
261
vendor/sabre/dav/lib/CalDAV/Schedule/Inbox.php
vendored
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Schedule;
|
||||||
|
|
||||||
|
use Sabre\DAV;
|
||||||
|
use Sabre\CalDAV;
|
||||||
|
use Sabre\DAVACL;
|
||||||
|
use Sabre\CalDAV\Backend;
|
||||||
|
use Sabre\VObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CalDAV scheduling inbox
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class Inbox extends DAV\Collection implements IInbox {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CalDAV backend
|
||||||
|
*
|
||||||
|
* @var Backend\BackendInterface
|
||||||
|
*/
|
||||||
|
protected $caldavBackend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The principal Uri
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $principalUri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param Backend\SchedulingSupport $caldavBackend
|
||||||
|
* @param string $principalUri
|
||||||
|
*/
|
||||||
|
function __construct(Backend\SchedulingSupport $caldavBackend, $principalUri) {
|
||||||
|
|
||||||
|
$this->caldavBackend = $caldavBackend;
|
||||||
|
$this->principalUri = $principalUri;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the node.
|
||||||
|
*
|
||||||
|
* This is used to generate the url.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getName() {
|
||||||
|
|
||||||
|
return 'inbox';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array with all the child nodes
|
||||||
|
*
|
||||||
|
* @return \Sabre\DAV\INode[]
|
||||||
|
*/
|
||||||
|
function getChildren() {
|
||||||
|
|
||||||
|
$objs = $this->caldavBackend->getSchedulingObjects($this->principalUri);
|
||||||
|
$children = [];
|
||||||
|
foreach ($objs as $obj) {
|
||||||
|
//$obj['acl'] = $this->getACL();
|
||||||
|
$obj['principaluri'] = $this->principalUri;
|
||||||
|
$children[] = new SchedulingObject($this->caldavBackend, $obj);
|
||||||
|
}
|
||||||
|
return $children;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new file in the directory
|
||||||
|
*
|
||||||
|
* Data will either be supplied as a stream resource, or in certain cases
|
||||||
|
* as a string. Keep in mind that you may have to support either.
|
||||||
|
*
|
||||||
|
* After succesful creation of the file, you may choose to return the ETag
|
||||||
|
* of the new file here.
|
||||||
|
*
|
||||||
|
* The returned ETag must be surrounded by double-quotes (The quotes should
|
||||||
|
* be part of the actual string).
|
||||||
|
*
|
||||||
|
* If you cannot accurately determine the ETag, you should not return it.
|
||||||
|
* If you don't store the file exactly as-is (you're transforming it
|
||||||
|
* somehow) you should also not return an ETag.
|
||||||
|
*
|
||||||
|
* This means that if a subsequent GET to this new file does not exactly
|
||||||
|
* return the same contents of what was submitted here, you are strongly
|
||||||
|
* recommended to omit the ETag.
|
||||||
|
*
|
||||||
|
* @param string $name Name of the file
|
||||||
|
* @param resource|string $data Initial payload
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
function createFile($name, $data = null) {
|
||||||
|
|
||||||
|
$this->caldavBackend->createSchedulingObject($this->principalUri, $name, $data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the owner principal
|
||||||
|
*
|
||||||
|
* This must be a url to a principal, or null if there's no owner
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getOwner() {
|
||||||
|
|
||||||
|
return $this->principalUri;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a group principal
|
||||||
|
*
|
||||||
|
* This must be a url to a principal, or null if there's no owner
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getGroup() {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of ACE's for this node.
|
||||||
|
*
|
||||||
|
* Each ACE has the following properties:
|
||||||
|
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
|
||||||
|
* currently the only supported privileges
|
||||||
|
* * 'principal', a url to the principal who owns the node
|
||||||
|
* * 'protected' (optional), indicating that this ACE is not allowed to
|
||||||
|
* be updated.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getACL() {
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => '{DAV:}authenticated',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}write-properties',
|
||||||
|
'principal' => $this->getOwner(),
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}unbind',
|
||||||
|
'principal' => $this->getOwner(),
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}unbind',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-invite',
|
||||||
|
'principal' => '{DAV:}authenticated',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-deliver-reply',
|
||||||
|
'principal' => '{DAV:}authenticated',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the ACL
|
||||||
|
*
|
||||||
|
* This method will receive a list of new ACE's.
|
||||||
|
*
|
||||||
|
* @param array $acl
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function setACL(array $acl) {
|
||||||
|
|
||||||
|
throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of supported privileges for this node.
|
||||||
|
*
|
||||||
|
* The returned data structure is a list of nested privileges.
|
||||||
|
* See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
|
||||||
|
* standard structure.
|
||||||
|
*
|
||||||
|
* If null is returned from this method, the default privilege set is used,
|
||||||
|
* which is fine for most common usecases.
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
function getSupportedPrivilegeSet() {
|
||||||
|
|
||||||
|
$ns = '{' . CalDAV\Plugin::NS_CALDAV . '}';
|
||||||
|
|
||||||
|
$default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
|
||||||
|
$default['aggregates'][] = [
|
||||||
|
'privilege' => $ns . 'schedule-deliver',
|
||||||
|
'aggregates' => [
|
||||||
|
['privilege' => $ns . 'schedule-deliver-invite'],
|
||||||
|
['privilege' => $ns . 'schedule-deliver-reply'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
return $default;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a calendar-query on the contents of this calendar.
|
||||||
|
*
|
||||||
|
* The calendar-query is defined in RFC4791 : CalDAV. Using the
|
||||||
|
* calendar-query it is possible for a client to request a specific set of
|
||||||
|
* object, based on contents of iCalendar properties, date-ranges and
|
||||||
|
* iCalendar component types (VTODO, VEVENT).
|
||||||
|
*
|
||||||
|
* This method should just return a list of (relative) urls that match this
|
||||||
|
* query.
|
||||||
|
*
|
||||||
|
* The list of filters are specified as an array. The exact array is
|
||||||
|
* documented by \Sabre\CalDAV\CalendarQueryParser.
|
||||||
|
*
|
||||||
|
* @param array $filters
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function calendarQuery(array $filters) {
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
$validator = new CalDAV\CalendarQueryValidator();
|
||||||
|
|
||||||
|
$objects = $this->caldavBackend->getSchedulingObjects($this->principalUri);
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
$vObject = VObject\Reader::read($object['calendardata']);
|
||||||
|
if ($validator->validate($vObject, $filters)) {
|
||||||
|
$result[] = $object['uri'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy circular references to PHP will GC the object.
|
||||||
|
$vObject->destroy();
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace Sabre\CalDAV\Schedule;
|
namespace Sabre\CalDAV\Schedule;
|
||||||
|
|
||||||
use Sabre\DAV;
|
use Sabre\DAV;
|
||||||
use Sabre\CalDAV;
|
use Sabre\CalDAV;
|
||||||
use Sabre\DAVACL;
|
use Sabre\DAVACL;
|
||||||
@ -12,7 +13,7 @@ use Sabre\DAVACL;
|
|||||||
* free-busy requests. This functionality is completely handled by the
|
* free-busy requests. This functionality is completely handled by the
|
||||||
* Scheduling plugin, so this object is actually mostly static.
|
* Scheduling plugin, so this object is actually mostly static.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -30,7 +31,7 @@ class Outbox extends DAV\Collection implements IOutbox {
|
|||||||
*
|
*
|
||||||
* @param string $principalUri
|
* @param string $principalUri
|
||||||
*/
|
*/
|
||||||
public function __construct($principalUri) {
|
function __construct($principalUri) {
|
||||||
|
|
||||||
$this->principalUri = $principalUri;
|
$this->principalUri = $principalUri;
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ class Outbox extends DAV\Collection implements IOutbox {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getName() {
|
function getName() {
|
||||||
|
|
||||||
return 'outbox';
|
return 'outbox';
|
||||||
|
|
||||||
@ -54,9 +55,9 @@ class Outbox extends DAV\Collection implements IOutbox {
|
|||||||
*
|
*
|
||||||
* @return \Sabre\DAV\INode[]
|
* @return \Sabre\DAV\INode[]
|
||||||
*/
|
*/
|
||||||
public function getChildren() {
|
function getChildren() {
|
||||||
|
|
||||||
return array();
|
return [];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ class Outbox extends DAV\Collection implements IOutbox {
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getOwner() {
|
function getOwner() {
|
||||||
|
|
||||||
return $this->principalUri;
|
return $this->principalUri;
|
||||||
|
|
||||||
@ -80,7 +81,7 @@ class Outbox extends DAV\Collection implements IOutbox {
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getGroup() {
|
function getGroup() {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -98,25 +99,45 @@ class Outbox extends DAV\Collection implements IOutbox {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getACL() {
|
function getACL() {
|
||||||
|
|
||||||
return array(
|
return [
|
||||||
array(
|
[
|
||||||
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
|
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
|
||||||
'principal' => $this->getOwner(),
|
'principal' => $this->getOwner(),
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
|
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
|
||||||
'principal' => $this->getOwner(),
|
'principal' => $this->getOwner(),
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
array(
|
[
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => $this->getOwner(),
|
'principal' => $this->getOwner(),
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
),
|
],
|
||||||
);
|
[
|
||||||
|
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-read',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +149,7 @@ class Outbox extends DAV\Collection implements IOutbox {
|
|||||||
* @param array $acl
|
* @param array $acl
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setACL(array $acl) {
|
function setACL(array $acl) {
|
||||||
|
|
||||||
throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
|
throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL');
|
||||||
|
|
||||||
@ -146,15 +167,15 @@ class Outbox extends DAV\Collection implements IOutbox {
|
|||||||
*
|
*
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function getSupportedPrivilegeSet() {
|
function getSupportedPrivilegeSet() {
|
||||||
|
|
||||||
$default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
|
$default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet();
|
||||||
$default['aggregates'][] = array(
|
$default['aggregates'][] = [
|
||||||
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
|
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy',
|
||||||
);
|
];
|
||||||
$default['aggregates'][] = array(
|
$default['aggregates'][] = [
|
||||||
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
|
'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent',
|
||||||
);
|
];
|
||||||
|
|
||||||
return $default;
|
return $default;
|
||||||
|
|
994
vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php
vendored
Normal file
994
vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php
vendored
Normal file
@ -0,0 +1,994 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Schedule;
|
||||||
|
|
||||||
|
use DateTimeZone;
|
||||||
|
use Sabre\DAV\Server;
|
||||||
|
use Sabre\DAV\ServerPlugin;
|
||||||
|
use Sabre\DAV\PropFind;
|
||||||
|
use Sabre\DAV\PropPatch;
|
||||||
|
use Sabre\DAV\INode;
|
||||||
|
use Sabre\DAV\Xml\Property\Href;
|
||||||
|
use Sabre\HTTP\RequestInterface;
|
||||||
|
use Sabre\HTTP\ResponseInterface;
|
||||||
|
use Sabre\VObject;
|
||||||
|
use Sabre\VObject\Reader;
|
||||||
|
use Sabre\VObject\Component\VCalendar;
|
||||||
|
use Sabre\VObject\ITip;
|
||||||
|
use Sabre\VObject\ITip\Message;
|
||||||
|
use Sabre\DAVACL;
|
||||||
|
use Sabre\CalDAV\ICalendar;
|
||||||
|
use Sabre\CalDAV\ICalendarObject;
|
||||||
|
use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp;
|
||||||
|
use Sabre\DAV\Exception\NotFound;
|
||||||
|
use Sabre\DAV\Exception\Forbidden;
|
||||||
|
use Sabre\DAV\Exception\BadRequest;
|
||||||
|
use Sabre\DAV\Exception\NotImplemented;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CalDAV scheduling plugin.
|
||||||
|
* =========================
|
||||||
|
*
|
||||||
|
* This plugin provides the functionality added by the "Scheduling Extensions
|
||||||
|
* to CalDAV" standard, as defined in RFC6638.
|
||||||
|
*
|
||||||
|
* calendar-auto-schedule largely works by intercepting a users request to
|
||||||
|
* update their local calendar. If a user creates a new event with attendees,
|
||||||
|
* this plugin is supposed to grab the information from that event, and notify
|
||||||
|
* the attendees of this.
|
||||||
|
*
|
||||||
|
* There's 3 possible transports for this:
|
||||||
|
* * local delivery
|
||||||
|
* * delivery through email (iMip)
|
||||||
|
* * server-to-server delivery (iSchedule)
|
||||||
|
*
|
||||||
|
* iMip is simply, because we just need to add the iTip message as an email
|
||||||
|
* attachment. Local delivery is harder, because we both need to add this same
|
||||||
|
* message to a local DAV inbox, as well as live-update the relevant events.
|
||||||
|
*
|
||||||
|
* iSchedule is something for later.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class Plugin extends ServerPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the official CalDAV namespace
|
||||||
|
*/
|
||||||
|
const NS_CALDAV = 'urn:ietf:params:xml:ns:caldav';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to main Server object.
|
||||||
|
*
|
||||||
|
* @var Server
|
||||||
|
*/
|
||||||
|
protected $server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of features for the DAV: HTTP header.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getFeatures() {
|
||||||
|
|
||||||
|
return ['calendar-auto-schedule', 'calendar-availability'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the plugin.
|
||||||
|
*
|
||||||
|
* Using this name other plugins will be able to access other plugins
|
||||||
|
* using Server::getPlugin
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getPluginName() {
|
||||||
|
|
||||||
|
return 'caldav-schedule';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the plugin
|
||||||
|
*
|
||||||
|
* @param Server $server
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function initialize(Server $server) {
|
||||||
|
|
||||||
|
$this->server = $server;
|
||||||
|
$server->on('method:POST', [$this, 'httpPost']);
|
||||||
|
$server->on('propFind', [$this, 'propFind']);
|
||||||
|
$server->on('propPatch', [$this, 'propPatch']);
|
||||||
|
$server->on('calendarObjectChange', [$this, 'calendarObjectChange']);
|
||||||
|
$server->on('beforeUnbind', [$this, 'beforeUnbind']);
|
||||||
|
$server->on('schedule', [$this, 'scheduleLocalDelivery']);
|
||||||
|
|
||||||
|
$ns = '{' . self::NS_CALDAV . '}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This information ensures that the {DAV:}resourcetype property has
|
||||||
|
* the correct values.
|
||||||
|
*/
|
||||||
|
$server->resourceTypeMapping['\\Sabre\\CalDAV\\Schedule\\IOutbox'] = $ns . 'schedule-outbox';
|
||||||
|
$server->resourceTypeMapping['\\Sabre\\CalDAV\\Schedule\\IInbox'] = $ns . 'schedule-inbox';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties we protect are made read-only by the server.
|
||||||
|
*/
|
||||||
|
array_push($server->protectedProperties,
|
||||||
|
$ns . 'schedule-inbox-URL',
|
||||||
|
$ns . 'schedule-outbox-URL',
|
||||||
|
$ns . 'calendar-user-address-set',
|
||||||
|
$ns . 'calendar-user-type',
|
||||||
|
$ns . 'schedule-default-calendar-URL'
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this method to tell the server this plugin defines additional
|
||||||
|
* HTTP methods.
|
||||||
|
*
|
||||||
|
* This method is passed a uri. It should only return HTTP methods that are
|
||||||
|
* available for the specified uri.
|
||||||
|
*
|
||||||
|
* @param string $uri
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getHTTPMethods($uri) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
$node = $this->server->tree->getNodeForPath($uri);
|
||||||
|
} catch (NotFound $e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node instanceof IOutbox) {
|
||||||
|
return ['POST'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method handles POST request for the outbox.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function httpPost(RequestInterface $request, ResponseInterface $response) {
|
||||||
|
|
||||||
|
// Checking if this is a text/calendar content type
|
||||||
|
$contentType = $request->getHeader('Content-Type');
|
||||||
|
if (strpos($contentType, 'text/calendar') !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = $request->getPath();
|
||||||
|
|
||||||
|
// Checking if we're talking to an outbox
|
||||||
|
try {
|
||||||
|
$node = $this->server->tree->getNodeForPath($path);
|
||||||
|
} catch (NotFound $e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!$node instanceof IOutbox)
|
||||||
|
return;
|
||||||
|
|
||||||
|
$this->server->transactionType = 'post-caldav-outbox';
|
||||||
|
$this->outboxRequest($node, $request, $response);
|
||||||
|
|
||||||
|
// Returning false breaks the event chain and tells the server we've
|
||||||
|
// handled the request.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method handler is invoked during fetching of properties.
|
||||||
|
*
|
||||||
|
* We use this event to add calendar-auto-schedule-specific properties.
|
||||||
|
*
|
||||||
|
* @param PropFind $propFind
|
||||||
|
* @param INode $node
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function propFind(PropFind $propFind, INode $node) {
|
||||||
|
|
||||||
|
if ($node instanceof DAVACL\IPrincipal) {
|
||||||
|
|
||||||
|
$caldavPlugin = $this->server->getPlugin('caldav');
|
||||||
|
$principalUrl = $node->getPrincipalUrl();
|
||||||
|
|
||||||
|
// schedule-outbox-URL property
|
||||||
|
$propFind->handle('{' . self::NS_CALDAV . '}schedule-outbox-URL', function() use ($principalUrl, $caldavPlugin) {
|
||||||
|
|
||||||
|
$calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
|
||||||
|
if (!$calendarHomePath) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$outboxPath = $calendarHomePath . '/outbox/';
|
||||||
|
|
||||||
|
return new Href($outboxPath);
|
||||||
|
|
||||||
|
});
|
||||||
|
// schedule-inbox-URL property
|
||||||
|
$propFind->handle('{' . self::NS_CALDAV . '}schedule-inbox-URL', function() use ($principalUrl, $caldavPlugin) {
|
||||||
|
|
||||||
|
$calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
|
||||||
|
if (!$calendarHomePath) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$inboxPath = $calendarHomePath . '/inbox/';
|
||||||
|
|
||||||
|
return new Href($inboxPath);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$propFind->handle('{' . self::NS_CALDAV . '}schedule-default-calendar-URL', function() use ($principalUrl, $caldavPlugin) {
|
||||||
|
|
||||||
|
// We don't support customizing this property yet, so in the
|
||||||
|
// meantime we just grab the first calendar in the home-set.
|
||||||
|
$calendarHomePath = $caldavPlugin->getCalendarHomeForPrincipal($principalUrl);
|
||||||
|
|
||||||
|
if (!$calendarHomePath) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sccs = '{' . self::NS_CALDAV . '}supported-calendar-component-set';
|
||||||
|
|
||||||
|
$result = $this->server->getPropertiesForPath($calendarHomePath, [
|
||||||
|
'{DAV:}resourcetype',
|
||||||
|
$sccs,
|
||||||
|
], 1);
|
||||||
|
|
||||||
|
foreach ($result as $child) {
|
||||||
|
if (!isset($child[200]['{DAV:}resourcetype']) || !$child[200]['{DAV:}resourcetype']->is('{' . self::NS_CALDAV . '}calendar') || $child[200]['{DAV:}resourcetype']->is('{http://calendarserver.org/ns/}shared')) {
|
||||||
|
// Node is either not a calendar or a shared instance.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!isset($child[200][$sccs]) || in_array('VEVENT', $child[200][$sccs]->getValue())) {
|
||||||
|
// Either there is no supported-calendar-component-set
|
||||||
|
// (which is fine) or we found one that supports VEVENT.
|
||||||
|
return new Href($child['href']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// The server currently reports every principal to be of type
|
||||||
|
// 'INDIVIDUAL'
|
||||||
|
$propFind->handle('{' . self::NS_CALDAV . '}calendar-user-type', function() {
|
||||||
|
|
||||||
|
return 'INDIVIDUAL';
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapping the old property to the new property.
|
||||||
|
$propFind->handle('{http://calendarserver.org/ns/}calendar-availability', function() use ($propFind, $node) {
|
||||||
|
|
||||||
|
// In case it wasn't clear, the only difference is that we map the
|
||||||
|
// old property to a different namespace.
|
||||||
|
$availProp = '{' . self::NS_CALDAV . '}calendar-availability';
|
||||||
|
$subPropFind = new PropFind(
|
||||||
|
$propFind->getPath(),
|
||||||
|
[$availProp]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->server->getPropertiesByNode(
|
||||||
|
$subPropFind,
|
||||||
|
$node
|
||||||
|
);
|
||||||
|
|
||||||
|
$propFind->set(
|
||||||
|
'{http://calendarserver.org/ns/}calendar-availability',
|
||||||
|
$subPropFind->get($availProp),
|
||||||
|
$subPropFind->getStatus($availProp)
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called during property updates.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param PropPatch $propPatch
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function propPatch($path, PropPatch $propPatch) {
|
||||||
|
|
||||||
|
// Mapping the old property to the new property.
|
||||||
|
$propPatch->handle('{http://calendarserver.org/ns/}calendar-availability', function($value) use ($path) {
|
||||||
|
|
||||||
|
$availProp = '{' . self::NS_CALDAV . '}calendar-availability';
|
||||||
|
$subPropPatch = new PropPatch([$availProp => $value]);
|
||||||
|
$this->server->emit('propPatch', [$path, $subPropPatch]);
|
||||||
|
$subPropPatch->commit();
|
||||||
|
|
||||||
|
return $subPropPatch->getResult()[$availProp];
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is triggered whenever there was a calendar object gets
|
||||||
|
* created or updated.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request HTTP request
|
||||||
|
* @param ResponseInterface $response HTTP Response
|
||||||
|
* @param VCalendar $vCal Parsed iCalendar object
|
||||||
|
* @param mixed $calendarPath Path to calendar collection
|
||||||
|
* @param mixed $modified The iCalendar object has been touched.
|
||||||
|
* @param mixed $isNew Whether this was a new item or we're updating one
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function calendarObjectChange(RequestInterface $request, ResponseInterface $response, VCalendar $vCal, $calendarPath, &$modified, $isNew) {
|
||||||
|
|
||||||
|
if (!$this->scheduleReply($this->server->httpRequest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$calendarNode = $this->server->tree->getNodeForPath($calendarPath);
|
||||||
|
|
||||||
|
$addresses = $this->getAddressesForPrincipal(
|
||||||
|
$calendarNode->getOwner()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$isNew) {
|
||||||
|
$node = $this->server->tree->getNodeForPath($request->getPath());
|
||||||
|
$oldObj = Reader::read($node->get());
|
||||||
|
} else {
|
||||||
|
$oldObj = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->processICalendarChange($oldObj, $vCal, $addresses, [], $modified);
|
||||||
|
|
||||||
|
if ($oldObj) {
|
||||||
|
// Destroy circular references so PHP will GC the object.
|
||||||
|
$oldObj->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is responsible for delivering the ITip message.
|
||||||
|
*
|
||||||
|
* @param ITip\Message $itipMessage
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function deliver(ITip\Message $iTipMessage) {
|
||||||
|
|
||||||
|
$this->server->emit('schedule', [$iTipMessage]);
|
||||||
|
if (!$iTipMessage->scheduleStatus) {
|
||||||
|
$iTipMessage->scheduleStatus = '5.2;There was no system capable of delivering the scheduling message';
|
||||||
|
}
|
||||||
|
// In case the change was considered 'insignificant', we are going to
|
||||||
|
// remove any error statuses, if any. See ticket #525.
|
||||||
|
list($baseCode) = explode('.', $iTipMessage->scheduleStatus);
|
||||||
|
if (!$iTipMessage->significantChange && in_array($baseCode, ['3', '5'])) {
|
||||||
|
$iTipMessage->scheduleStatus = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is triggered before a file gets deleted.
|
||||||
|
*
|
||||||
|
* We use this event to make sure that when this happens, attendees get
|
||||||
|
* cancellations, and organizers get 'DECLINED' statuses.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function beforeUnbind($path) {
|
||||||
|
|
||||||
|
// FIXME: We shouldn't trigger this functionality when we're issuing a
|
||||||
|
// MOVE. This is a hack.
|
||||||
|
if ($this->server->httpRequest->getMethod() === 'MOVE') return;
|
||||||
|
|
||||||
|
$node = $this->server->tree->getNodeForPath($path);
|
||||||
|
|
||||||
|
if (!$node instanceof ICalendarObject || $node instanceof ISchedulingObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->scheduleReply($this->server->httpRequest)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$addresses = $this->getAddressesForPrincipal(
|
||||||
|
$node->getOwner()
|
||||||
|
);
|
||||||
|
|
||||||
|
$broker = new ITip\Broker();
|
||||||
|
$messages = $broker->parseEvent(null, $addresses, $node->get());
|
||||||
|
|
||||||
|
foreach ($messages as $message) {
|
||||||
|
$this->deliver($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the 'schedule' event.
|
||||||
|
*
|
||||||
|
* This handler attempts to look at local accounts to deliver the
|
||||||
|
* scheduling object.
|
||||||
|
*
|
||||||
|
* @param ITip\Message $iTipMessage
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function scheduleLocalDelivery(ITip\Message $iTipMessage) {
|
||||||
|
|
||||||
|
$aclPlugin = $this->server->getPlugin('acl');
|
||||||
|
|
||||||
|
// Local delivery is not available if the ACL plugin is not loaded.
|
||||||
|
if (!$aclPlugin) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$caldavNS = '{' . self::NS_CALDAV . '}';
|
||||||
|
|
||||||
|
$principalUri = $aclPlugin->getPrincipalByUri($iTipMessage->recipient);
|
||||||
|
if (!$principalUri) {
|
||||||
|
$iTipMessage->scheduleStatus = '3.7;Could not find principal.';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We found a principal URL, now we need to find its inbox.
|
||||||
|
// Unfortunately we may not have sufficient privileges to find this, so
|
||||||
|
// we are temporarily turning off ACL to let this come through.
|
||||||
|
//
|
||||||
|
// Once we support PHP 5.5, this should be wrapped in a try..finally
|
||||||
|
// block so we can ensure that this privilege gets added again after.
|
||||||
|
$this->server->removeListener('propFind', [$aclPlugin, 'propFind']);
|
||||||
|
|
||||||
|
$result = $this->server->getProperties(
|
||||||
|
$principalUri,
|
||||||
|
[
|
||||||
|
'{DAV:}principal-URL',
|
||||||
|
$caldavNS . 'calendar-home-set',
|
||||||
|
$caldavNS . 'schedule-inbox-URL',
|
||||||
|
$caldavNS . 'schedule-default-calendar-URL',
|
||||||
|
'{http://sabredav.org/ns}email-address',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Re-registering the ACL event
|
||||||
|
$this->server->on('propFind', [$aclPlugin, 'propFind'], 20);
|
||||||
|
|
||||||
|
if (!isset($result[$caldavNS . 'schedule-inbox-URL'])) {
|
||||||
|
$iTipMessage->scheduleStatus = '5.2;Could not find local inbox';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isset($result[$caldavNS . 'calendar-home-set'])) {
|
||||||
|
$iTipMessage->scheduleStatus = '5.2;Could not locate a calendar-home-set';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isset($result[$caldavNS . 'schedule-default-calendar-URL'])) {
|
||||||
|
$iTipMessage->scheduleStatus = '5.2;Could not find a schedule-default-calendar-URL property';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$calendarPath = $result[$caldavNS . 'schedule-default-calendar-URL']->getHref();
|
||||||
|
$homePath = $result[$caldavNS . 'calendar-home-set']->getHref();
|
||||||
|
$inboxPath = $result[$caldavNS . 'schedule-inbox-URL']->getHref();
|
||||||
|
|
||||||
|
if ($iTipMessage->method === 'REPLY') {
|
||||||
|
$privilege = 'schedule-deliver-reply';
|
||||||
|
} else {
|
||||||
|
$privilege = 'schedule-deliver-invite';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$aclPlugin->checkPrivileges($inboxPath, $caldavNS . $privilege, DAVACL\Plugin::R_PARENT, false)) {
|
||||||
|
$iTipMessage->scheduleStatus = '3.8;organizer did not have the ' . $privilege . ' privilege on the attendees inbox';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next, we're going to find out if the item already exits in one of
|
||||||
|
// the users' calendars.
|
||||||
|
$uid = $iTipMessage->uid;
|
||||||
|
|
||||||
|
$newFileName = 'sabredav-' . \Sabre\DAV\UUIDUtil::getUUID() . '.ics';
|
||||||
|
|
||||||
|
$home = $this->server->tree->getNodeForPath($homePath);
|
||||||
|
$inbox = $this->server->tree->getNodeForPath($inboxPath);
|
||||||
|
|
||||||
|
$currentObject = null;
|
||||||
|
$objectNode = null;
|
||||||
|
$isNewNode = false;
|
||||||
|
|
||||||
|
$result = $home->getCalendarObjectByUID($uid);
|
||||||
|
if ($result) {
|
||||||
|
// There was an existing object, we need to update probably.
|
||||||
|
$objectPath = $homePath . '/' . $result;
|
||||||
|
$objectNode = $this->server->tree->getNodeForPath($objectPath);
|
||||||
|
$oldICalendarData = $objectNode->get();
|
||||||
|
$currentObject = Reader::read($oldICalendarData);
|
||||||
|
} else {
|
||||||
|
$isNewNode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$broker = new ITip\Broker();
|
||||||
|
$newObject = $broker->processMessage($iTipMessage, $currentObject);
|
||||||
|
|
||||||
|
$inbox->createFile($newFileName, $iTipMessage->message->serialize());
|
||||||
|
|
||||||
|
if (!$newObject) {
|
||||||
|
// We received an iTip message referring to a UID that we don't
|
||||||
|
// have in any calendars yet, and processMessage did not give us a
|
||||||
|
// calendarobject back.
|
||||||
|
//
|
||||||
|
// The implication is that processMessage did not understand the
|
||||||
|
// iTip message.
|
||||||
|
$iTipMessage->scheduleStatus = '5.0;iTip message was not processed by the server, likely because we didn\'t understand it.';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that we are bypassing ACL on purpose by calling this directly.
|
||||||
|
// We may need to look a bit deeper into this later. Supporting ACL
|
||||||
|
// here would be nice.
|
||||||
|
if ($isNewNode) {
|
||||||
|
$calendar = $this->server->tree->getNodeForPath($calendarPath);
|
||||||
|
$calendar->createFile($newFileName, $newObject->serialize());
|
||||||
|
} else {
|
||||||
|
// If the message was a reply, we may have to inform other
|
||||||
|
// attendees of this attendees status. Therefore we're shooting off
|
||||||
|
// another itipMessage.
|
||||||
|
if ($iTipMessage->method === 'REPLY') {
|
||||||
|
$this->processICalendarChange(
|
||||||
|
$oldICalendarData,
|
||||||
|
$newObject,
|
||||||
|
[$iTipMessage->recipient],
|
||||||
|
[$iTipMessage->sender]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$objectNode->put($newObject->serialize());
|
||||||
|
}
|
||||||
|
$iTipMessage->scheduleStatus = '1.2;Message delivered locally';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method looks at an old iCalendar object, a new iCalendar object and
|
||||||
|
* starts sending scheduling messages based on the changes.
|
||||||
|
*
|
||||||
|
* A list of addresses needs to be specified, so the system knows who made
|
||||||
|
* the update, because the behavior may be different based on if it's an
|
||||||
|
* attendee or an organizer.
|
||||||
|
*
|
||||||
|
* This method may update $newObject to add any status changes.
|
||||||
|
*
|
||||||
|
* @param VCalendar|string $oldObject
|
||||||
|
* @param VCalendar $newObject
|
||||||
|
* @param array $addresses
|
||||||
|
* @param array $ignore Any addresses to not send messages to.
|
||||||
|
* @param bool $modified A marker to indicate that the original object
|
||||||
|
* modified by this process.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function processICalendarChange($oldObject = null, VCalendar $newObject, array $addresses, array $ignore = [], &$modified = false) {
|
||||||
|
|
||||||
|
$broker = new ITip\Broker();
|
||||||
|
$messages = $broker->parseEvent($newObject, $addresses, $oldObject);
|
||||||
|
|
||||||
|
if ($messages) $modified = true;
|
||||||
|
|
||||||
|
foreach ($messages as $message) {
|
||||||
|
|
||||||
|
if (in_array($message->recipient, $ignore)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->deliver($message);
|
||||||
|
|
||||||
|
if (isset($newObject->VEVENT->ORGANIZER) && ($newObject->VEVENT->ORGANIZER->getNormalizedValue() === $message->recipient)) {
|
||||||
|
if ($message->scheduleStatus) {
|
||||||
|
$newObject->VEVENT->ORGANIZER['SCHEDULE-STATUS'] = $message->getScheduleStatus();
|
||||||
|
}
|
||||||
|
unset($newObject->VEVENT->ORGANIZER['SCHEDULE-FORCE-SEND']);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (isset($newObject->VEVENT->ATTENDEE)) foreach ($newObject->VEVENT->ATTENDEE as $attendee) {
|
||||||
|
|
||||||
|
if ($attendee->getNormalizedValue() === $message->recipient) {
|
||||||
|
if ($message->scheduleStatus) {
|
||||||
|
$attendee['SCHEDULE-STATUS'] = $message->getScheduleStatus();
|
||||||
|
}
|
||||||
|
unset($attendee['SCHEDULE-FORCE-SEND']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of addresses that are associated with a principal.
|
||||||
|
*
|
||||||
|
* @param string $principal
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getAddressesForPrincipal($principal) {
|
||||||
|
|
||||||
|
$CUAS = '{' . self::NS_CALDAV . '}calendar-user-address-set';
|
||||||
|
|
||||||
|
$properties = $this->server->getProperties(
|
||||||
|
$principal,
|
||||||
|
[$CUAS]
|
||||||
|
);
|
||||||
|
|
||||||
|
// If we can't find this information, we'll stop processing
|
||||||
|
if (!isset($properties[$CUAS])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$addresses = $properties[$CUAS]->getHrefs();
|
||||||
|
return $addresses;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method handles POST requests to the schedule-outbox.
|
||||||
|
*
|
||||||
|
* Currently, two types of requests are support:
|
||||||
|
* * FREEBUSY requests from RFC 6638
|
||||||
|
* * Simple iTIP messages from draft-desruisseaux-caldav-sched-04
|
||||||
|
*
|
||||||
|
* The latter is from an expired early draft of the CalDAV scheduling
|
||||||
|
* extensions, but iCal depends on a feature from that spec, so we
|
||||||
|
* implement it.
|
||||||
|
*
|
||||||
|
* @param IOutbox $outboxNode
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function outboxRequest(IOutbox $outboxNode, RequestInterface $request, ResponseInterface $response) {
|
||||||
|
|
||||||
|
$outboxPath = $request->getPath();
|
||||||
|
|
||||||
|
// Parsing the request body
|
||||||
|
try {
|
||||||
|
$vObject = VObject\Reader::read($request->getBody());
|
||||||
|
} catch (VObject\ParseException $e) {
|
||||||
|
throw new BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// The incoming iCalendar object must have a METHOD property, and a
|
||||||
|
// component. The combination of both determines what type of request
|
||||||
|
// this is.
|
||||||
|
$componentType = null;
|
||||||
|
foreach ($vObject->getComponents() as $component) {
|
||||||
|
if ($component->name !== 'VTIMEZONE') {
|
||||||
|
$componentType = $component->name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_null($componentType)) {
|
||||||
|
throw new BadRequest('We expected at least one VTODO, VJOURNAL, VFREEBUSY or VEVENT component');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validating the METHOD
|
||||||
|
$method = strtoupper((string)$vObject->METHOD);
|
||||||
|
if (!$method) {
|
||||||
|
throw new BadRequest('A METHOD property must be specified in iTIP messages');
|
||||||
|
}
|
||||||
|
|
||||||
|
// So we support one type of request:
|
||||||
|
//
|
||||||
|
// REQUEST with a VFREEBUSY component
|
||||||
|
|
||||||
|
$acl = $this->server->getPlugin('acl');
|
||||||
|
|
||||||
|
if ($componentType === 'VFREEBUSY' && $method === 'REQUEST') {
|
||||||
|
|
||||||
|
$acl && $acl->checkPrivileges($outboxPath, '{' . self::NS_CALDAV . '}schedule-query-freebusy');
|
||||||
|
$this->handleFreeBusyRequest($outboxNode, $vObject, $request, $response);
|
||||||
|
|
||||||
|
// Destroy circular references so PHP can GC the object.
|
||||||
|
$vObject->destroy();
|
||||||
|
unset($vObject);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
throw new NotImplemented('We only support VFREEBUSY (REQUEST) on this endpoint');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is responsible for parsing a free-busy query request and
|
||||||
|
* returning it's result.
|
||||||
|
*
|
||||||
|
* @param IOutbox $outbox
|
||||||
|
* @param VObject\Component $vObject
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function handleFreeBusyRequest(IOutbox $outbox, VObject\Component $vObject, RequestInterface $request, ResponseInterface $response) {
|
||||||
|
|
||||||
|
$vFreeBusy = $vObject->VFREEBUSY;
|
||||||
|
$organizer = $vFreeBusy->organizer;
|
||||||
|
|
||||||
|
$organizer = (string)$organizer;
|
||||||
|
|
||||||
|
// Validating if the organizer matches the owner of the inbox.
|
||||||
|
$owner = $outbox->getOwner();
|
||||||
|
|
||||||
|
$caldavNS = '{' . self::NS_CALDAV . '}';
|
||||||
|
|
||||||
|
$uas = $caldavNS . 'calendar-user-address-set';
|
||||||
|
$props = $this->server->getProperties($owner, [$uas]);
|
||||||
|
|
||||||
|
if (empty($props[$uas]) || !in_array($organizer, $props[$uas]->getHrefs())) {
|
||||||
|
throw new Forbidden('The organizer in the request did not match any of the addresses for the owner of this inbox');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($vFreeBusy->ATTENDEE)) {
|
||||||
|
throw new BadRequest('You must at least specify 1 attendee');
|
||||||
|
}
|
||||||
|
|
||||||
|
$attendees = [];
|
||||||
|
foreach ($vFreeBusy->ATTENDEE as $attendee) {
|
||||||
|
$attendees[] = (string)$attendee;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!isset($vFreeBusy->DTSTART) || !isset($vFreeBusy->DTEND)) {
|
||||||
|
throw new BadRequest('DTSTART and DTEND must both be specified');
|
||||||
|
}
|
||||||
|
|
||||||
|
$startRange = $vFreeBusy->DTSTART->getDateTime();
|
||||||
|
$endRange = $vFreeBusy->DTEND->getDateTime();
|
||||||
|
|
||||||
|
$results = [];
|
||||||
|
foreach ($attendees as $attendee) {
|
||||||
|
$results[] = $this->getFreeBusyForEmail($attendee, $startRange, $endRange, $vObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
$dom = new \DOMDocument('1.0', 'utf-8');
|
||||||
|
$dom->formatOutput = true;
|
||||||
|
$scheduleResponse = $dom->createElement('cal:schedule-response');
|
||||||
|
foreach ($this->server->xml->namespaceMap as $namespace => $prefix) {
|
||||||
|
|
||||||
|
$scheduleResponse->setAttribute('xmlns:' . $prefix, $namespace);
|
||||||
|
|
||||||
|
}
|
||||||
|
$dom->appendChild($scheduleResponse);
|
||||||
|
|
||||||
|
foreach ($results as $result) {
|
||||||
|
$xresponse = $dom->createElement('cal:response');
|
||||||
|
|
||||||
|
$recipient = $dom->createElement('cal:recipient');
|
||||||
|
$recipientHref = $dom->createElement('d:href');
|
||||||
|
|
||||||
|
$recipientHref->appendChild($dom->createTextNode($result['href']));
|
||||||
|
$recipient->appendChild($recipientHref);
|
||||||
|
$xresponse->appendChild($recipient);
|
||||||
|
|
||||||
|
$reqStatus = $dom->createElement('cal:request-status');
|
||||||
|
$reqStatus->appendChild($dom->createTextNode($result['request-status']));
|
||||||
|
$xresponse->appendChild($reqStatus);
|
||||||
|
|
||||||
|
if (isset($result['calendar-data'])) {
|
||||||
|
|
||||||
|
$calendardata = $dom->createElement('cal:calendar-data');
|
||||||
|
$calendardata->appendChild($dom->createTextNode(str_replace("\r\n", "\n", $result['calendar-data']->serialize())));
|
||||||
|
$xresponse->appendChild($calendardata);
|
||||||
|
|
||||||
|
}
|
||||||
|
$scheduleResponse->appendChild($xresponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->setStatus(200);
|
||||||
|
$response->setHeader('Content-Type', 'application/xml');
|
||||||
|
$response->setBody($dom->saveXML());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns free-busy information for a specific address. The returned
|
||||||
|
* data is an array containing the following properties:
|
||||||
|
*
|
||||||
|
* calendar-data : A VFREEBUSY VObject
|
||||||
|
* request-status : an iTip status code.
|
||||||
|
* href: The principal's email address, as requested
|
||||||
|
*
|
||||||
|
* The following request status codes may be returned:
|
||||||
|
* * 2.0;description
|
||||||
|
* * 3.7;description
|
||||||
|
*
|
||||||
|
* @param string $email address
|
||||||
|
* @param DateTimeInterface $start
|
||||||
|
* @param DateTimeInterface $end
|
||||||
|
* @param VObject\Component $request
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getFreeBusyForEmail($email, \DateTimeInterface $start, \DateTimeInterface $end, VObject\Component $request) {
|
||||||
|
|
||||||
|
$caldavNS = '{' . self::NS_CALDAV . '}';
|
||||||
|
|
||||||
|
$aclPlugin = $this->server->getPlugin('acl');
|
||||||
|
if (substr($email, 0, 7) === 'mailto:') $email = substr($email, 7);
|
||||||
|
|
||||||
|
$result = $aclPlugin->principalSearch(
|
||||||
|
['{http://sabredav.org/ns}email-address' => $email],
|
||||||
|
[
|
||||||
|
'{DAV:}principal-URL',
|
||||||
|
$caldavNS . 'calendar-home-set',
|
||||||
|
$caldavNS . 'schedule-inbox-URL',
|
||||||
|
'{http://sabredav.org/ns}email-address',
|
||||||
|
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!count($result)) {
|
||||||
|
return [
|
||||||
|
'request-status' => '3.7;Could not find principal',
|
||||||
|
'href' => 'mailto:' . $email,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($result[0][200][$caldavNS . 'calendar-home-set'])) {
|
||||||
|
return [
|
||||||
|
'request-status' => '3.7;No calendar-home-set property found',
|
||||||
|
'href' => 'mailto:' . $email,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (!isset($result[0][200][$caldavNS . 'schedule-inbox-URL'])) {
|
||||||
|
return [
|
||||||
|
'request-status' => '3.7;No schedule-inbox-URL property found',
|
||||||
|
'href' => 'mailto:' . $email,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$homeSet = $result[0][200][$caldavNS . 'calendar-home-set']->getHref();
|
||||||
|
$inboxUrl = $result[0][200][$caldavNS . 'schedule-inbox-URL']->getHref();
|
||||||
|
|
||||||
|
// Grabbing the calendar list
|
||||||
|
$objects = [];
|
||||||
|
$calendarTimeZone = new DateTimeZone('UTC');
|
||||||
|
|
||||||
|
foreach ($this->server->tree->getNodeForPath($homeSet)->getChildren() as $node) {
|
||||||
|
if (!$node instanceof ICalendar) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sct = $caldavNS . 'schedule-calendar-transp';
|
||||||
|
$ctz = $caldavNS . 'calendar-timezone';
|
||||||
|
$props = $node->getProperties([$sct, $ctz]);
|
||||||
|
|
||||||
|
if (isset($props[$sct]) && $props[$sct]->getValue() == ScheduleCalendarTransp::TRANSPARENT) {
|
||||||
|
// If a calendar is marked as 'transparent', it means we must
|
||||||
|
// ignore it for free-busy purposes.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$aclPlugin->checkPrivileges($homeSet . $node->getName(), $caldavNS . 'read-free-busy');
|
||||||
|
|
||||||
|
if (isset($props[$ctz])) {
|
||||||
|
$vtimezoneObj = VObject\Reader::read($props[$ctz]);
|
||||||
|
$calendarTimeZone = $vtimezoneObj->VTIMEZONE->getTimeZone();
|
||||||
|
|
||||||
|
// Destroy circular references so PHP can garbage collect the object.
|
||||||
|
$vtimezoneObj->destroy();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getting the list of object uris within the time-range
|
||||||
|
$urls = $node->calendarQuery([
|
||||||
|
'name' => 'VCALENDAR',
|
||||||
|
'comp-filters' => [
|
||||||
|
[
|
||||||
|
'name' => 'VEVENT',
|
||||||
|
'comp-filters' => [],
|
||||||
|
'prop-filters' => [],
|
||||||
|
'is-not-defined' => false,
|
||||||
|
'time-range' => [
|
||||||
|
'start' => $start,
|
||||||
|
'end' => $end,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'prop-filters' => [],
|
||||||
|
'is-not-defined' => false,
|
||||||
|
'time-range' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$calObjects = array_map(function($url) use ($node) {
|
||||||
|
$obj = $node->getChild($url)->get();
|
||||||
|
return $obj;
|
||||||
|
}, $urls);
|
||||||
|
|
||||||
|
$objects = array_merge($objects, $calObjects);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$inboxProps = $this->server->getProperties(
|
||||||
|
$inboxUrl,
|
||||||
|
$caldavNS . 'calendar-availability'
|
||||||
|
);
|
||||||
|
|
||||||
|
$vcalendar = new VObject\Component\VCalendar();
|
||||||
|
$vcalendar->METHOD = 'REPLY';
|
||||||
|
|
||||||
|
$generator = new VObject\FreeBusyGenerator();
|
||||||
|
$generator->setObjects($objects);
|
||||||
|
$generator->setTimeRange($start, $end);
|
||||||
|
$generator->setBaseObject($vcalendar);
|
||||||
|
$generator->setTimeZone($calendarTimeZone);
|
||||||
|
|
||||||
|
if ($inboxProps) {
|
||||||
|
$generator->setVAvailability(
|
||||||
|
VObject\Reader::read(
|
||||||
|
$inboxProps[$caldavNS . 'calendar-availability']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $generator->getResult();
|
||||||
|
|
||||||
|
$vcalendar->VFREEBUSY->ATTENDEE = 'mailto:' . $email;
|
||||||
|
$vcalendar->VFREEBUSY->UID = (string)$request->VFREEBUSY->UID;
|
||||||
|
$vcalendar->VFREEBUSY->ORGANIZER = clone $request->VFREEBUSY->ORGANIZER;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'calendar-data' => $result,
|
||||||
|
'request-status' => '2.0;Success',
|
||||||
|
'href' => 'mailto:' . $email,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks the 'Schedule-Reply' header
|
||||||
|
* and returns false if it's 'F', otherwise true.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function scheduleReply(RequestInterface $request) {
|
||||||
|
|
||||||
|
$scheduleReply = $request->getHeader('Schedule-Reply');
|
||||||
|
return $scheduleReply !== 'F';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bunch of meta-data about the plugin.
|
||||||
|
*
|
||||||
|
* Providing this information is optional, and is mainly displayed by the
|
||||||
|
* Browser plugin.
|
||||||
|
*
|
||||||
|
* The description key in the returned array may contain html and will not
|
||||||
|
* be sanitized.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getPluginInfo() {
|
||||||
|
|
||||||
|
return [
|
||||||
|
'name' => $this->getPluginName(),
|
||||||
|
'description' => 'Adds calendar-auto-schedule, as defined in rf6868',
|
||||||
|
'link' => 'http://sabre.io/dav/scheduling/',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
165
vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php
vendored
Normal file
165
vendor/sabre/dav/lib/CalDAV/Schedule/SchedulingObject.php
vendored
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Schedule;
|
||||||
|
|
||||||
|
use Sabre\CalDAV\Backend;
|
||||||
|
use Sabre\DAV\Exception\MethodNotAllowed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SchedulingObject represents a scheduling object in the Inbox collection
|
||||||
|
*
|
||||||
|
* @author Brett (https://github.com/bretten)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
*/
|
||||||
|
class SchedulingObject extends \Sabre\CalDAV\CalendarObject implements ISchedulingObject {
|
||||||
|
|
||||||
|
/**
|
||||||
|
/* The CalDAV backend
|
||||||
|
*
|
||||||
|
* @var Backend\SchedulingSupport
|
||||||
|
*/
|
||||||
|
protected $caldavBackend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array with information about this SchedulingObject
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $objectData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* The following properties may be passed within $objectData:
|
||||||
|
*
|
||||||
|
* * uri - A unique uri. Only the 'basename' must be passed.
|
||||||
|
* * principaluri - the principal that owns the object.
|
||||||
|
* * calendardata (optional) - The iCalendar data
|
||||||
|
* * etag - (optional) The etag for this object, MUST be encloded with
|
||||||
|
* double-quotes.
|
||||||
|
* * size - (optional) The size of the data in bytes.
|
||||||
|
* * lastmodified - (optional) format as a unix timestamp.
|
||||||
|
* * acl - (optional) Use this to override the default ACL for the node.
|
||||||
|
*
|
||||||
|
* @param Backend\BackendInterface $caldavBackend
|
||||||
|
* @param array $objectData
|
||||||
|
*/
|
||||||
|
function __construct(Backend\SchedulingSupport $caldavBackend, array $objectData) {
|
||||||
|
|
||||||
|
$this->caldavBackend = $caldavBackend;
|
||||||
|
|
||||||
|
if (!isset($objectData['uri'])) {
|
||||||
|
throw new \InvalidArgumentException('The objectData argument must contain an \'uri\' property');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->objectData = $objectData;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ICalendar-formatted object
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function get() {
|
||||||
|
|
||||||
|
// Pre-populating the 'calendardata' is optional, if we don't have it
|
||||||
|
// already we fetch it from the backend.
|
||||||
|
if (!isset($this->objectData['calendardata'])) {
|
||||||
|
$this->objectData = $this->caldavBackend->getSchedulingObject($this->objectData['principaluri'], $this->objectData['uri']);
|
||||||
|
}
|
||||||
|
return $this->objectData['calendardata'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the ICalendar-formatted object
|
||||||
|
*
|
||||||
|
* @param string|resource $calendarData
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function put($calendarData) {
|
||||||
|
|
||||||
|
throw new MethodNotAllowed('Updating scheduling objects is not supported');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the scheduling message
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function delete() {
|
||||||
|
|
||||||
|
$this->caldavBackend->deleteSchedulingObject($this->objectData['principaluri'], $this->objectData['uri']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the owner principal
|
||||||
|
*
|
||||||
|
* This must be a url to a principal, or null if there's no owner
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getOwner() {
|
||||||
|
|
||||||
|
return $this->objectData['principaluri'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of ACE's for this node.
|
||||||
|
*
|
||||||
|
* Each ACE has the following properties:
|
||||||
|
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
|
||||||
|
* currently the only supported privileges
|
||||||
|
* * 'principal', a url to the principal who owns the node
|
||||||
|
* * 'protected' (optional), indicating that this ACE is not allowed to
|
||||||
|
* be updated.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getACL() {
|
||||||
|
|
||||||
|
// An alternative acl may be specified in the object data.
|
||||||
|
//
|
||||||
|
|
||||||
|
if (isset($this->objectData['acl'])) {
|
||||||
|
return $this->objectData['acl'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// The default ACL
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->objectData['principaluri'],
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}write',
|
||||||
|
'principal' => $this->objectData['principaluri'],
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->objectData['principaluri'] . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}write',
|
||||||
|
'principal' => $this->objectData['principaluri'] . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->objectData['principaluri'] . '/calendar-proxy-read',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,7 +6,7 @@ namespace Sabre\CalDAV;
|
|||||||
* This object represents a CalDAV calendar that can be shared with other
|
* This object represents a CalDAV calendar that can be shared with other
|
||||||
* users.
|
* users.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -30,7 +30,7 @@ class ShareableCalendar extends Calendar implements IShareableCalendar {
|
|||||||
* @param array $remove
|
* @param array $remove
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function updateShares(array $add, array $remove) {
|
function updateShares(array $add, array $remove) {
|
||||||
|
|
||||||
$this->caldavBackend->updateShares($this->calendarInfo['id'], $add, $remove);
|
$this->caldavBackend->updateShares($this->calendarInfo['id'], $add, $remove);
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ class ShareableCalendar extends Calendar implements IShareableCalendar {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getShares() {
|
function getShares() {
|
||||||
|
|
||||||
return $this->caldavBackend->getShares($this->calendarInfo['id']);
|
return $this->caldavBackend->getShares($this->calendarInfo['id']);
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ class ShareableCalendar extends Calendar implements IShareableCalendar {
|
|||||||
* @param bool $value
|
* @param bool $value
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setPublishStatus($value) {
|
function setPublishStatus($value) {
|
||||||
|
|
||||||
$this->caldavBackend->setPublishStatus($this->calendarInfo['id'], $value);
|
$this->caldavBackend->setPublishStatus($this->calendarInfo['id'], $value);
|
||||||
|
|
@ -2,12 +2,10 @@
|
|||||||
|
|
||||||
namespace Sabre\CalDAV;
|
namespace Sabre\CalDAV;
|
||||||
|
|
||||||
use Sabre\DAVACL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This object represents a CalDAV calendar that is shared by a different user.
|
* This object represents a CalDAV calendar that is shared by a different user.
|
||||||
*
|
*
|
||||||
* @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/).
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
* @author Evert Pot (http://evertpot.com/)
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
* @license http://sabre.io/license/ Modified BSD License
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
*/
|
*/
|
||||||
@ -19,14 +17,14 @@ class SharedCalendar extends Calendar implements ISharedCalendar {
|
|||||||
* @param Backend\BackendInterface $caldavBackend
|
* @param Backend\BackendInterface $caldavBackend
|
||||||
* @param array $calendarInfo
|
* @param array $calendarInfo
|
||||||
*/
|
*/
|
||||||
public function __construct(Backend\BackendInterface $caldavBackend, $calendarInfo) {
|
function __construct(Backend\BackendInterface $caldavBackend, $calendarInfo) {
|
||||||
|
|
||||||
$required = array(
|
$required = [
|
||||||
'{http://calendarserver.org/ns/}shared-url',
|
'{http://calendarserver.org/ns/}shared-url',
|
||||||
'{http://sabredav.org/ns}owner-principal',
|
'{http://sabredav.org/ns}owner-principal',
|
||||||
'{http://sabredav.org/ns}read-only',
|
'{http://sabredav.org/ns}read-only',
|
||||||
);
|
];
|
||||||
foreach($required as $r) {
|
foreach ($required as $r) {
|
||||||
if (!isset($calendarInfo[$r])) {
|
if (!isset($calendarInfo[$r])) {
|
||||||
throw new \InvalidArgumentException('The ' . $r . ' property must be specified for SharedCalendar(s)');
|
throw new \InvalidArgumentException('The ' . $r . ' property must be specified for SharedCalendar(s)');
|
||||||
}
|
}
|
||||||
@ -42,7 +40,7 @@ class SharedCalendar extends Calendar implements ISharedCalendar {
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getSharedUrl() {
|
function getSharedUrl() {
|
||||||
|
|
||||||
return $this->calendarInfo['{http://calendarserver.org/ns/}shared-url'];
|
return $this->calendarInfo['{http://calendarserver.org/ns/}shared-url'];
|
||||||
|
|
||||||
@ -55,7 +53,7 @@ class SharedCalendar extends Calendar implements ISharedCalendar {
|
|||||||
*
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function getOwner() {
|
function getOwner() {
|
||||||
|
|
||||||
return $this->calendarInfo['{http://sabredav.org/ns}owner-principal'];
|
return $this->calendarInfo['{http://sabredav.org/ns}owner-principal'];
|
||||||
|
|
||||||
@ -73,28 +71,62 @@ class SharedCalendar extends Calendar implements ISharedCalendar {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getACL() {
|
function getACL() {
|
||||||
|
|
||||||
// The top-level ACL only contains access information for the true
|
// The top-level ACL only contains access information for the true
|
||||||
// owner of the calendar, so we need to add the information for the
|
// owner of the calendar, so we need to add the information for the
|
||||||
// sharee.
|
// sharee.
|
||||||
$acl = parent::getACL();
|
$acl = parent::getACL();
|
||||||
$acl[] = array(
|
$acl[] = [
|
||||||
'privilege' => '{DAV:}read',
|
'privilege' => '{DAV:}read',
|
||||||
'principal' => $this->calendarInfo['principaluri'],
|
'principal' => $this->calendarInfo['principaluri'],
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
);
|
];
|
||||||
if (!$this->calendarInfo['{http://sabredav.org/ns}read-only']) {
|
if ($this->calendarInfo['{http://sabredav.org/ns}read-only']) {
|
||||||
$acl[] = array(
|
$acl[] = [
|
||||||
|
'privilege' => '{DAV:}write-properties',
|
||||||
|
'principal' => $this->calendarInfo['principaluri'],
|
||||||
|
'protected' => true,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$acl[] = [
|
||||||
'privilege' => '{DAV:}write',
|
'privilege' => '{DAV:}write',
|
||||||
'principal' => $this->calendarInfo['principaluri'],
|
'principal' => $this->calendarInfo['principaluri'],
|
||||||
'protected' => true,
|
'protected' => true,
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
return $acl;
|
return $acl;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the ACL's for calendar objects in this calendar.
|
||||||
|
* The result of this method automatically gets passed to the
|
||||||
|
* calendar-object nodes in the calendar.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getChildACL() {
|
||||||
|
|
||||||
|
$acl = parent::getChildACL();
|
||||||
|
$acl[] = [
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->calendarInfo['principaluri'],
|
||||||
|
'protected' => true,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$this->calendarInfo['{http://sabredav.org/ns}read-only']) {
|
||||||
|
$acl[] = [
|
||||||
|
'privilege' => '{DAV:}write',
|
||||||
|
'principal' => $this->calendarInfo['principaluri'],
|
||||||
|
'protected' => true,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $acl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of people whom this calendar is shared with.
|
* Returns the list of people whom this calendar is shared with.
|
||||||
*
|
*
|
||||||
@ -107,7 +139,7 @@ class SharedCalendar extends Calendar implements ISharedCalendar {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getShares() {
|
function getShares() {
|
||||||
|
|
||||||
return $this->caldavBackend->getShares($this->calendarInfo['id']);
|
return $this->caldavBackend->getShares($this->calendarInfo['id']);
|
||||||
|
|
426
vendor/sabre/dav/lib/CalDAV/SharingPlugin.php
vendored
Normal file
426
vendor/sabre/dav/lib/CalDAV/SharingPlugin.php
vendored
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV;
|
||||||
|
|
||||||
|
use Sabre\DAV;
|
||||||
|
use Sabre\DAV\Xml\Property\Href;
|
||||||
|
use Sabre\HTTP\RequestInterface;
|
||||||
|
use Sabre\HTTP\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This plugin implements support for caldav sharing.
|
||||||
|
*
|
||||||
|
* This spec is defined at:
|
||||||
|
* http://svn.calendarserver.org/repository/calendarserver/CalendarServer/trunk/doc/Extensions/caldav-sharing.txt
|
||||||
|
*
|
||||||
|
* See:
|
||||||
|
* Sabre\CalDAV\Backend\SharingSupport for all the documentation.
|
||||||
|
*
|
||||||
|
* Note: This feature is experimental, and may change in between different
|
||||||
|
* SabreDAV versions.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class SharingPlugin extends DAV\ServerPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These are the various status constants used by sharing-messages.
|
||||||
|
*/
|
||||||
|
const STATUS_ACCEPTED = 1;
|
||||||
|
const STATUS_DECLINED = 2;
|
||||||
|
const STATUS_DELETED = 3;
|
||||||
|
const STATUS_NORESPONSE = 4;
|
||||||
|
const STATUS_INVALID = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to SabreDAV server object.
|
||||||
|
*
|
||||||
|
* @var Sabre\DAV\Server
|
||||||
|
*/
|
||||||
|
protected $server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should return a list of server-features.
|
||||||
|
*
|
||||||
|
* This is for example 'versioning' and is added to the DAV: header
|
||||||
|
* in an OPTIONS response.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getFeatures() {
|
||||||
|
|
||||||
|
return ['calendarserver-sharing'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a plugin name.
|
||||||
|
*
|
||||||
|
* Using this name other plugins will be able to access other plugins
|
||||||
|
* using Sabre\DAV\Server::getPlugin
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getPluginName() {
|
||||||
|
|
||||||
|
return 'caldav-sharing';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This initializes the plugin.
|
||||||
|
*
|
||||||
|
* This function is called by Sabre\DAV\Server, after
|
||||||
|
* addPlugin is called.
|
||||||
|
*
|
||||||
|
* This method should set up the required event subscriptions.
|
||||||
|
*
|
||||||
|
* @param DAV\Server $server
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function initialize(DAV\Server $server) {
|
||||||
|
|
||||||
|
$this->server = $server;
|
||||||
|
$server->resourceTypeMapping['Sabre\\CalDAV\\ISharedCalendar'] = '{' . Plugin::NS_CALENDARSERVER . '}shared';
|
||||||
|
|
||||||
|
array_push(
|
||||||
|
$this->server->protectedProperties,
|
||||||
|
'{' . Plugin::NS_CALENDARSERVER . '}invite',
|
||||||
|
'{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes',
|
||||||
|
'{' . Plugin::NS_CALENDARSERVER . '}shared-url'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->server->xml->elementMap['{' . Plugin::NS_CALENDARSERVER . '}share'] = 'Sabre\\CalDAV\\Xml\\Request\\Share';
|
||||||
|
$this->server->xml->elementMap['{' . Plugin::NS_CALENDARSERVER . '}invite-reply'] = 'Sabre\\CalDAV\\Xml\\Request\\InviteReply';
|
||||||
|
|
||||||
|
$this->server->on('propFind', [$this, 'propFindEarly']);
|
||||||
|
$this->server->on('propFind', [$this, 'propFindLate'], 150);
|
||||||
|
$this->server->on('propPatch', [$this, 'propPatch'], 40);
|
||||||
|
$this->server->on('method:POST', [$this, 'httpPost']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event is triggered when properties are requested for a certain
|
||||||
|
* node.
|
||||||
|
*
|
||||||
|
* This allows us to inject any properties early.
|
||||||
|
*
|
||||||
|
* @param DAV\PropFind $propFind
|
||||||
|
* @param DAV\INode $node
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function propFindEarly(DAV\PropFind $propFind, DAV\INode $node) {
|
||||||
|
|
||||||
|
if ($node instanceof IShareableCalendar) {
|
||||||
|
|
||||||
|
$propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}invite', function() use ($node) {
|
||||||
|
return new Xml\Property\Invite(
|
||||||
|
$node->getShares()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node instanceof ISharedCalendar) {
|
||||||
|
|
||||||
|
$propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}shared-url', function() use ($node) {
|
||||||
|
return new Href(
|
||||||
|
$node->getSharedUrl()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}invite', function() use ($node) {
|
||||||
|
|
||||||
|
// Fetching owner information
|
||||||
|
$props = $this->server->getPropertiesForPath($node->getOwner(), [
|
||||||
|
'{http://sabredav.org/ns}email-address',
|
||||||
|
'{DAV:}displayname',
|
||||||
|
], 0);
|
||||||
|
|
||||||
|
$ownerInfo = [
|
||||||
|
'href' => $node->getOwner(),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isset($props[0][200])) {
|
||||||
|
|
||||||
|
// We're mapping the internal webdav properties to the
|
||||||
|
// elements caldav-sharing expects.
|
||||||
|
if (isset($props[0][200]['{http://sabredav.org/ns}email-address'])) {
|
||||||
|
$ownerInfo['href'] = 'mailto:' . $props[0][200]['{http://sabredav.org/ns}email-address'];
|
||||||
|
}
|
||||||
|
if (isset($props[0][200]['{DAV:}displayname'])) {
|
||||||
|
$ownerInfo['commonName'] = $props[0][200]['{DAV:}displayname'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Xml\Property\Invite(
|
||||||
|
$node->getShares(),
|
||||||
|
$ownerInfo
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is triggered *after* all properties have been retrieved.
|
||||||
|
* This allows us to inject the correct resourcetype for calendars that
|
||||||
|
* have been shared.
|
||||||
|
*
|
||||||
|
* @param DAV\PropFind $propFind
|
||||||
|
* @param DAV\INode $node
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function propFindLate(DAV\PropFind $propFind, DAV\INode $node) {
|
||||||
|
|
||||||
|
if ($node instanceof IShareableCalendar) {
|
||||||
|
if ($rt = $propFind->get('{DAV:}resourcetype')) {
|
||||||
|
if (count($node->getShares()) > 0) {
|
||||||
|
$rt->add('{' . Plugin::NS_CALENDARSERVER . '}shared-owner');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$propFind->handle('{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes', function() {
|
||||||
|
return new Xml\Property\AllowedSharingModes(true, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is trigged when a user attempts to update a node's
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* A previous draft of the sharing spec stated that it was possible to use
|
||||||
|
* PROPPATCH to remove 'shared-owner' from the resourcetype, thus unsharing
|
||||||
|
* the calendar.
|
||||||
|
*
|
||||||
|
* Even though this is no longer in the current spec, we keep this around
|
||||||
|
* because OS X 10.7 may still make use of this feature.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param DAV\PropPatch $propPatch
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function propPatch($path, DAV\PropPatch $propPatch) {
|
||||||
|
|
||||||
|
$node = $this->server->tree->getNodeForPath($path);
|
||||||
|
if (!$node instanceof IShareableCalendar)
|
||||||
|
return;
|
||||||
|
|
||||||
|
$propPatch->handle('{DAV:}resourcetype', function($value) use ($node) {
|
||||||
|
if ($value->is('{' . Plugin::NS_CALENDARSERVER . '}shared-owner')) return false;
|
||||||
|
$shares = $node->getShares();
|
||||||
|
$remove = [];
|
||||||
|
foreach ($shares as $share) {
|
||||||
|
$remove[] = $share['href'];
|
||||||
|
}
|
||||||
|
$node->updateShares([], $remove);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We intercept this to handle POST requests on calendars.
|
||||||
|
*
|
||||||
|
* @param RequestInterface $request
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @return null|bool
|
||||||
|
*/
|
||||||
|
function httpPost(RequestInterface $request, ResponseInterface $response) {
|
||||||
|
|
||||||
|
$path = $request->getPath();
|
||||||
|
|
||||||
|
// Only handling xml
|
||||||
|
$contentType = $request->getHeader('Content-Type');
|
||||||
|
if (strpos($contentType, 'application/xml') === false && strpos($contentType, 'text/xml') === false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Making sure the node exists
|
||||||
|
try {
|
||||||
|
$node = $this->server->tree->getNodeForPath($path);
|
||||||
|
} catch (DAV\Exception\NotFound $e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$requestBody = $request->getBodyAsString();
|
||||||
|
|
||||||
|
// If this request handler could not deal with this POST request, it
|
||||||
|
// will return 'null' and other plugins get a chance to handle the
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// However, we already requested the full body. This is a problem,
|
||||||
|
// because a body can only be read once. This is why we preemptively
|
||||||
|
// re-populated the request body with the existing data.
|
||||||
|
$request->setBody($requestBody);
|
||||||
|
|
||||||
|
$message = $this->server->xml->parse($requestBody, $request->getUrl(), $documentType);
|
||||||
|
|
||||||
|
switch ($documentType) {
|
||||||
|
|
||||||
|
// Dealing with the 'share' document, which modified invitees on a
|
||||||
|
// calendar.
|
||||||
|
case '{' . Plugin::NS_CALENDARSERVER . '}share' :
|
||||||
|
|
||||||
|
// We can only deal with IShareableCalendar objects
|
||||||
|
if (!$node instanceof IShareableCalendar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->server->transactionType = 'post-calendar-share';
|
||||||
|
|
||||||
|
// Getting ACL info
|
||||||
|
$acl = $this->server->getPlugin('acl');
|
||||||
|
|
||||||
|
// If there's no ACL support, we allow everything
|
||||||
|
if ($acl) {
|
||||||
|
$acl->checkPrivileges($path, '{DAV:}write');
|
||||||
|
}
|
||||||
|
|
||||||
|
$node->updateShares($message->set, $message->remove);
|
||||||
|
|
||||||
|
$response->setStatus(200);
|
||||||
|
// Adding this because sending a response body may cause issues,
|
||||||
|
// and I wanted some type of indicator the response was handled.
|
||||||
|
$response->setHeader('X-Sabre-Status', 'everything-went-well');
|
||||||
|
|
||||||
|
// Breaking the event chain
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// The invite-reply document is sent when the user replies to an
|
||||||
|
// invitation of a calendar share.
|
||||||
|
case '{' . Plugin::NS_CALENDARSERVER . '}invite-reply' :
|
||||||
|
|
||||||
|
// This only works on the calendar-home-root node.
|
||||||
|
if (!$node instanceof CalendarHome) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->server->transactionType = 'post-invite-reply';
|
||||||
|
|
||||||
|
// Getting ACL info
|
||||||
|
$acl = $this->server->getPlugin('acl');
|
||||||
|
|
||||||
|
// If there's no ACL support, we allow everything
|
||||||
|
if ($acl) {
|
||||||
|
$acl->checkPrivileges($path, '{DAV:}write');
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = $node->shareReply(
|
||||||
|
$message->href,
|
||||||
|
$message->status,
|
||||||
|
$message->calendarUri,
|
||||||
|
$message->inReplyTo,
|
||||||
|
$message->summary
|
||||||
|
);
|
||||||
|
|
||||||
|
$response->setStatus(200);
|
||||||
|
// Adding this because sending a response body may cause issues,
|
||||||
|
// and I wanted some type of indicator the response was handled.
|
||||||
|
$response->setHeader('X-Sabre-Status', 'everything-went-well');
|
||||||
|
|
||||||
|
if ($url) {
|
||||||
|
$writer = $this->server->xml->getWriter($this->server->getBaseUri());
|
||||||
|
$writer->openMemory();
|
||||||
|
$writer->startDocument();
|
||||||
|
$writer->startElement('{' . Plugin::NS_CALENDARSERVER . '}shared-as');
|
||||||
|
$writer->write(new Href($url));
|
||||||
|
$writer->endElement();
|
||||||
|
$response->setHeader('Content-Type', 'application/xml');
|
||||||
|
$response->setBody($writer->outputMemory());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Breaking the event chain
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case '{' . Plugin::NS_CALENDARSERVER . '}publish-calendar' :
|
||||||
|
|
||||||
|
// We can only deal with IShareableCalendar objects
|
||||||
|
if (!$node instanceof IShareableCalendar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->server->transactionType = 'post-publish-calendar';
|
||||||
|
|
||||||
|
// Getting ACL info
|
||||||
|
$acl = $this->server->getPlugin('acl');
|
||||||
|
|
||||||
|
// If there's no ACL support, we allow everything
|
||||||
|
if ($acl) {
|
||||||
|
$acl->checkPrivileges($path, '{DAV:}write');
|
||||||
|
}
|
||||||
|
|
||||||
|
$node->setPublishStatus(true);
|
||||||
|
|
||||||
|
// iCloud sends back the 202, so we will too.
|
||||||
|
$response->setStatus(202);
|
||||||
|
|
||||||
|
// Adding this because sending a response body may cause issues,
|
||||||
|
// and I wanted some type of indicator the response was handled.
|
||||||
|
$response->setHeader('X-Sabre-Status', 'everything-went-well');
|
||||||
|
|
||||||
|
// Breaking the event chain
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case '{' . Plugin::NS_CALENDARSERVER . '}unpublish-calendar' :
|
||||||
|
|
||||||
|
// We can only deal with IShareableCalendar objects
|
||||||
|
if (!$node instanceof IShareableCalendar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->server->transactionType = 'post-unpublish-calendar';
|
||||||
|
|
||||||
|
// Getting ACL info
|
||||||
|
$acl = $this->server->getPlugin('acl');
|
||||||
|
|
||||||
|
// If there's no ACL support, we allow everything
|
||||||
|
if ($acl) {
|
||||||
|
$acl->checkPrivileges($path, '{DAV:}write');
|
||||||
|
}
|
||||||
|
|
||||||
|
$node->setPublishStatus(false);
|
||||||
|
|
||||||
|
$response->setStatus(200);
|
||||||
|
|
||||||
|
// Adding this because sending a response body may cause issues,
|
||||||
|
// and I wanted some type of indicator the response was handled.
|
||||||
|
$response->setHeader('X-Sabre-Status', 'everything-went-well');
|
||||||
|
|
||||||
|
// Breaking the event chain
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bunch of meta-data about the plugin.
|
||||||
|
*
|
||||||
|
* Providing this information is optional, and is mainly displayed by the
|
||||||
|
* Browser plugin.
|
||||||
|
*
|
||||||
|
* The description key in the returned array may contain html and will not
|
||||||
|
* be sanitized.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getPluginInfo() {
|
||||||
|
|
||||||
|
return [
|
||||||
|
'name' => $this->getPluginName(),
|
||||||
|
'description' => 'Adds support for caldav-sharing.',
|
||||||
|
'link' => 'http://sabre.io/dav/caldav-sharing/',
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
40
vendor/sabre/dav/lib/CalDAV/Subscriptions/ISubscription.php
vendored
Normal file
40
vendor/sabre/dav/lib/CalDAV/Subscriptions/ISubscription.php
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Subscriptions;
|
||||||
|
|
||||||
|
use Sabre\DAV\ICollection;
|
||||||
|
use Sabre\DAV\IProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ISubscription
|
||||||
|
*
|
||||||
|
* Nodes implementing this interface represent calendar subscriptions.
|
||||||
|
*
|
||||||
|
* The subscription node doesn't do much, other than returning and updating
|
||||||
|
* subscription-related properties.
|
||||||
|
*
|
||||||
|
* The following properties should be supported:
|
||||||
|
*
|
||||||
|
* 1. {DAV:}displayname
|
||||||
|
* 2. {http://apple.com/ns/ical/}refreshrate
|
||||||
|
* 3. {http://calendarserver.org/ns/}subscribed-strip-todos (omit if todos
|
||||||
|
* should not be stripped).
|
||||||
|
* 4. {http://calendarserver.org/ns/}subscribed-strip-alarms (omit if alarms
|
||||||
|
* should not be stripped).
|
||||||
|
* 5. {http://calendarserver.org/ns/}subscribed-strip-attachments (omit if
|
||||||
|
* attachments should not be stripped).
|
||||||
|
* 6. {http://calendarserver.org/ns/}source (Must be a
|
||||||
|
* Sabre\DAV\Property\Href).
|
||||||
|
* 7. {http://apple.com/ns/ical/}calendar-color
|
||||||
|
* 8. {http://apple.com/ns/ical/}calendar-order
|
||||||
|
*
|
||||||
|
* It is recommended to support every property.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
interface ISubscription extends ICollection, IProperties {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
120
vendor/sabre/dav/lib/CalDAV/Subscriptions/Plugin.php
vendored
Normal file
120
vendor/sabre/dav/lib/CalDAV/Subscriptions/Plugin.php
vendored
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Subscriptions;
|
||||||
|
|
||||||
|
use Sabre\DAV\INode;
|
||||||
|
use Sabre\DAV\PropFind;
|
||||||
|
use Sabre\DAV\ServerPlugin;
|
||||||
|
use Sabre\DAV\Server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This plugin adds calendar-subscription support to your CalDAV server.
|
||||||
|
*
|
||||||
|
* Some clients support 'managed subscriptions' server-side. This is basically
|
||||||
|
* a list of subscription urls a user is using.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class Plugin extends ServerPlugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This initializes the plugin.
|
||||||
|
*
|
||||||
|
* This function is called by Sabre\DAV\Server, after
|
||||||
|
* addPlugin is called.
|
||||||
|
*
|
||||||
|
* This method should set up the required event subscriptions.
|
||||||
|
*
|
||||||
|
* @param Server $server
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function initialize(Server $server) {
|
||||||
|
|
||||||
|
$server->resourceTypeMapping['Sabre\\CalDAV\\Subscriptions\\ISubscription'] =
|
||||||
|
'{http://calendarserver.org/ns/}subscribed';
|
||||||
|
|
||||||
|
$server->xml->elementMap['{http://calendarserver.org/ns/}source'] =
|
||||||
|
'Sabre\\DAV\\Xml\\Property\\Href';
|
||||||
|
|
||||||
|
$server->on('propFind', [$this, 'propFind'], 150);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should return a list of server-features.
|
||||||
|
*
|
||||||
|
* This is for example 'versioning' and is added to the DAV: header
|
||||||
|
* in an OPTIONS response.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getFeatures() {
|
||||||
|
|
||||||
|
return ['calendarserver-subscribed'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered after properties have been fetched.
|
||||||
|
*
|
||||||
|
* @param PropFind $propFind
|
||||||
|
* @param INode $node
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function propFind(PropFind $propFind, INode $node) {
|
||||||
|
|
||||||
|
// There's a bunch of properties that must appear as a self-closing
|
||||||
|
// xml-element. This event handler ensures that this will be the case.
|
||||||
|
$props = [
|
||||||
|
'{http://calendarserver.org/ns/}subscribed-strip-alarms',
|
||||||
|
'{http://calendarserver.org/ns/}subscribed-strip-attachments',
|
||||||
|
'{http://calendarserver.org/ns/}subscribed-strip-todos',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($props as $prop) {
|
||||||
|
|
||||||
|
if ($propFind->getStatus($prop) === 200) {
|
||||||
|
$propFind->set($prop, '', 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a plugin name.
|
||||||
|
*
|
||||||
|
* Using this name other plugins will be able to access other plugins
|
||||||
|
* using \Sabre\DAV\Server::getPlugin
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getPluginName() {
|
||||||
|
|
||||||
|
return 'subscriptions';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a bunch of meta-data about the plugin.
|
||||||
|
*
|
||||||
|
* Providing this information is optional, and is mainly displayed by the
|
||||||
|
* Browser plugin.
|
||||||
|
*
|
||||||
|
* The description key in the returned array may contain html and will not
|
||||||
|
* be sanitized.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getPluginInfo() {
|
||||||
|
|
||||||
|
return [
|
||||||
|
'name' => $this->getPluginName(),
|
||||||
|
'description' => 'This plugin allows users to store iCalendar subscriptions in their calendar-home.',
|
||||||
|
'link' => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
274
vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php
vendored
Normal file
274
vendor/sabre/dav/lib/CalDAV/Subscriptions/Subscription.php
vendored
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Subscriptions;
|
||||||
|
|
||||||
|
use Sabre\DAV\Collection;
|
||||||
|
use Sabre\DAV\Xml\Property\Href;
|
||||||
|
use Sabre\DAV\PropPatch;
|
||||||
|
use Sabre\DAV\Exception\MethodNotAllowed;
|
||||||
|
use Sabre\DAVACL\IACL;
|
||||||
|
use Sabre\CalDAV\Backend\SubscriptionSupport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscription Node
|
||||||
|
*
|
||||||
|
* This node represents a subscription.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://evertpot.com/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class Subscription extends Collection implements ISubscription, IACL {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* caldavBackend
|
||||||
|
*
|
||||||
|
* @var SupportsSubscriptions
|
||||||
|
*/
|
||||||
|
protected $caldavBackend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscriptionInfo
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $subscriptionInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param SubscriptionSupport $caldavBackend
|
||||||
|
* @param array $calendarInfo
|
||||||
|
*/
|
||||||
|
function __construct(SubscriptionSupport $caldavBackend, array $subscriptionInfo) {
|
||||||
|
|
||||||
|
$this->caldavBackend = $caldavBackend;
|
||||||
|
$this->subscriptionInfo = $subscriptionInfo;
|
||||||
|
|
||||||
|
$required = [
|
||||||
|
'id',
|
||||||
|
'uri',
|
||||||
|
'principaluri',
|
||||||
|
'source',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($required as $r) {
|
||||||
|
if (!isset($subscriptionInfo[$r])) {
|
||||||
|
throw new \InvalidArgumentException('The ' . $r . ' field is required when creating a subscription node');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the node.
|
||||||
|
*
|
||||||
|
* This is used to generate the url.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function getName() {
|
||||||
|
|
||||||
|
return $this->subscriptionInfo['uri'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last modification time
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
function getLastModified() {
|
||||||
|
|
||||||
|
if (isset($this->subscriptionInfo['lastmodified'])) {
|
||||||
|
return $this->subscriptionInfo['lastmodified'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the current node
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function delete() {
|
||||||
|
|
||||||
|
$this->caldavBackend->deleteSubscription(
|
||||||
|
$this->subscriptionInfo['id']
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array with all the child nodes
|
||||||
|
*
|
||||||
|
* @return DAV\INode[]
|
||||||
|
*/
|
||||||
|
function getChildren() {
|
||||||
|
|
||||||
|
return [];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates properties on this node.
|
||||||
|
*
|
||||||
|
* This method received a PropPatch object, which contains all the
|
||||||
|
* information about the update.
|
||||||
|
*
|
||||||
|
* To update specific properties, call the 'handle' method on this object.
|
||||||
|
* Read the PropPatch documentation for more information.
|
||||||
|
*
|
||||||
|
* @param PropPatch $propPatch
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function propPatch(PropPatch $propPatch) {
|
||||||
|
|
||||||
|
return $this->caldavBackend->updateSubscription(
|
||||||
|
$this->subscriptionInfo['id'],
|
||||||
|
$propPatch
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of properties for this nodes.
|
||||||
|
*
|
||||||
|
* The properties list is a list of propertynames the client requested,
|
||||||
|
* encoded in clark-notation {xmlnamespace}tagname.
|
||||||
|
*
|
||||||
|
* If the array is empty, it means 'all properties' were requested.
|
||||||
|
*
|
||||||
|
* Note that it's fine to liberally give properties back, instead of
|
||||||
|
* conforming to the list of requested properties.
|
||||||
|
* The Server class will filter out the extra.
|
||||||
|
*
|
||||||
|
* @param array $properties
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function getProperties($properties) {
|
||||||
|
|
||||||
|
$r = [];
|
||||||
|
|
||||||
|
foreach ($properties as $prop) {
|
||||||
|
|
||||||
|
switch ($prop) {
|
||||||
|
case '{http://calendarserver.org/ns/}source' :
|
||||||
|
$r[$prop] = new Href($this->subscriptionInfo['source'], false);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
if (array_key_exists($prop, $this->subscriptionInfo)) {
|
||||||
|
$r[$prop] = $this->subscriptionInfo[$prop];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $r;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the owner principal.
|
||||||
|
*
|
||||||
|
* This must be a url to a principal, or null if there's no owner
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getOwner() {
|
||||||
|
|
||||||
|
return $this->subscriptionInfo['principaluri'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a group principal.
|
||||||
|
*
|
||||||
|
* This must be a url to a principal, or null if there's no owner
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
function getGroup() {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of ACE's for this node.
|
||||||
|
*
|
||||||
|
* Each ACE has the following properties:
|
||||||
|
* * 'privilege', a string such as {DAV:}read or {DAV:}write. These are
|
||||||
|
* currently the only supported privileges
|
||||||
|
* * 'principal', a url to the principal who owns the node
|
||||||
|
* * 'protected' (optional), indicating that this ACE is not allowed to
|
||||||
|
* be updated.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function getACL() {
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner(),
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}write',
|
||||||
|
'principal' => $this->getOwner(),
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}write',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-write',
|
||||||
|
'protected' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'privilege' => '{DAV:}read',
|
||||||
|
'principal' => $this->getOwner() . '/calendar-proxy-read',
|
||||||
|
'protected' => true,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the ACL.
|
||||||
|
*
|
||||||
|
* This method will receive a list of new ACE's.
|
||||||
|
*
|
||||||
|
* @param array $acl
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function setACL(array $acl) {
|
||||||
|
|
||||||
|
throw new MethodNotAllowed('Changing ACL is not yet supported');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of supported privileges for this node.
|
||||||
|
*
|
||||||
|
* The returned data structure is a list of nested privileges.
|
||||||
|
* See \Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple
|
||||||
|
* standard structure.
|
||||||
|
*
|
||||||
|
* If null is returned from this method, the default privilege set is used,
|
||||||
|
* which is fine for most common usecases.
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
function getSupportedPrivilegeSet() {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
84
vendor/sabre/dav/lib/CalDAV/Xml/Filter/CalendarData.php
vendored
Normal file
84
vendor/sabre/dav/lib/CalDAV/Xml/Filter/CalendarData.php
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Xml\Filter;
|
||||||
|
|
||||||
|
use Sabre\Xml\Reader;
|
||||||
|
use Sabre\Xml\XmlDeserializable;
|
||||||
|
use Sabre\DAV\Exception\BadRequest;
|
||||||
|
use Sabre\CalDAV\Plugin;
|
||||||
|
use Sabre\VObject\DateTimeParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CalendarData parser.
|
||||||
|
*
|
||||||
|
* This class parses the {urn:ietf:params:xml:ns:caldav}calendar-data XML
|
||||||
|
* element, as defined in:
|
||||||
|
*
|
||||||
|
* https://tools.ietf.org/html/rfc4791#section-9.6
|
||||||
|
*
|
||||||
|
* This element is used in three distinct places in the caldav spec, but in
|
||||||
|
* this case, this element class only implements the calendar-data element as
|
||||||
|
* it appears in a DAV:prop element, in a calendar-query or calendar-multiget
|
||||||
|
* REPORT request.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class CalendarData implements XmlDeserializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deserialize method is called during xml parsing.
|
||||||
|
*
|
||||||
|
* This method is called statictly, this is because in theory this method
|
||||||
|
* may be used as a type of constructor, or factory method.
|
||||||
|
*
|
||||||
|
* Often you want to return an instance of the current class, but you are
|
||||||
|
* free to return other data as well.
|
||||||
|
*
|
||||||
|
* You are responsible for advancing the reader to the next element. Not
|
||||||
|
* doing anything will result in a never-ending loop.
|
||||||
|
*
|
||||||
|
* If you just want to skip parsing for this element altogether, you can
|
||||||
|
* just call $reader->next();
|
||||||
|
*
|
||||||
|
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
|
||||||
|
* the next element.
|
||||||
|
*
|
||||||
|
* @param Reader $reader
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
static function xmlDeserialize(Reader $reader) {
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
'contentType' => $reader->getAttribute('content-type') ?: 'text/calendar',
|
||||||
|
'version' => $reader->getAttribute('version') ?: '2.0',
|
||||||
|
];
|
||||||
|
|
||||||
|
$elems = (array)$reader->parseInnerTree();
|
||||||
|
foreach ($elems as $elem) {
|
||||||
|
|
||||||
|
switch ($elem['name']) {
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}expand' :
|
||||||
|
|
||||||
|
$result['expand'] = [
|
||||||
|
'start' => isset($elem['attributes']['start']) ? DateTimeParser::parseDateTime($elem['attributes']['start']) : null,
|
||||||
|
'end' => isset($elem['attributes']['end']) ? DateTimeParser::parseDateTime($elem['attributes']['end']) : null,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!$result['expand']['start'] || !$result['expand']['end']) {
|
||||||
|
throw new BadRequest('The "start" and "end" attributes are required when expanding calendar-data');
|
||||||
|
}
|
||||||
|
if ($result['expand']['end'] <= $result['expand']['start']) {
|
||||||
|
throw new BadRequest('The end-date must be larger than the start-date when expanding calendar-data');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
97
vendor/sabre/dav/lib/CalDAV/Xml/Filter/CompFilter.php
vendored
Normal file
97
vendor/sabre/dav/lib/CalDAV/Xml/Filter/CompFilter.php
vendored
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Xml\Filter;
|
||||||
|
|
||||||
|
use Sabre\Xml\Reader;
|
||||||
|
use Sabre\Xml\XmlDeserializable;
|
||||||
|
use Sabre\DAV\Exception\BadRequest;
|
||||||
|
use Sabre\CalDAV\Plugin;
|
||||||
|
use Sabre\VObject\DateTimeParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CompFilter parser.
|
||||||
|
*
|
||||||
|
* This class parses the {urn:ietf:params:xml:ns:caldav}comp-filter XML
|
||||||
|
* element, as defined in:
|
||||||
|
*
|
||||||
|
* https://tools.ietf.org/html/rfc4791#section-9.6
|
||||||
|
*
|
||||||
|
* The result will be spit out as an array.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class CompFilter implements XmlDeserializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deserialize method is called during xml parsing.
|
||||||
|
*
|
||||||
|
* This method is called statictly, this is because in theory this method
|
||||||
|
* may be used as a type of constructor, or factory method.
|
||||||
|
*
|
||||||
|
* Often you want to return an instance of the current class, but you are
|
||||||
|
* free to return other data as well.
|
||||||
|
*
|
||||||
|
* You are responsible for advancing the reader to the next element. Not
|
||||||
|
* doing anything will result in a never-ending loop.
|
||||||
|
*
|
||||||
|
* If you just want to skip parsing for this element altogether, you can
|
||||||
|
* just call $reader->next();
|
||||||
|
*
|
||||||
|
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
|
||||||
|
* the next element.
|
||||||
|
*
|
||||||
|
* @param Reader $reader
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
static function xmlDeserialize(Reader $reader) {
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
'name' => null,
|
||||||
|
'is-not-defined' => false,
|
||||||
|
'comp-filters' => [],
|
||||||
|
'prop-filters' => [],
|
||||||
|
'time-range' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
$att = $reader->parseAttributes();
|
||||||
|
$result['name'] = $att['name'];
|
||||||
|
|
||||||
|
$elems = $reader->parseInnerTree();
|
||||||
|
|
||||||
|
if (is_array($elems)) foreach ($elems as $elem) {
|
||||||
|
|
||||||
|
switch ($elem['name']) {
|
||||||
|
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}comp-filter' :
|
||||||
|
$result['comp-filters'][] = $elem['value'];
|
||||||
|
break;
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}prop-filter' :
|
||||||
|
$result['prop-filters'][] = $elem['value'];
|
||||||
|
break;
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}is-not-defined' :
|
||||||
|
$result['is-not-defined'] = true;
|
||||||
|
break;
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}time-range' :
|
||||||
|
if ($result['name'] === 'VCALENDAR') {
|
||||||
|
throw new BadRequest('You cannot add time-range filters on the VCALENDAR component');
|
||||||
|
}
|
||||||
|
$result['time-range'] = [
|
||||||
|
'start' => isset($elem['attributes']['start']) ? DateTimeParser::parseDateTime($elem['attributes']['start']) : null,
|
||||||
|
'end' => isset($elem['attributes']['end']) ? DateTimeParser::parseDateTime($elem['attributes']['end']) : null,
|
||||||
|
];
|
||||||
|
if ($result['time-range']['start'] && $result['time-range']['end'] && $result['time-range']['end'] <= $result['time-range']['start']) {
|
||||||
|
throw new BadRequest('The end-date must be larger than the start-date');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
82
vendor/sabre/dav/lib/CalDAV/Xml/Filter/ParamFilter.php
vendored
Normal file
82
vendor/sabre/dav/lib/CalDAV/Xml/Filter/ParamFilter.php
vendored
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Xml\Filter;
|
||||||
|
|
||||||
|
use Sabre\Xml\Reader;
|
||||||
|
use Sabre\Xml\XmlDeserializable;
|
||||||
|
use Sabre\CalDAV\Plugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PropFilter parser.
|
||||||
|
*
|
||||||
|
* This class parses the {urn:ietf:params:xml:ns:caldav}param-filter XML
|
||||||
|
* element, as defined in:
|
||||||
|
*
|
||||||
|
* https://tools.ietf.org/html/rfc4791#section-9.7.3
|
||||||
|
*
|
||||||
|
* The result will be spit out as an array.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class ParamFilter implements XmlDeserializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deserialize method is called during xml parsing.
|
||||||
|
*
|
||||||
|
* This method is called statictly, this is because in theory this method
|
||||||
|
* may be used as a type of constructor, or factory method.
|
||||||
|
*
|
||||||
|
* Often you want to return an instance of the current class, but you are
|
||||||
|
* free to return other data as well.
|
||||||
|
*
|
||||||
|
* Important note 2: You are responsible for advancing the reader to the
|
||||||
|
* next element. Not doing anything will result in a never-ending loop.
|
||||||
|
*
|
||||||
|
* If you just want to skip parsing for this element altogether, you can
|
||||||
|
* just call $reader->next();
|
||||||
|
*
|
||||||
|
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
|
||||||
|
* the next element.
|
||||||
|
*
|
||||||
|
* @param Reader $reader
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
static function xmlDeserialize(Reader $reader) {
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
'name' => null,
|
||||||
|
'is-not-defined' => false,
|
||||||
|
'text-match' => null,
|
||||||
|
];
|
||||||
|
|
||||||
|
$att = $reader->parseAttributes();
|
||||||
|
$result['name'] = $att['name'];
|
||||||
|
|
||||||
|
$elems = $reader->parseInnerTree();
|
||||||
|
|
||||||
|
if (is_array($elems)) foreach ($elems as $elem) {
|
||||||
|
|
||||||
|
switch ($elem['name']) {
|
||||||
|
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}is-not-defined' :
|
||||||
|
$result['is-not-defined'] = true;
|
||||||
|
break;
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}text-match' :
|
||||||
|
$result['text-match'] = [
|
||||||
|
'negate-condition' => isset($elem['attributes']['negate-condition']) && $elem['attributes']['negate-condition'] === 'yes',
|
||||||
|
'collation' => isset($elem['attributes']['collation']) ? $elem['attributes']['collation'] : 'i;ascii-casemap',
|
||||||
|
'value' => $elem['value'],
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
98
vendor/sabre/dav/lib/CalDAV/Xml/Filter/PropFilter.php
vendored
Normal file
98
vendor/sabre/dav/lib/CalDAV/Xml/Filter/PropFilter.php
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Sabre\CalDAV\Xml\Filter;
|
||||||
|
|
||||||
|
use Sabre\Xml\Reader;
|
||||||
|
use Sabre\Xml\XmlDeserializable;
|
||||||
|
use Sabre\DAV\Exception\BadRequest;
|
||||||
|
use Sabre\CalDAV\Plugin;
|
||||||
|
use Sabre\VObject\DateTimeParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PropFilter parser.
|
||||||
|
*
|
||||||
|
* This class parses the {urn:ietf:params:xml:ns:caldav}prop-filter XML
|
||||||
|
* element, as defined in:
|
||||||
|
*
|
||||||
|
* https://tools.ietf.org/html/rfc4791#section-9.7.2
|
||||||
|
*
|
||||||
|
* The result will be spit out as an array.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) fruux GmbH (https://fruux.com/)
|
||||||
|
* @author Evert Pot (http://www.rooftopsolutions.nl/)
|
||||||
|
* @license http://sabre.io/license/ Modified BSD License
|
||||||
|
*/
|
||||||
|
class PropFilter implements XmlDeserializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deserialize method is called during xml parsing.
|
||||||
|
*
|
||||||
|
* This method is called statictly, this is because in theory this method
|
||||||
|
* may be used as a type of constructor, or factory method.
|
||||||
|
*
|
||||||
|
* Often you want to return an instance of the current class, but you are
|
||||||
|
* free to return other data as well.
|
||||||
|
*
|
||||||
|
* You are responsible for advancing the reader to the next element. Not
|
||||||
|
* doing anything will result in a never-ending loop.
|
||||||
|
*
|
||||||
|
* If you just want to skip parsing for this element altogether, you can
|
||||||
|
* just call $reader->next();
|
||||||
|
*
|
||||||
|
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
|
||||||
|
* the next element.
|
||||||
|
*
|
||||||
|
* @param Reader $reader
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
static function xmlDeserialize(Reader $reader) {
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
'name' => null,
|
||||||
|
'is-not-defined' => false,
|
||||||
|
'param-filters' => [],
|
||||||
|
'text-match' => null,
|
||||||
|
'time-range' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
$att = $reader->parseAttributes();
|
||||||
|
$result['name'] = $att['name'];
|
||||||
|
|
||||||
|
$elems = $reader->parseInnerTree();
|
||||||
|
|
||||||
|
if (is_array($elems)) foreach ($elems as $elem) {
|
||||||
|
|
||||||
|
switch ($elem['name']) {
|
||||||
|
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}param-filter' :
|
||||||
|
$result['param-filters'][] = $elem['value'];
|
||||||
|
break;
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}is-not-defined' :
|
||||||
|
$result['is-not-defined'] = true;
|
||||||
|
break;
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}time-range' :
|
||||||
|
$result['time-range'] = [
|
||||||
|
'start' => isset($elem['attributes']['start']) ? DateTimeParser::parseDateTime($elem['attributes']['start']) : null,
|
||||||
|
'end' => isset($elem['attributes']['end']) ? DateTimeParser::parseDateTime($elem['attributes']['end']) : null,
|
||||||
|
];
|
||||||
|
if ($result['time-range']['start'] && $result['time-range']['end'] && $result['time-range']['end'] <= $result['time-range']['start']) {
|
||||||
|
throw new BadRequest('The end-date must be larger than the start-date');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '{' . Plugin::NS_CALDAV . '}text-match' :
|
||||||
|
$result['text-match'] = [
|
||||||
|
'negate-condition' => isset($elem['attributes']['negate-condition']) && $elem['attributes']['negate-condition'] === 'yes',
|
||||||
|
'collation' => isset($elem['attributes']['collation']) ? $elem['attributes']['collation'] : 'i;ascii-casemap',
|
||||||
|
'value' => $elem['value'],
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user