Merge pull request #14151 from owncloud/update-sabre2.1
Sabre Update to 2.1
This commit is contained in:
commit
799e144b04
2
3rdparty
2
3rdparty
|
@ -1 +1 @@
|
|||
Subproject commit 59f092231c6036838746262a4db80997908bb06f
|
||||
Subproject commit 588b1308f4abf58acb3bb8519f6952d9890cca89
|
|
@ -27,37 +27,47 @@
|
|||
*
|
||||
*/
|
||||
// Backends
|
||||
$authBackend = new OC_Connector_Sabre_Auth();
|
||||
$lockBackend = new OC_Connector_Sabre_Locks();
|
||||
$requestBackend = new OC_Connector_Sabre_Request();
|
||||
$authBackend = new \OC\Connector\Sabre\Auth();
|
||||
|
||||
// Fire up server
|
||||
$objectTree = new \OC\Connector\Sabre\ObjectTree();
|
||||
$server = new OC_Connector_Sabre_Server($objectTree);
|
||||
$server->httpRequest = $requestBackend;
|
||||
$server = new \OC\Connector\Sabre\Server($objectTree);
|
||||
// Set URL explicitly due to reverse-proxy situations
|
||||
$server->httpRequest->setUrl(\OC::$server->getRequest()->getRequestUri());
|
||||
$server->setBaseUri($baseuri);
|
||||
|
||||
// Load plugins
|
||||
$defaults = new OC_Defaults();
|
||||
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, $defaults->getName()));
|
||||
$server->addPlugin(new \Sabre\DAV\Locks\Plugin($lockBackend));
|
||||
$server->addPlugin(new \Sabre\DAV\Browser\Plugin(false, false)); // Show something in the Browser, but no upload
|
||||
$server->addPlugin(new OC_Connector_Sabre_FilesPlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
|
||||
// FIXME: The following line is a workaround for legacy components relying on being able to send a GET to /
|
||||
$server->addPlugin(new \OC\Connector\Sabre\DummyGetResponsePlugin());
|
||||
$server->addPlugin(new \OC\Connector\Sabre\FilesPlugin($objectTree));
|
||||
$server->addPlugin(new \OC\Connector\Sabre\MaintenancePlugin());
|
||||
$server->addPlugin(new \OC\Connector\Sabre\ExceptionLoggerPlugin('webdav'));
|
||||
|
||||
// wait with registering these until auth is handled and the filesystem is setup
|
||||
$server->subscribeEvent('beforeMethod', function () use ($server, $objectTree) {
|
||||
$server->on('beforeMethod', function () use ($server, $objectTree) {
|
||||
$view = \OC\Files\Filesystem::getView();
|
||||
$rootInfo = $view->getFileInfo('');
|
||||
|
||||
// Create ownCloud Dir
|
||||
$mountManager = \OC\Files\Filesystem::getMountManager();
|
||||
$rootDir = new OC_Connector_Sabre_Directory($view, $rootInfo);
|
||||
$rootDir = new \OC\Connector\Sabre\Directory($view, $rootInfo);
|
||||
$objectTree->init($rootDir, $view, $mountManager);
|
||||
|
||||
$server->addPlugin(new \OC\Connector\Sabre\TagsPlugin($objectTree, \OC::$server->getTagManager()));
|
||||
$server->addPlugin(new OC_Connector_Sabre_QuotaPlugin($view));
|
||||
$server->addPlugin(new \OC\Connector\Sabre\QuotaPlugin($view));
|
||||
|
||||
// custom properties plugin must be the last one
|
||||
$server->addPlugin(
|
||||
new \Sabre\DAV\PropertyStorage\Plugin(
|
||||
new \OC\Connector\Sabre\CustomPropertiesBackend(
|
||||
$objectTree,
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
\OC::$server->getUserSession()->getUser()
|
||||
)
|
||||
)
|
||||
);
|
||||
}, 30); // priority 30: after auth (10) and acl(20), before lock(50) and handling the request
|
||||
|
||||
// And off we go!
|
||||
|
|
|
@ -1,274 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Bjoern Schiessle <schiessle@owncloud.com>
|
||||
* @author Christopher Schäpers <kondou@ts.unde.re>
|
||||
* @author Florin Peter <github@florin-peter.de>
|
||||
* @author Joas Schilling <nickvergessen@gmx.de>
|
||||
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
|
||||
* @author Lukas Reschke <lukas@owncloud.com>
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Robin Appelman <icewind@owncloud.com>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
namespace OCA\Files_Encryption\Tests;
|
||||
|
||||
/**
|
||||
* Class Webdav
|
||||
*
|
||||
* this class provide basic webdav tests for PUT,GET and DELETE
|
||||
*/
|
||||
class Webdav extends TestCase {
|
||||
|
||||
const TEST_ENCRYPTION_WEBDAV_USER1 = "test-webdav-user1";
|
||||
|
||||
public $userId;
|
||||
public $pass;
|
||||
/**
|
||||
* @var \OC\Files\View
|
||||
*/
|
||||
public $view;
|
||||
public $dataShort;
|
||||
public $stateFilesTrashbin;
|
||||
|
||||
private $storage;
|
||||
|
||||
public static function setUpBeforeClass() {
|
||||
parent::setUpBeforeClass();
|
||||
|
||||
// create test user
|
||||
self::loginHelper(self::TEST_ENCRYPTION_WEBDAV_USER1, true);
|
||||
|
||||
}
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// reset backend
|
||||
\OC_User::useBackend('database');
|
||||
|
||||
// set user id
|
||||
\OC_User::setUserId(self::TEST_ENCRYPTION_WEBDAV_USER1);
|
||||
$this->userId = self::TEST_ENCRYPTION_WEBDAV_USER1;
|
||||
$this->pass = self::TEST_ENCRYPTION_WEBDAV_USER1;
|
||||
|
||||
// init filesystem view
|
||||
$this->view = new \OC\Files\View('/');
|
||||
list($this->storage, ) = $this->view->resolvePath('/');
|
||||
// init short data
|
||||
$this->dataShort = 'hats';
|
||||
|
||||
// remember files_trashbin state
|
||||
$this->stateFilesTrashbin = \OC_App::isEnabled('files_trashbin');
|
||||
|
||||
// we don't want to tests with app files_trashbin enabled
|
||||
\OC_App::disable('files_trashbin');
|
||||
|
||||
// create test user
|
||||
self::loginHelper(self::TEST_ENCRYPTION_WEBDAV_USER1);
|
||||
}
|
||||
|
||||
protected function tearDown() {
|
||||
// reset app files_trashbin
|
||||
if ($this->stateFilesTrashbin) {
|
||||
\OC_App::enable('files_trashbin');
|
||||
} else {
|
||||
\OC_App::disable('files_trashbin');
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass() {
|
||||
// cleanup test user
|
||||
\OC_User::deleteUser(self::TEST_ENCRYPTION_WEBDAV_USER1);
|
||||
|
||||
parent::tearDownAfterClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* test webdav put random file
|
||||
*/
|
||||
function testWebdavPUT() {
|
||||
|
||||
// generate filename
|
||||
$filename = '/tmp-' . $this->getUniqueID() . '.txt';
|
||||
|
||||
// set server vars
|
||||
$_SERVER['REQUEST_METHOD'] = 'OPTIONS';
|
||||
|
||||
$_SERVER['REQUEST_METHOD'] = 'PUT';
|
||||
$_SERVER['REQUEST_URI'] = '/remote.php/webdav' . $filename;
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = 'Basic dGVzdC13ZWJkYXYtdXNlcjE6dGVzdC13ZWJkYXYtdXNlcjE=';
|
||||
$_SERVER['CONTENT_TYPE'] = 'application/octet-stream';
|
||||
$_SERVER['PATH_INFO'] = '/webdav' . $filename;
|
||||
$_SERVER['CONTENT_LENGTH'] = strlen($this->dataShort);
|
||||
|
||||
// handle webdav request
|
||||
$this->handleWebdavRequest($this->dataShort);
|
||||
|
||||
// check if file was created
|
||||
$this->assertTrue($this->view->file_exists('/' . $this->userId . '/files' . $filename));
|
||||
|
||||
// check if key-file was created
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . $this->userId . '/files_encryption/keys/' . $filename . '/fileKey'));
|
||||
|
||||
// check if shareKey-file was created
|
||||
$this->assertTrue($this->view->file_exists(
|
||||
'/' . $this->userId . '/files_encryption/keys/' . $filename . '/' . $this->userId . '.shareKey'));
|
||||
|
||||
// disable encryption proxy to prevent recursive calls
|
||||
$proxyStatus = \OC_FileProxy::$enabled;
|
||||
\OC_FileProxy::$enabled = false;
|
||||
|
||||
// get encrypted file content
|
||||
$encryptedContent = $this->view->file_get_contents('/' . $this->userId . '/files' . $filename);
|
||||
|
||||
// restore proxy state
|
||||
\OC_FileProxy::$enabled = $proxyStatus;
|
||||
|
||||
// check if encrypted content is valid
|
||||
$this->assertTrue(\OCA\Files_Encryption\Crypt::isCatfileContent($encryptedContent));
|
||||
|
||||
// get decrypted file contents
|
||||
$decrypt = file_get_contents('crypt:///' . $this->userId . '/files' . $filename);
|
||||
|
||||
// check if file content match with the written content
|
||||
$this->assertEquals($this->dataShort, $decrypt);
|
||||
|
||||
// return filename for next test
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* test webdav get random file
|
||||
*
|
||||
* @depends testWebdavPUT
|
||||
*/
|
||||
function testWebdavGET($filename) {
|
||||
|
||||
// set server vars
|
||||
$_SERVER['REQUEST_METHOD'] = 'GET';
|
||||
$_SERVER['REQUEST_URI'] = '/remote.php/webdav' . $filename;
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = 'Basic dGVzdC13ZWJkYXYtdXNlcjE6dGVzdC13ZWJkYXYtdXNlcjE=';
|
||||
$_SERVER['PATH_INFO'] = '/webdav' . $filename;
|
||||
|
||||
// handle webdav request
|
||||
$content = $this->handleWebdavRequest();
|
||||
|
||||
// check if file content match with the written content
|
||||
$this->assertEquals($this->dataShort, $content);
|
||||
|
||||
// return filename for next test
|
||||
return $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* test webdav delete random file
|
||||
* @depends testWebdavGET
|
||||
*/
|
||||
function testWebdavDELETE($filename) {
|
||||
// set server vars
|
||||
$_SERVER['REQUEST_METHOD'] = 'DELETE';
|
||||
$_SERVER['REQUEST_URI'] = '/remote.php/webdav' . $filename;
|
||||
$_SERVER['HTTP_AUTHORIZATION'] = 'Basic dGVzdC13ZWJkYXYtdXNlcjE6dGVzdC13ZWJkYXYtdXNlcjE=';
|
||||
$_SERVER['PATH_INFO'] = '/webdav' . $filename;
|
||||
|
||||
// at the beginning the file should exist
|
||||
$this->assertTrue($this->view->file_exists('/' . $this->userId . '/files' . $filename));
|
||||
|
||||
// handle webdav request
|
||||
$content = $this->handleWebdavRequest();
|
||||
|
||||
// check if file was removed
|
||||
$this->assertFalse($this->view->file_exists('/' . $this->userId . '/files' . $filename));
|
||||
|
||||
// check if key-file was removed
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . $this->userId . '/files_encryption/keys/' . $filename . '/fileKey'));
|
||||
|
||||
// check if shareKey-file was removed
|
||||
$this->assertFalse($this->view->file_exists(
|
||||
'/' . $this->userId . '/files_encryption/keys/' . $filename . '/' . $this->userId . '.shareKey'));
|
||||
}
|
||||
|
||||
/**
|
||||
* handle webdav request
|
||||
*
|
||||
* @param bool $body
|
||||
* @note this init procedure is copied from /apps/files/appinfo/remote.php
|
||||
*/
|
||||
function handleWebdavRequest($body = false) {
|
||||
// Backends
|
||||
$authBackend = $this->getMockBuilder('OC_Connector_Sabre_Auth')
|
||||
->setMethods(['validateUserPass'])
|
||||
->getMock();
|
||||
$authBackend->expects($this->any())
|
||||
->method('validateUserPass')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
$lockBackend = new \OC_Connector_Sabre_Locks();
|
||||
$requestBackend = new \OC_Connector_Sabre_Request();
|
||||
|
||||
// Create ownCloud Dir
|
||||
$root = '/' . $this->userId . '/files';
|
||||
$view = new \OC\Files\View($root);
|
||||
$publicDir = new \OC_Connector_Sabre_Directory($view, $view->getFileInfo(''));
|
||||
$objectTree = new \OC\Connector\Sabre\ObjectTree();
|
||||
$mountManager = \OC\Files\Filesystem::getMountManager();
|
||||
$objectTree->init($publicDir, $view, $mountManager);
|
||||
|
||||
// Fire up server
|
||||
$server = new \Sabre\DAV\Server($publicDir);
|
||||
$server->httpRequest = $requestBackend;
|
||||
$server->setBaseUri('/remote.php/webdav/');
|
||||
|
||||
// Load plugins
|
||||
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, 'ownCloud'));
|
||||
$server->addPlugin(new \Sabre\DAV\Locks\Plugin($lockBackend));
|
||||
$server->addPlugin(new \Sabre\DAV\Browser\Plugin(false)); // Show something in the Browser, but no upload
|
||||
$server->addPlugin(new \OC_Connector_Sabre_QuotaPlugin($view));
|
||||
$server->addPlugin(new \OC_Connector_Sabre_MaintenancePlugin());
|
||||
$server->debugExceptions = true;
|
||||
|
||||
// Totally ugly hack to setup the FS
|
||||
\OC::$server->getUserSession()->login($this->userId, $this->userId);
|
||||
\OC_Util::setupFS($this->userId);
|
||||
|
||||
// And off we go!
|
||||
if ($body) {
|
||||
$server->httpRequest->setBody($body);
|
||||
}
|
||||
|
||||
// turn on output buffering
|
||||
ob_start();
|
||||
|
||||
// handle request
|
||||
$server->exec();
|
||||
|
||||
// file content is written in the output buffer
|
||||
$content = ob_get_contents();
|
||||
|
||||
// flush the output buffer and turn off output buffering
|
||||
ob_end_clean();
|
||||
|
||||
// return captured content
|
||||
return $content;
|
||||
}
|
||||
}
|
|
@ -34,26 +34,24 @@ OC_Util::obEnd();
|
|||
|
||||
// Backends
|
||||
$authBackend = new OCA\Files_Sharing\Connector\PublicAuth(\OC::$server->getConfig());
|
||||
$lockBackend = new OC_Connector_Sabre_Locks();
|
||||
$requestBackend = new OC_Connector_Sabre_Request();
|
||||
|
||||
// Fire up server
|
||||
$objectTree = new \OC\Connector\Sabre\ObjectTree();
|
||||
$server = new OC_Connector_Sabre_Server($objectTree);
|
||||
$server->httpRequest = $requestBackend;
|
||||
$server = new \OC\Connector\Sabre\Server($objectTree);
|
||||
// Set URL explicitly due to reverse-proxy situations
|
||||
$server->httpRequest->setUrl(\OC::$server->getRequest()->getRequestUri());
|
||||
$server->setBaseUri($baseuri);
|
||||
|
||||
// Load plugins
|
||||
$defaults = new OC_Defaults();
|
||||
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend, $defaults->getName()));
|
||||
$server->addPlugin(new \Sabre\DAV\Locks\Plugin($lockBackend));
|
||||
$server->addPlugin(new \Sabre\DAV\Browser\Plugin(false)); // Show something in the Browser, but no upload
|
||||
$server->addPlugin(new OC_Connector_Sabre_FilesPlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_MaintenancePlugin());
|
||||
$server->addPlugin(new OC_Connector_Sabre_ExceptionLoggerPlugin('webdav'));
|
||||
$server->addPlugin(new \OC\Connector\Sabre\FilesPlugin($objectTree));
|
||||
$server->addPlugin(new \OC\Connector\Sabre\MaintenancePlugin());
|
||||
$server->addPlugin(new \OC\Connector\Sabre\ExceptionLoggerPlugin('webdav'));
|
||||
|
||||
// wait with registering these until auth is handled and the filesystem is setup
|
||||
$server->subscribeEvent('beforeMethod', function () use ($server, $objectTree, $authBackend) {
|
||||
$server->on('beforeMethod', function () use ($server, $objectTree, $authBackend) {
|
||||
$share = $authBackend->getShare();
|
||||
$owner = $share['uid_owner'];
|
||||
$isWritable = $share['permissions'] & (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_CREATE);
|
||||
|
@ -74,14 +72,14 @@ $server->subscribeEvent('beforeMethod', function () use ($server, $objectTree, $
|
|||
|
||||
// Create ownCloud Dir
|
||||
if ($rootInfo->getType() === 'dir') {
|
||||
$root = new OC_Connector_Sabre_Directory($view, $rootInfo);
|
||||
$root = new \OC\Connector\Sabre\Directory($view, $rootInfo);
|
||||
} else {
|
||||
$root = new OC_Connector_Sabre_File($view, $rootInfo);
|
||||
$root = new \OC\Connector\Sabre\File($view, $rootInfo);
|
||||
}
|
||||
$mountManager = \OC\Files\Filesystem::getMountManager();
|
||||
$objectTree->init($root, $view, $mountManager);
|
||||
|
||||
$server->addPlugin(new OC_Connector_Sabre_QuotaPlugin($view));
|
||||
$server->addPlugin(new \OC\Connector\Sabre\QuotaPlugin($view));
|
||||
}, 30); // priority 30: after auth (10) and acl(20), before lock(50) and handling the request
|
||||
|
||||
// And off we go!
|
||||
|
|
|
@ -543,7 +543,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
|
|||
|
||||
// strip off the script name's dir and file name
|
||||
// FIXME: Sabre does not really belong here
|
||||
list($path, $name) = \Sabre\DAV\URLUtil::splitPath($scriptName);
|
||||
list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($scriptName);
|
||||
if (!empty($path)) {
|
||||
if($path === $pathInfo || strpos($pathInfo, $path.'/') === 0) {
|
||||
$pathInfo = substr($pathInfo, strlen($path));
|
||||
|
@ -575,7 +575,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
|
|||
}
|
||||
|
||||
$pathInfo = $this->getRawPathInfo();
|
||||
// following is taken from \Sabre\DAV\URLUtil::decodePathSegment
|
||||
// following is taken from \Sabre\HTTP\URLUtil::decodePathSegment
|
||||
$pathInfo = rawurldecode($pathInfo);
|
||||
$encoding = mb_detect_encoding($pathInfo, ['UTF-8', 'ISO-8859-1']);
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ class AppEnabledPlugin extends ServerPlugin {
|
|||
public function initialize(\Sabre\DAV\Server $server) {
|
||||
|
||||
$this->server = $server;
|
||||
$this->server->subscribeEvent('beforeMethod', array($this, 'checkAppEnabled'), 30);
|
||||
$this->server->on('beforeMethod', array($this, 'checkAppEnabled'), 30);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,31 +1,7 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Arthur Schiwon <blizzz@owncloud.com>
|
||||
* @author Bart Visscher <bartv@thisnet.nl>
|
||||
* @author Jakob Sack <mail@jakobsack.de>
|
||||
* @author Lukas Reschke <lukas@owncloud.com>
|
||||
* @author Markus Goetz <markus@woboq.com>
|
||||
* @author Michael Gapczynski <gapczynskim@gmail.com>
|
||||
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
class Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
|
||||
const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND';
|
||||
|
||||
/**
|
||||
|
@ -55,19 +31,19 @@ class OC_Connector_Sabre_Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
|
|||
* @return bool
|
||||
*/
|
||||
protected function validateUserPass($username, $password) {
|
||||
if (OC_User::isLoggedIn() &&
|
||||
$this->isDavAuthenticated(OC_User::getUser())
|
||||
if (\OC_User::isLoggedIn() &&
|
||||
$this->isDavAuthenticated(\OC_User::getUser())
|
||||
) {
|
||||
OC_Util::setupFS(OC_User::getUser());
|
||||
\OC_Util::setupFS(\OC_User::getUser());
|
||||
\OC::$server->getSession()->close();
|
||||
return true;
|
||||
} else {
|
||||
OC_Util::setUpFS(); //login hooks may need early access to the filesystem
|
||||
if(OC_User::login($username, $password)) {
|
||||
\OC_Util::setUpFS(); //login hooks may need early access to the filesystem
|
||||
if(\OC_User::login($username, $password)) {
|
||||
// make sure we use owncloud's internal username here
|
||||
// and not the HTTP auth supplied one, see issue #14048
|
||||
$ocUser = OC_User::getUser();
|
||||
OC_Util::setUpFS($ocUser);
|
||||
$ocUser = \OC_User::getUser();
|
||||
\OC_Util::setUpFS($ocUser);
|
||||
\OC::$server->getSession()->set(self::DAV_AUTHENTICATED, $ocUser);
|
||||
\OC::$server->getSession()->close();
|
||||
return true;
|
||||
|
@ -86,7 +62,7 @@ class OC_Connector_Sabre_Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
|
|||
* @return string|null
|
||||
*/
|
||||
public function getCurrentUser() {
|
||||
$user = OC_User::getUser();
|
||||
$user = \OC_User::getUser();
|
||||
if($user && $this->isDavAuthenticated($user)) {
|
||||
return $user;
|
||||
}
|
||||
|
@ -117,11 +93,11 @@ class OC_Connector_Sabre_Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
|
|||
* @return bool
|
||||
*/
|
||||
private function auth(\Sabre\DAV\Server $server, $realm) {
|
||||
if (OC_User::handleApacheAuth() ||
|
||||
(OC_User::isLoggedIn() && is_null(\OC::$server->getSession()->get(self::DAV_AUTHENTICATED)))
|
||||
if (\OC_User::handleApacheAuth() ||
|
||||
(\OC_User::isLoggedIn() && is_null(\OC::$server->getSession()->get(self::DAV_AUTHENTICATED)))
|
||||
) {
|
||||
$user = OC_User::getUser();
|
||||
OC_Util::setupFS($user);
|
||||
$user = \OC_User::getUser();
|
||||
\OC_Util::setupFS($user);
|
||||
$this->currentUser = $user;
|
||||
\OC::$server->getSession()->close();
|
||||
return true;
|
||||
|
|
|
@ -0,0 +1,347 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Vincent Petry
|
||||
* @copyright 2015 Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
use \Sabre\DAV\PropFind;
|
||||
use \Sabre\DAV\PropPatch;
|
||||
use \Sabre\HTTP\RequestInterface;
|
||||
use \Sabre\HTTP\ResponseInterface;
|
||||
|
||||
class CustomPropertiesBackend implements \Sabre\DAV\PropertyStorage\Backend\BackendInterface {
|
||||
|
||||
/**
|
||||
* Ignored properties
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $ignoredProperties = array(
|
||||
'{DAV:}getcontentlength',
|
||||
'{DAV:}getcontenttype',
|
||||
'{DAV:}getetag',
|
||||
'{DAV:}quota-used-bytes',
|
||||
'{DAV:}quota-available-bytes',
|
||||
'{DAV:}quota-available-bytes',
|
||||
'{http://owncloud.org/ns}permissions',
|
||||
'{http://owncloud.org/ns}downloadURL',
|
||||
'{http://owncloud.org/ns}dDC',
|
||||
'{http://owncloud.org/ns}size',
|
||||
);
|
||||
|
||||
/**
|
||||
* @var \Sabre\DAV\Tree
|
||||
*/
|
||||
private $tree;
|
||||
|
||||
/**
|
||||
* @var \OCP\IDBConnection
|
||||
*/
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @var \OCP\IUser
|
||||
*/
|
||||
private $user;
|
||||
|
||||
/**
|
||||
* Properties cache
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $cache = [];
|
||||
|
||||
/**
|
||||
* @param \Sabre\DAV\Tree $tree node tree
|
||||
* @param \OCP\IDBConnection $connection database connection
|
||||
* @param \OCP\IUser $user owner of the tree and properties
|
||||
*/
|
||||
public function __construct(
|
||||
\Sabre\DAV\Tree $tree,
|
||||
\OCP\IDBConnection $connection,
|
||||
\OCP\IUser $user) {
|
||||
$this->tree = $tree;
|
||||
$this->connection = $connection;
|
||||
$this->user = $user->getUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches properties for a path.
|
||||
*
|
||||
* @param string $path
|
||||
* @param PropFind $propFind
|
||||
* @return void
|
||||
*/
|
||||
public function propFind($path, PropFind $propFind) {
|
||||
$node = $this->tree->getNodeForPath($path);
|
||||
if (!($node instanceof \OC\Connector\Sabre\Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$requestedProps = $propFind->get404Properties();
|
||||
|
||||
// these might appear
|
||||
$requestedProps = array_diff(
|
||||
$requestedProps,
|
||||
$this->ignoredProperties
|
||||
);
|
||||
|
||||
if (empty($requestedProps)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($node instanceof \OC\Connector\Sabre\Directory
|
||||
&& $propFind->getDepth() !== 0
|
||||
) {
|
||||
// note: pre-fetching only supported for depth <= 1
|
||||
$this->loadChildrenProperties($node, $requestedProps);
|
||||
}
|
||||
|
||||
$props = $this->getProperties($node, $requestedProps);
|
||||
foreach ($props as $propName => $propValue) {
|
||||
$propFind->set($propName, $propValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates properties for a path
|
||||
*
|
||||
* @param string $path
|
||||
* @param PropPatch $propPatch
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function propPatch($path, PropPatch $propPatch) {
|
||||
$node = $this->tree->getNodeForPath($path);
|
||||
if (!($node instanceof \OC\Connector\Sabre\Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$propPatch->handleRemaining(function($changedProps) use ($node) {
|
||||
return $this->updateProperties($node, $changedProps);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called after a node is deleted.
|
||||
*
|
||||
* @param string $path path of node for which to delete properties
|
||||
*/
|
||||
public function delete($path) {
|
||||
$statement = $this->connection->prepare(
|
||||
'DELETE FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?'
|
||||
);
|
||||
$statement->execute(array($this->user, '/' . $path));
|
||||
$statement->closeCursor();
|
||||
|
||||
unset($this->cache[$path]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called after a successful MOVE
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $destination
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function move($source, $destination) {
|
||||
$statement = $this->connection->prepare(
|
||||
'UPDATE `*PREFIX*properties` SET `propertypath` = ?' .
|
||||
' WHERE `userid` = ? AND `propertypath` = ?'
|
||||
);
|
||||
$statement->execute(array('/' . $destination, $this->user, '/' . $source));
|
||||
$statement->closeCursor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of properties for this nodes.;
|
||||
* @param \OC\Connector\Sabre\Node $node
|
||||
* @param array $requestedProperties requested properties or empty array for "all"
|
||||
* @return array
|
||||
* @note The properties list is a list of propertynames the client
|
||||
* requested, encoded as xmlnamespace#tagName, for example:
|
||||
* http://www.example.org/namespace#author If the array is empty, all
|
||||
* properties should be returned
|
||||
*/
|
||||
private function getProperties(\OC\Connector\Sabre\Node $node, array $requestedProperties) {
|
||||
$path = $node->getPath();
|
||||
if (isset($this->cache[$path])) {
|
||||
return $this->cache[$path];
|
||||
}
|
||||
|
||||
// TODO: chunking if more than 1000 properties
|
||||
$sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?';
|
||||
|
||||
$whereValues = array($this->user, $path);
|
||||
$whereTypes = array(null, null);
|
||||
|
||||
if (!empty($requestedProperties)) {
|
||||
// request only a subset
|
||||
$sql .= ' AND `propertyname` in (?)';
|
||||
$whereValues[] = $requestedProperties;
|
||||
$whereTypes[] = \Doctrine\DBAL\Connection::PARAM_STR_ARRAY;
|
||||
}
|
||||
|
||||
$result = $this->connection->executeQuery(
|
||||
$sql,
|
||||
$whereValues,
|
||||
$whereTypes
|
||||
);
|
||||
|
||||
$props = [];
|
||||
while ($row = $result->fetch()) {
|
||||
$props[$row['propertyname']] = $row['propertyvalue'];
|
||||
}
|
||||
|
||||
$result->closeCursor();
|
||||
|
||||
$this->cache[$path] = $props;
|
||||
return $props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update properties
|
||||
*
|
||||
* @param \OC\Connector\Sabre\Node $node node for which to update properties
|
||||
* @param array $properties array of properties to update
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function updateProperties($node, $properties) {
|
||||
$path = $node->getPath();
|
||||
|
||||
$deleteStatement = $this->connection->prepare(
|
||||
'DELETE FROM `*PREFIX*properties`' .
|
||||
' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'
|
||||
);
|
||||
|
||||
$insertStatement = $this->connection->prepare(
|
||||
'INSERT INTO `*PREFIX*properties`' .
|
||||
' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)'
|
||||
);
|
||||
|
||||
$updateStatement = $this->connection->prepare(
|
||||
'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' .
|
||||
' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'
|
||||
);
|
||||
|
||||
// TODO: use "insert or update" strategy ?
|
||||
$existing = $this->getProperties($node, array());
|
||||
$this->connection->beginTransaction();
|
||||
foreach ($properties as $propertyName => $propertyValue) {
|
||||
// If it was null, we need to delete the property
|
||||
if (is_null($propertyValue)) {
|
||||
if (array_key_exists($propertyName, $existing)) {
|
||||
$deleteStatement->execute(
|
||||
array(
|
||||
$this->user,
|
||||
$path,
|
||||
$propertyName
|
||||
)
|
||||
);
|
||||
$deleteStatement->closeCursor();
|
||||
}
|
||||
} else {
|
||||
if (!array_key_exists($propertyName, $existing)) {
|
||||
$insertStatement->execute(
|
||||
array(
|
||||
$this->user,
|
||||
$path,
|
||||
$propertyName,
|
||||
$propertyValue
|
||||
)
|
||||
);
|
||||
$insertStatement->closeCursor();
|
||||
} else {
|
||||
$updateStatement->execute(
|
||||
array(
|
||||
$propertyValue,
|
||||
$this->user,
|
||||
$path,
|
||||
$propertyName
|
||||
)
|
||||
);
|
||||
$updateStatement->closeCursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->connection->commit();
|
||||
unset($this->cache[$path]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk load properties for directory children
|
||||
*
|
||||
* @param \OC\Connector\Sabre\Directory $node
|
||||
* @param array $requestedProperties requested properties
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function loadChildrenProperties(\OC\Connector\Sabre\Directory $node, $requestedProperties) {
|
||||
$path = $node->getPath();
|
||||
if (isset($this->cache[$path])) {
|
||||
// we already loaded them at some point
|
||||
return;
|
||||
}
|
||||
|
||||
$childNodes = $node->getChildren();
|
||||
// pre-fill cache
|
||||
foreach ($childNodes as $childNode) {
|
||||
$this->cache[$childNode->getPath()] = [];
|
||||
}
|
||||
|
||||
$sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` LIKE ?';
|
||||
$sql .= ' AND `propertyname` in (?) ORDER BY `propertypath`, `propertyname`';
|
||||
|
||||
$result = $this->connection->executeQuery(
|
||||
$sql,
|
||||
array($this->user, rtrim($path, '/') . '/%', $requestedProperties),
|
||||
array(null, null, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY)
|
||||
);
|
||||
|
||||
$props = [];
|
||||
$oldPath = null;
|
||||
$props = [];
|
||||
while ($row = $result->fetch()) {
|
||||
$path = $row['propertypath'];
|
||||
if ($oldPath !== $path) {
|
||||
// save previously gathered props
|
||||
$this->cache[$oldPath] = $props;
|
||||
$oldPath = $path;
|
||||
// prepare props for next path
|
||||
$props = [];
|
||||
}
|
||||
$props[$row['propertyname']] = $row['propertyvalue'];
|
||||
}
|
||||
if (!is_null($oldPath)) {
|
||||
// save props from last run
|
||||
$this->cache[$oldPath] = $props;
|
||||
}
|
||||
|
||||
$result->closeCursor();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
<?php
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
/**
|
||||
* @author Arthur Schiwon <blizzz@owncloud.com>
|
||||
* @author Bart Visscher <bartv@thisnet.nl>
|
||||
|
@ -24,7 +26,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
|
||||
class Directory extends \OC\Connector\Sabre\Node
|
||||
implements \Sabre\DAV\ICollection, \Sabre\DAV\IQuota {
|
||||
|
||||
/**
|
||||
|
@ -74,7 +76,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
|
|||
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
|
||||
|
||||
// exit if we can't create a new file and we don't updatable existing file
|
||||
$info = OC_FileChunking::decodeName($name);
|
||||
$info = \OC_FileChunking::decodeName($name);
|
||||
if (!$this->fileView->isCreatable($this->path) &&
|
||||
!$this->fileView->isUpdatable($this->path . '/' . $info['name'])
|
||||
) {
|
||||
|
@ -91,7 +93,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
|
|||
$path = $this->fileView->getAbsolutePath($this->path) . '/' . $name;
|
||||
// using a dummy FileInfo is acceptable here since it will be refreshed after the put is complete
|
||||
$info = new \OC\Files\FileInfo($path, null, null, array(), null);
|
||||
$node = new OC_Connector_Sabre_File($this->fileView, $info);
|
||||
$node = new \OC\Connector\Sabre\File($this->fileView, $info);
|
||||
return $node->put($data);
|
||||
} catch (\OCP\Files\StorageNotAvailableException $e) {
|
||||
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
|
||||
|
@ -143,9 +145,9 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
|
|||
}
|
||||
|
||||
if ($info['mimetype'] == 'httpd/unix-directory') {
|
||||
$node = new OC_Connector_Sabre_Directory($this->fileView, $info);
|
||||
$node = new \OC\Connector\Sabre\Directory($this->fileView, $info);
|
||||
} else {
|
||||
$node = new OC_Connector_Sabre_File($this->fileView, $info);
|
||||
$node = new \OC\Connector\Sabre\File($this->fileView, $info);
|
||||
}
|
||||
return $node;
|
||||
}
|
||||
|
@ -161,42 +163,9 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
|
|||
}
|
||||
$folderContent = $this->fileView->getDirectoryContent($this->path);
|
||||
|
||||
$properties = array();
|
||||
$paths = array();
|
||||
foreach ($folderContent as $info) {
|
||||
$name = $info->getName();
|
||||
$paths[] = $this->path . '/' . $name;
|
||||
$properties[$this->path . '/' . $name][self::GETETAG_PROPERTYNAME] = '"' . $info->getEtag() . '"';
|
||||
}
|
||||
// TODO: move this to a beforeGetPropertiesForPath event to pre-cache properties
|
||||
// TODO: only fetch the requested properties
|
||||
if (count($paths) > 0) {
|
||||
//
|
||||
// the number of arguments within IN conditions are limited in most databases
|
||||
// we chunk $paths into arrays of 200 items each to meet this criteria
|
||||
//
|
||||
$chunks = array_chunk($paths, 200, false);
|
||||
foreach ($chunks as $pack) {
|
||||
$placeholders = join(',', array_fill(0, count($pack), '?'));
|
||||
$query = OC_DB::prepare('SELECT * FROM `*PREFIX*properties`'
|
||||
. ' WHERE `userid` = ?' . ' AND `propertypath` IN (' . $placeholders . ')');
|
||||
array_unshift($pack, OC_User::getUser()); // prepend userid
|
||||
$result = $query->execute($pack);
|
||||
while ($row = $result->fetchRow()) {
|
||||
$propertypath = $row['propertypath'];
|
||||
$propertyname = $row['propertyname'];
|
||||
$propertyvalue = $row['propertyvalue'];
|
||||
if ($propertyname !== self::GETETAG_PROPERTYNAME) {
|
||||
$properties[$propertypath][$propertyname] = $propertyvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$nodes = array();
|
||||
foreach ($folderContent as $info) {
|
||||
$node = $this->getChild($info->getName(), $info);
|
||||
$node->setPropertyCache($properties[$this->path . '/' . $info->getName()]);
|
||||
$nodes[] = $node;
|
||||
}
|
||||
$this->dirContent = $nodes;
|
||||
|
@ -210,7 +179,13 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
|
|||
* @return bool
|
||||
*/
|
||||
public function childExists($name) {
|
||||
|
||||
// note: here we do NOT resolve the chunk file name to the real file name
|
||||
// to make sure we return false when checking for file existence with a chunk
|
||||
// file name.
|
||||
// This is to make sure that "createFile" is still triggered
|
||||
// (required old code) instead of "updateFile".
|
||||
//
|
||||
// TODO: resolve chunk file name here and implement "updateFile"
|
||||
$path = $this->path . '/' . $name;
|
||||
return $this->fileView->file_exists($path);
|
||||
|
||||
|
@ -245,7 +220,7 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
|
|||
return $this->quotaInfo;
|
||||
}
|
||||
try {
|
||||
$storageInfo = OC_Helper::getStorageInfo($this->info->getPath(), $this->info);
|
||||
$storageInfo = \OC_Helper::getStorageInfo($this->info->getPath(), $this->info);
|
||||
$this->quotaInfo = array(
|
||||
$storageInfo['used'],
|
||||
$storageInfo['free']
|
||||
|
@ -256,32 +231,4 @@ class OC_Connector_Sabre_Directory extends OC_Connector_Sabre_Node
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of properties for this nodes.;
|
||||
*
|
||||
* The properties list is a list of propertynames the client requested,
|
||||
* encoded as xmlnamespace#tagName, for example:
|
||||
* http://www.example.org/namespace#author
|
||||
* If the array is empty, all properties should be returned
|
||||
*
|
||||
* @param array $properties
|
||||
* @return array
|
||||
*/
|
||||
public function getProperties($properties) {
|
||||
$props = parent::getProperties($properties);
|
||||
if (in_array(self::GETETAG_PROPERTYNAME, $properties) && !isset($props[self::GETETAG_PROPERTYNAME])) {
|
||||
$props[self::GETETAG_PROPERTYNAME] = $this->info->getEtag();
|
||||
}
|
||||
return $props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the node, in bytes
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSize() {
|
||||
return $this->info->getSize();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
/**
|
||||
* Class DummyGetResponsePlugin is a plugin used to not show a "Not implemented"
|
||||
* error to clients that rely on verifying the functionality of the ownCloud
|
||||
* WebDAV backend using a simple GET to /.
|
||||
*
|
||||
* This is considered a legacy behaviour and implementers should consider sending
|
||||
* a PROPFIND request instead to verify whether the WebDAV component is working
|
||||
* properly.
|
||||
*
|
||||
* FIXME: Remove once clients are all compliant.
|
||||
*
|
||||
* @package OC\Connector\Sabre
|
||||
*/
|
||||
class DummyGetResponsePlugin extends \Sabre\DAV\ServerPlugin {
|
||||
/** @var \Sabre\DAV\Server */
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* @param \Sabre\DAV\Server $server
|
||||
* @return void
|
||||
*/
|
||||
function initialize(\Sabre\DAV\Server $server) {
|
||||
$this->server = $server;
|
||||
$this->server->on('method:GET', [$this,'httpGet'], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false
|
||||
*/
|
||||
function httpGet() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,24 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_Exception_EntityTooLarge extends \Sabre\DAV\Exception {
|
||||
|
||||
|
||||
namespace OC\Connector\Sabre\Exception;
|
||||
|
||||
class EntityTooLarge extends \Sabre\DAV\Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP status code for this exception
|
||||
|
|
|
@ -1,26 +1,10 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Lukas Reschke <lukas@owncloud.com>
|
||||
* @author Owen Winkler <a_github@midnightcircus.com>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_Exception_FileLocked extends \Sabre\DAV\Exception {
|
||||
|
||||
namespace OC\Connector\Sabre\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class FileLocked extends \Sabre\DAV\Exception {
|
||||
|
||||
public function __construct($message = "", $code = 0, Exception $previous = null) {
|
||||
if($previous instanceof \OCP\Files\LockNotAcquiredException) {
|
||||
|
|
|
@ -1,24 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_Exception_UnsupportedMediaType extends \Sabre\DAV\Exception {
|
||||
|
||||
|
||||
namespace OC\Connector\Sabre\Exception;
|
||||
|
||||
class UnsupportedMediaType extends \Sabre\DAV\Exception {
|
||||
|
||||
/**
|
||||
* Returns the HTTP status code for this exception
|
||||
|
|
|
@ -1,26 +1,8 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin
|
||||
{
|
||||
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
class ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin {
|
||||
private $nonFatalExceptions = array(
|
||||
'Sabre\DAV\Exception\NotAuthenticated' => true,
|
||||
// the sync client uses this to find out whether files exist,
|
||||
|
@ -54,7 +36,7 @@ class OC_Connector_Sabre_ExceptionLoggerPlugin extends \Sabre\DAV\ServerPlugin
|
|||
*/
|
||||
public function initialize(\Sabre\DAV\Server $server) {
|
||||
|
||||
$server->subscribeEvent('exception', array($this, 'logException'), 10);
|
||||
$server->on('exception', array($this, 'logException'), 10);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,38 +1,7 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@owncloud.com>
|
||||
* @author Bart Visscher <bartv@thisnet.nl>
|
||||
* @author Bjoern Schiessle <schiessle@owncloud.com>
|
||||
* @author chli1 <chli1@users.noreply.github.com>
|
||||
* @author Chris Wilson <chris+github@qwirx.com>
|
||||
* @author Jakob Sack <mail@jakobsack.de>
|
||||
* @author Joas Schilling <nickvergessen@gmx.de>
|
||||
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
|
||||
* @author Lukas Reschke <lukas@owncloud.com>
|
||||
* @author Owen Winkler <a_github@midnightcircus.com>
|
||||
* @author Robin Appelman <icewind@owncloud.com>
|
||||
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Thomas Tanghus <thomas@tanghus.net>
|
||||
* @author Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\DAV\IFile {
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
class File extends \OC\Connector\Sabre\Node implements \Sabre\DAV\IFile {
|
||||
|
||||
/**
|
||||
* Updates the data
|
||||
|
@ -52,11 +21,12 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
|
|||
* return an ETag, and just return null.
|
||||
*
|
||||
* @param resource $data
|
||||
*
|
||||
* @throws \Sabre\DAV\Exception\Forbidden
|
||||
* @throws OC_Connector_Sabre_Exception_UnsupportedMediaType
|
||||
* @throws \OC\Connector\Sabre\Exception\UnsupportedMediaType
|
||||
* @throws \Sabre\DAV\Exception\BadRequest
|
||||
* @throws \Sabre\DAV\Exception
|
||||
* @throws OC_Connector_Sabre_Exception_EntityTooLarge
|
||||
* @throws \OC\Connector\Sabre\Exception\EntityTooLarge
|
||||
* @throws \Sabre\DAV\Exception\ServiceUnavailable
|
||||
* @return string|null
|
||||
*/
|
||||
|
@ -110,11 +80,11 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
|
|||
|
||||
} catch (\OCP\Files\EntityTooLargeException $e) {
|
||||
// the file is too big to be stored
|
||||
throw new OC_Connector_Sabre_Exception_EntityTooLarge($e->getMessage());
|
||||
throw new \OC\Connector\Sabre\Exception\EntityTooLarge($e->getMessage());
|
||||
|
||||
} catch (\OCP\Files\InvalidContentException $e) {
|
||||
// the file content is not permitted
|
||||
throw new OC_Connector_Sabre_Exception_UnsupportedMediaType($e->getMessage());
|
||||
throw new \OC\Connector\Sabre\Exception\UnsupportedMediaType($e->getMessage());
|
||||
|
||||
} catch (\OCP\Files\InvalidPathException $e) {
|
||||
// the path for the file was not valid
|
||||
|
@ -122,7 +92,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
|
|||
throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
|
||||
} catch (\OCP\Files\LockNotAcquiredException $e) {
|
||||
// the file is currently being written to by another process
|
||||
throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e);
|
||||
throw new \OC\Connector\Sabre\Exception\FileLocked($e->getMessage(), $e->getCode(), $e);
|
||||
} catch (\OCA\Files_Encryption\Exception\EncryptionException $e) {
|
||||
throw new \Sabre\DAV\Exception\Forbidden($e->getMessage());
|
||||
} catch (\OCP\Files\StorageNotAvailableException $e) {
|
||||
|
@ -155,7 +125,7 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
|
|||
}
|
||||
catch (\OCP\Files\LockNotAcquiredException $e) {
|
||||
// the file is currently being written to by another process
|
||||
throw new OC_Connector_Sabre_Exception_FileLocked($e->getMessage(), $e->getCode(), $e);
|
||||
throw new \OC\Connector\Sabre\Exception\FileLocked($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,34 +185,6 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
|
|||
} catch (\OCP\Files\StorageNotAvailableException $e) {
|
||||
throw new \Sabre\DAV\Exception\ServiceUnavailable("Failed to unlink: ".$e->getMessage());
|
||||
}
|
||||
|
||||
// remove properties
|
||||
$this->removeProperties();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the node, in bytes
|
||||
*
|
||||
* @return int|float
|
||||
*/
|
||||
public function getSize() {
|
||||
return $this->info->getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ETag for a file
|
||||
*
|
||||
* An ETag is a unique identifier representing the current version of the
|
||||
* file. If the file changes, the ETag MUST change. The ETag is an
|
||||
* arbitrary string, but MUST be surrounded by double-quotes.
|
||||
*
|
||||
* Return null if the ETag can not effectively be determined
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getETag() {
|
||||
return '"' . $this->info->getEtag() . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -288,13 +230,13 @@ class OC_Connector_Sabre_File extends OC_Connector_Sabre_Node implements \Sabre\
|
|||
*/
|
||||
private function createFileChunked($data)
|
||||
{
|
||||
list($path, $name) = \Sabre\DAV\URLUtil::splitPath($this->path);
|
||||
list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($this->path);
|
||||
|
||||
$info = OC_FileChunking::decodeName($name);
|
||||
$info = \OC_FileChunking::decodeName($name);
|
||||
if (empty($info)) {
|
||||
throw new \Sabre\DAV\Exception\NotImplemented();
|
||||
}
|
||||
$chunk_handler = new OC_FileChunking($info);
|
||||
$chunk_handler = new \OC_FileChunking($info);
|
||||
$bytesWritten = $chunk_handler->store($info['index'], $data);
|
||||
|
||||
//detect aborted upload
|
||||
|
|
|
@ -1,30 +1,21 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
|
||||
{
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
use \Sabre\DAV\PropFind;
|
||||
use \Sabre\DAV\PropPatch;
|
||||
use \Sabre\HTTP\RequestInterface;
|
||||
use \Sabre\HTTP\ResponseInterface;
|
||||
|
||||
class FilesPlugin extends \Sabre\DAV\ServerPlugin {
|
||||
|
||||
// namespace
|
||||
const NS_OWNCLOUD = 'http://owncloud.org/ns';
|
||||
const FILEID_PROPERTYNAME = '{http://owncloud.org/ns}id';
|
||||
const PERMISSIONS_PROPERTYNAME = '{http://owncloud.org/ns}permissions';
|
||||
const DOWNLOADURL_PROPERTYNAME = '{http://owncloud.org/ns}downloadURL';
|
||||
const SIZE_PROPERTYNAME = '{http://owncloud.org/ns}size';
|
||||
const GETETAG_PROPERTYNAME = '{DAV:}getetag';
|
||||
const GETLASTMODIFIED_PROPERTYNAME = '{DAV:}getlastmodified';
|
||||
|
||||
/**
|
||||
* Reference to main server object
|
||||
|
@ -33,6 +24,15 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
|
|||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* @var \Sabre\DAV\Tree
|
||||
*/
|
||||
private $tree;
|
||||
|
||||
public function __construct(\Sabre\DAV\Tree $tree) {
|
||||
$this->tree = $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* This initializes the plugin.
|
||||
*
|
||||
|
@ -47,66 +47,98 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
|
|||
public function initialize(\Sabre\DAV\Server $server) {
|
||||
|
||||
$server->xmlNamespaces[self::NS_OWNCLOUD] = 'oc';
|
||||
$server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}id';
|
||||
$server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}permissions';
|
||||
$server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}size';
|
||||
$server->protectedProperties[] = '{' . self::NS_OWNCLOUD . '}downloadURL';
|
||||
$server->protectedProperties[] = self::FILEID_PROPERTYNAME;
|
||||
$server->protectedProperties[] = self::PERMISSIONS_PROPERTYNAME;
|
||||
$server->protectedProperties[] = self::SIZE_PROPERTYNAME;
|
||||
$server->protectedProperties[] = self::DOWNLOADURL_PROPERTYNAME;
|
||||
|
||||
// normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
|
||||
$allowedProperties = ['{DAV:}getetag', '{DAV:}getlastmodified'];
|
||||
$server->protectedProperties = array_diff($server->protectedProperties, $allowedProperties);
|
||||
|
||||
$this->server = $server;
|
||||
$this->server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties'));
|
||||
$this->server->subscribeEvent('afterBind', array($this, 'sendFileIdHeader'));
|
||||
$this->server->subscribeEvent('afterWriteContent', array($this, 'sendFileIdHeader'));
|
||||
$this->server->on('propFind', array($this, 'handleGetProperties'));
|
||||
$this->server->on('propPatch', array($this, 'handleUpdateProperties'));
|
||||
$this->server->on('afterBind', array($this, 'sendFileIdHeader'));
|
||||
$this->server->on('afterWriteContent', array($this, 'sendFileIdHeader'));
|
||||
$this->server->on('beforeMethod:GET', array($this, 'handleRangeHeaders'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all ownCloud-specific properties
|
||||
*
|
||||
* @param string $path
|
||||
* @param PropFind $propFind
|
||||
* @param \Sabre\DAV\INode $node
|
||||
* @param array $requestedProperties
|
||||
* @param array $returnedProperties
|
||||
* @return void
|
||||
*/
|
||||
public function beforeGetProperties($path, \Sabre\DAV\INode $node, array &$requestedProperties, array &$returnedProperties) {
|
||||
public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node) {
|
||||
|
||||
if ($node instanceof OC_Connector_Sabre_Node) {
|
||||
if ($node instanceof \OC\Connector\Sabre\Node) {
|
||||
|
||||
$fileIdPropertyName = '{' . self::NS_OWNCLOUD . '}id';
|
||||
$permissionsPropertyName = '{' . self::NS_OWNCLOUD . '}permissions';
|
||||
if (array_search($fileIdPropertyName, $requestedProperties)) {
|
||||
unset($requestedProperties[array_search($fileIdPropertyName, $requestedProperties)]);
|
||||
}
|
||||
if (array_search($permissionsPropertyName, $requestedProperties)) {
|
||||
unset($requestedProperties[array_search($permissionsPropertyName, $requestedProperties)]);
|
||||
}
|
||||
$propFind->handle(self::FILEID_PROPERTYNAME, function() use ($node) {
|
||||
return $node->getFileId();
|
||||
});
|
||||
|
||||
/** @var $node OC_Connector_Sabre_Node */
|
||||
$fileId = $node->getFileId();
|
||||
if (!is_null($fileId)) {
|
||||
$returnedProperties[200][$fileIdPropertyName] = $fileId;
|
||||
}
|
||||
$propFind->handle(self::PERMISSIONS_PROPERTYNAME, function() use ($node) {
|
||||
return $node->getDavPermissions();
|
||||
});
|
||||
|
||||
$permissions = $node->getDavPermissions();
|
||||
if (!is_null($permissions)) {
|
||||
$returnedProperties[200][$permissionsPropertyName] = $permissions;
|
||||
}
|
||||
$propFind->handle(self::GETETAG_PROPERTYNAME, function() use ($node) {
|
||||
return $node->getEtag();
|
||||
});
|
||||
}
|
||||
|
||||
if ($node instanceof OC_Connector_Sabre_File) {
|
||||
/** @var $node OC_Connector_Sabre_File */
|
||||
$directDownloadUrl = $node->getDirectDownload();
|
||||
if (isset($directDownloadUrl['url'])) {
|
||||
$directDownloadUrlPropertyName = '{' . self::NS_OWNCLOUD . '}downloadURL';
|
||||
$returnedProperties[200][$directDownloadUrlPropertyName] = $directDownloadUrl['url'];
|
||||
if ($node instanceof \OC\Connector\Sabre\File) {
|
||||
$propFind->handle(self::DOWNLOADURL_PROPERTYNAME, function() use ($node) {
|
||||
/** @var $node \OC\Connector\Sabre\File */
|
||||
$directDownloadUrl = $node->getDirectDownload();
|
||||
if (isset($directDownloadUrl['url'])) {
|
||||
return $directDownloadUrl['url'];
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if ($node instanceof \OC\Connector\Sabre\Directory) {
|
||||
$propFind->handle(self::SIZE_PROPERTYNAME, function() use ($node) {
|
||||
return $node->getSize();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update ownCloud-specific properties
|
||||
*
|
||||
* @param string $path
|
||||
* @param PropPatch $propPatch
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handleUpdateProperties($path, PropPatch $propPatch) {
|
||||
$propPatch->handle(self::GETLASTMODIFIED_PROPERTYNAME, function($time) use ($path) {
|
||||
if (empty($time)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($node instanceof OC_Connector_Sabre_Directory) {
|
||||
$sizePropertyName = '{' . self::NS_OWNCLOUD . '}size';
|
||||
|
||||
/** @var $node OC_Connector_Sabre_Directory */
|
||||
$returnedProperties[200][$sizePropertyName] = $node->getSize();
|
||||
}
|
||||
$node = $this->tree->getNodeForPath($path);
|
||||
if (is_null($node)) {
|
||||
return 404;
|
||||
}
|
||||
$node->touch($time);
|
||||
return true;
|
||||
});
|
||||
$propPatch->handle(self::GETETAG_PROPERTYNAME, function($etag) use ($path) {
|
||||
if (empty($etag)) {
|
||||
return false;
|
||||
}
|
||||
$node = $this->tree->getNodeForPath($path);
|
||||
if (is_null($node)) {
|
||||
return 404;
|
||||
}
|
||||
if ($node->setEtag($etag) !== -1) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,8 +149,8 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
|
|||
public function sendFileIdHeader($filePath, \Sabre\DAV\INode $node = null) {
|
||||
// chunked upload handling
|
||||
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
|
||||
list($path, $name) = \Sabre\DAV\URLUtil::splitPath($filePath);
|
||||
$info = OC_FileChunking::decodeName($name);
|
||||
list($path, $name) = \Sabre\HTTP\URLUtil::splitPath($filePath);
|
||||
$info = \OC_FileChunking::decodeName($name);
|
||||
if (!empty($info)) {
|
||||
$filePath = $path . '/' . $info['name'];
|
||||
}
|
||||
|
@ -129,7 +161,7 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
|
|||
return;
|
||||
}
|
||||
$node = $this->server->tree->getNodeForPath($filePath);
|
||||
if ($node instanceof OC_Connector_Sabre_Node) {
|
||||
if ($node instanceof \OC\Connector\Sabre\Node) {
|
||||
$fileId = $node->getFileId();
|
||||
if (!is_null($fileId)) {
|
||||
$this->server->httpResponse->setHeader('OC-FileId', $fileId);
|
||||
|
@ -137,4 +169,17 @@ class OC_Connector_Sabre_FilesPlugin extends \Sabre\DAV\ServerPlugin
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove range headers if encryption is enabled.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
public function handleRangeHeaders(RequestInterface $request, ResponseInterface $response) {
|
||||
if (\OC_App::isEnabled('files_encryption')) {
|
||||
// encryption does not support range requests (yet)
|
||||
$request->removeHeader('range');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,191 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Bart Visscher <bartv@thisnet.nl>
|
||||
* @author Felix Moeller <mail@felixmoeller.de>
|
||||
* @author Jakob Sack <mail@jakobsack.de>
|
||||
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
|
||||
* @author Robin Appelman <icewind@owncloud.com>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_Locks extends \Sabre\DAV\Locks\Backend\AbstractBackend {
|
||||
|
||||
/**
|
||||
* Returns a list of \Sabre\DAV\Locks_LockInfo objects
|
||||
*
|
||||
* This method should return all the locks for a particular uri, including
|
||||
* locks that might be set on a parent uri.
|
||||
*
|
||||
* If returnChildLocks is set to true, this method should also look for
|
||||
* any locks in the subtree of the uri for locks.
|
||||
*
|
||||
* @param string $uri
|
||||
* @param bool $returnChildLocks
|
||||
* @return array
|
||||
*/
|
||||
public function getLocks($uri, $returnChildLocks) {
|
||||
|
||||
// NOTE: the following 10 lines or so could be easily replaced by
|
||||
// pure sql. MySQL's non-standard string concatination prevents us
|
||||
// from doing this though.
|
||||
// NOTE: SQLite requires time() to be inserted directly. That's ugly
|
||||
// but otherwise reading locks from SQLite Databases will return
|
||||
// nothing
|
||||
$query = 'SELECT * FROM `*PREFIX*locks`'
|
||||
.' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( `uri` = ?)';
|
||||
if (OC_Config::getValue( "dbtype") === 'oci') {
|
||||
//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
|
||||
$query = 'SELECT * FROM `*PREFIX*locks`'
|
||||
.' WHERE `userid` = ? AND (`created` + `timeout`) > '.time().' AND (( to_char(`uri`) = ?)';
|
||||
}
|
||||
$params = array(OC_User::getUser(), $uri);
|
||||
|
||||
// We need to check locks for every part in the uri.
|
||||
$uriParts = explode('/', $uri);
|
||||
|
||||
// We already covered the last part of the uri
|
||||
array_pop($uriParts);
|
||||
|
||||
$currentPath='';
|
||||
|
||||
foreach($uriParts as $part) {
|
||||
|
||||
if ($currentPath) $currentPath.='/';
|
||||
$currentPath.=$part;
|
||||
//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
|
||||
if (OC_Config::getValue( "dbtype") === 'oci') {
|
||||
$query.=' OR (`depth` != 0 AND to_char(`uri`) = ?)';
|
||||
} else {
|
||||
$query.=' OR (`depth` != 0 AND `uri` = ?)';
|
||||
}
|
||||
$params[] = $currentPath;
|
||||
|
||||
}
|
||||
|
||||
if ($returnChildLocks) {
|
||||
|
||||
//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
|
||||
if (OC_Config::getValue( "dbtype") === 'oci') {
|
||||
$query.=' OR (to_char(`uri`) LIKE ?)';
|
||||
} else {
|
||||
$query.=' OR (`uri` LIKE ?)';
|
||||
}
|
||||
$params[] = $uri . '/%';
|
||||
|
||||
}
|
||||
$query.=')';
|
||||
|
||||
$result = OC_DB::executeAudited( $query, $params );
|
||||
|
||||
$lockList = array();
|
||||
while( $row = $result->fetchRow()) {
|
||||
|
||||
$lockInfo = new \Sabre\DAV\Locks\LockInfo();
|
||||
$lockInfo->owner = $row['owner'];
|
||||
$lockInfo->token = $row['token'];
|
||||
$lockInfo->timeout = $row['timeout'];
|
||||
$lockInfo->created = $row['created'];
|
||||
$lockInfo->scope = $row['scope'];
|
||||
$lockInfo->depth = $row['depth'];
|
||||
$lockInfo->uri = $row['uri'];
|
||||
$lockList[] = $lockInfo;
|
||||
|
||||
}
|
||||
|
||||
return $lockList;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks a uri
|
||||
*
|
||||
* @param string $uri
|
||||
* @param \Sabre\DAV\Locks\LockInfo $lockInfo
|
||||
* @return bool
|
||||
*/
|
||||
public function lock($uri, \Sabre\DAV\Locks\LockInfo $lockInfo) {
|
||||
|
||||
// We're making the lock timeout 5 minutes
|
||||
$lockInfo->timeout = 300;
|
||||
$lockInfo->created = time();
|
||||
$lockInfo->uri = $uri;
|
||||
|
||||
$locks = $this->getLocks($uri, false);
|
||||
$exists = false;
|
||||
foreach($locks as $lock) {
|
||||
if ($lock->token == $lockInfo->token) {
|
||||
$exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
$sql = 'UPDATE `*PREFIX*locks`'
|
||||
.' SET `owner` = ?, `timeout` = ?, `scope` = ?, `depth` = ?, `uri` = ?, `created` = ?'
|
||||
.' WHERE `userid` = ? AND `token` = ?';
|
||||
$result = OC_DB::executeAudited( $sql, array(
|
||||
$lockInfo->owner,
|
||||
$lockInfo->timeout,
|
||||
$lockInfo->scope,
|
||||
$lockInfo->depth,
|
||||
$uri,
|
||||
$lockInfo->created,
|
||||
OC_User::getUser(),
|
||||
$lockInfo->token)
|
||||
);
|
||||
} else {
|
||||
$sql = 'INSERT INTO `*PREFIX*locks`'
|
||||
.' (`userid`,`owner`,`timeout`,`scope`,`depth`,`uri`,`created`,`token`)'
|
||||
.' VALUES (?,?,?,?,?,?,?,?)';
|
||||
$result = OC_DB::executeAudited( $sql, array(
|
||||
OC_User::getUser(),
|
||||
$lockInfo->owner,
|
||||
$lockInfo->timeout,
|
||||
$lockInfo->scope,
|
||||
$lockInfo->depth,
|
||||
$uri,
|
||||
$lockInfo->created,
|
||||
$lockInfo->token)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a lock from a uri
|
||||
*
|
||||
* @param string $uri
|
||||
* @param \Sabre\DAV\Locks\LockInfo $lockInfo
|
||||
* @return bool
|
||||
*/
|
||||
public function unlock($uri, \Sabre\DAV\Locks\LockInfo $lockInfo) {
|
||||
|
||||
$sql = 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND `uri` = ? AND `token` = ?';
|
||||
if (OC_Config::getValue( "dbtype") === 'oci') {
|
||||
//FIXME oracle hack: need to explicitly cast CLOB to CHAR for comparison
|
||||
$sql = 'DELETE FROM `*PREFIX*locks` WHERE `userid` = ? AND to_char(`uri`) = ? AND `token` = ?';
|
||||
}
|
||||
$result = OC_DB::executeAudited( $sql, array(OC_User::getUser(), $uri, $lockInfo->token));
|
||||
|
||||
return $result === 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,25 +1,7 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Bart Visscher <bartv@thisnet.nl>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_MaintenancePlugin extends \Sabre\DAV\ServerPlugin
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
class MaintenancePlugin extends \Sabre\DAV\ServerPlugin
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -43,7 +25,7 @@ class OC_Connector_Sabre_MaintenancePlugin extends \Sabre\DAV\ServerPlugin
|
|||
public function initialize(\Sabre\DAV\Server $server) {
|
||||
|
||||
$this->server = $server;
|
||||
$this->server->subscribeEvent('beforeMethod', array($this, 'checkMaintenanceMode'), 10);
|
||||
$this->server->on('beforeMethod', array($this, 'checkMaintenanceMode'), 10);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,10 +37,10 @@ class OC_Connector_Sabre_MaintenancePlugin extends \Sabre\DAV\ServerPlugin
|
|||
* @return bool
|
||||
*/
|
||||
public function checkMaintenanceMode() {
|
||||
if (OC_Config::getValue('maintenance', false)) {
|
||||
if (\OC_Config::getValue('maintenance', false)) {
|
||||
throw new \Sabre\DAV\Exception\ServiceUnavailable();
|
||||
}
|
||||
if (OC::checkUpgrade(false)) {
|
||||
if (\OC::checkUpgrade(false)) {
|
||||
throw new \Sabre\DAV\Exception\ServiceUnavailable('Upgrade needed');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,36 +1,4 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Arthur Schiwon <blizzz@owncloud.com>
|
||||
* @author Bart Visscher <bartv@thisnet.nl>
|
||||
* @author Björn Schießle <schiessle@owncloud.com>
|
||||
* @author Jakob Sack <mail@jakobsack.de>
|
||||
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
|
||||
* @author Klaas Freitag <freitag@owncloud.com>
|
||||
* @author Markus Goetz <markus@woboq.com>
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Robin Appelman <icewind@owncloud.com>
|
||||
* @author Sam Tuke <mail@samtuke.com>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
use Sabre\DAV\URLUtil;
|
||||
use OC\Connector\Sabre\TagList;
|
||||
|
||||
/**
|
||||
* ownCloud
|
||||
|
@ -52,10 +20,10 @@ use OC\Connector\Sabre\TagList;
|
|||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\IProperties {
|
||||
const GETETAG_PROPERTYNAME = '{DAV:}getetag';
|
||||
const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified';
|
||||
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
abstract class Node implements \Sabre\DAV\INode {
|
||||
/**
|
||||
* Allow configuring the method used to generate Etags
|
||||
*
|
||||
|
@ -110,6 +78,15 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I
|
|||
return $this->info->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPath() {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the node
|
||||
* @param string $name The new name
|
||||
|
@ -123,23 +100,19 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I
|
|||
throw new \Sabre\DAV\Exception\Forbidden();
|
||||
}
|
||||
|
||||
list($parentPath,) = URLUtil::splitPath($this->path);
|
||||
list(, $newName) = URLUtil::splitPath($name);
|
||||
list($parentPath,) = \Sabre\HTTP\URLUtil::splitPath($this->path);
|
||||
list(, $newName) = \Sabre\HTTP\URLUtil::splitPath($name);
|
||||
|
||||
if (!\OCP\Util::isValidFileName($newName)) {
|
||||
throw new \Sabre\DAV\Exception\BadRequest();
|
||||
}
|
||||
|
||||
$newPath = $parentPath . '/' . $newName;
|
||||
$oldPath = $this->path;
|
||||
|
||||
$this->fileView->rename($this->path, $newPath);
|
||||
|
||||
$this->path = $newPath;
|
||||
|
||||
$query = OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertypath` = ?'
|
||||
. ' WHERE `userid` = ? AND `propertypath` = ?');
|
||||
$query->execute(array($newPath, OC_User::getUser(), $oldPath));
|
||||
$this->refreshInfo();
|
||||
}
|
||||
|
||||
|
@ -170,91 +143,38 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I
|
|||
}
|
||||
|
||||
/**
|
||||
* Updates properties on this node,
|
||||
* @see \Sabre\DAV\IProperties::updateProperties
|
||||
* @param array $properties
|
||||
* @return boolean
|
||||
* Returns the ETag for a file
|
||||
*
|
||||
* An ETag is a unique identifier representing the current version of the
|
||||
* file. If the file changes, the ETag MUST change. The ETag is an
|
||||
* arbitrary string, but MUST be surrounded by double-quotes.
|
||||
*
|
||||
* Return null if the ETag can not effectively be determined
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function updateProperties($properties) {
|
||||
$existing = $this->getProperties(array());
|
||||
foreach ($properties as $propertyName => $propertyValue) {
|
||||
// If it was null, we need to delete the property
|
||||
if (is_null($propertyValue)) {
|
||||
if (array_key_exists($propertyName, $existing)) {
|
||||
$query = OC_DB::prepare('DELETE FROM `*PREFIX*properties`'
|
||||
. ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?');
|
||||
$query->execute(array(OC_User::getUser(), $this->path, $propertyName));
|
||||
}
|
||||
} else {
|
||||
if (strcmp($propertyName, self::GETETAG_PROPERTYNAME) === 0) {
|
||||
\OC\Files\Filesystem::putFileInfo($this->path, array('etag' => $propertyValue));
|
||||
} elseif (strcmp($propertyName, self::LASTMODIFIED_PROPERTYNAME) === 0) {
|
||||
$this->touch($propertyValue);
|
||||
} else {
|
||||
if (!array_key_exists($propertyName, $existing)) {
|
||||
$query = OC_DB::prepare('INSERT INTO `*PREFIX*properties`'
|
||||
. ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)');
|
||||
$query->execute(array(OC_User::getUser(), $this->path, $propertyName, $propertyValue));
|
||||
} else {
|
||||
$query = OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertyvalue` = ?'
|
||||
. ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?');
|
||||
$query->execute(array($propertyValue, OC_User::getUser(), $this->path, $propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$this->setPropertyCache(null);
|
||||
return true;
|
||||
public function getETag() {
|
||||
return '"' . $this->info->getEtag() . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* removes all properties for this node and user
|
||||
* Sets the ETag
|
||||
*
|
||||
* @param string $etag
|
||||
*
|
||||
* @return int file id of updated file or -1 on failure
|
||||
*/
|
||||
public function removeProperties() {
|
||||
$query = OC_DB::prepare('DELETE FROM `*PREFIX*properties`'
|
||||
. ' WHERE `userid` = ? AND `propertypath` = ?');
|
||||
$query->execute(array(OC_User::getUser(), $this->path));
|
||||
|
||||
$this->setPropertyCache(null);
|
||||
public function setETag($etag) {
|
||||
return $this->fileView->putFileInfo($this->path, array('etag' => $etag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of properties for this nodes.;
|
||||
* @param array $properties
|
||||
* @return array
|
||||
* @note The properties list is a list of propertynames the client
|
||||
* requested, encoded as xmlnamespace#tagName, for example:
|
||||
* http://www.example.org/namespace#author If the array is empty, all
|
||||
* properties should be returned
|
||||
* Returns the size of the node, in bytes
|
||||
*
|
||||
* @return int|float
|
||||
*/
|
||||
public function getProperties($properties) {
|
||||
|
||||
if (is_null($this->property_cache)) {
|
||||
$sql = 'SELECT * FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ?';
|
||||
$result = OC_DB::executeAudited($sql, array(OC_User::getUser(), $this->path));
|
||||
|
||||
$this->property_cache = array();
|
||||
while ($row = $result->fetchRow()) {
|
||||
$this->property_cache[$row['propertyname']] = $row['propertyvalue'];
|
||||
}
|
||||
|
||||
$this->property_cache[self::GETETAG_PROPERTYNAME] = '"' . $this->info->getEtag() . '"';
|
||||
}
|
||||
|
||||
// if the array was empty, we need to return everything
|
||||
if (count($properties) == 0) {
|
||||
return $this->property_cache;
|
||||
}
|
||||
|
||||
$props = array();
|
||||
foreach ($properties as $property) {
|
||||
if (isset($this->property_cache[$property])) {
|
||||
$props[$property] = $this->property_cache[$property];
|
||||
}
|
||||
}
|
||||
|
||||
return $props;
|
||||
public function getSize() {
|
||||
return $this->info->getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -271,7 +191,7 @@ abstract class OC_Connector_Sabre_Node implements \Sabre\DAV\INode, \Sabre\DAV\I
|
|||
*/
|
||||
public function getFileId() {
|
||||
if ($this->info->getId()) {
|
||||
$instanceId = OC_Util::getInstanceId();
|
||||
$instanceId = \OC_Util::getInstanceId();
|
||||
$id = sprintf('%08d', $this->info->getId());
|
||||
return $id . $instanceId;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ use OC\Files\Mount\MoveableMount;
|
|||
use OCP\Files\StorageInvalidException;
|
||||
use OCP\Files\StorageNotAvailableException;
|
||||
|
||||
class ObjectTree extends \Sabre\DAV\ObjectTree {
|
||||
class ObjectTree extends \Sabre\DAV\Tree {
|
||||
|
||||
/**
|
||||
* @var \OC\Files\View
|
||||
|
@ -44,8 +44,6 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
|
|||
|
||||
/**
|
||||
* Creates the object
|
||||
*
|
||||
* This method expects the rootObject to be passed as a parameter
|
||||
*/
|
||||
public function __construct() {
|
||||
}
|
||||
|
@ -61,6 +59,35 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
|
|||
$this->mountManager = $mountManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given path is a chunked file name, converts it
|
||||
* to the real file name. Only applies if the OC-CHUNKED header
|
||||
* is present.
|
||||
*
|
||||
* @param string $path chunk file path to convert
|
||||
*
|
||||
* @return string path to real file
|
||||
*/
|
||||
private function resolveChunkFile($path) {
|
||||
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
|
||||
// resolve to real file name to find the proper node
|
||||
list($dir, $name) = \Sabre\HTTP\URLUtil::splitPath($path);
|
||||
if ($dir == '/' || $dir == '.') {
|
||||
$dir = '';
|
||||
}
|
||||
|
||||
$info = \OC_FileChunking::decodeName($name);
|
||||
// only replace path if it was really the chunked file
|
||||
if (isset($info['transferid'])) {
|
||||
// getNodePath is called for multiple nodes within a chunk
|
||||
// upload call
|
||||
$path = $dir . '/' . $info['name'];
|
||||
$path = ltrim($path, '/');
|
||||
}
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the INode object for the requested path
|
||||
*
|
||||
|
@ -102,12 +129,15 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
|
|||
$info = null;
|
||||
}
|
||||
} else {
|
||||
// resolve chunk file name to real name, if applicable
|
||||
$path = $this->resolveChunkFile($path);
|
||||
|
||||
// read from cache
|
||||
try {
|
||||
$info = $this->fileView->getFileInfo($path);
|
||||
} catch (StorageNotAvailableException $e) {
|
||||
throw new \Sabre\DAV\Exception\ServiceUnavailable('Storage not available');
|
||||
} catch (StorageInvalidException $e){
|
||||
} catch (StorageInvalidException $e) {
|
||||
throw new \Sabre\DAV\Exception\NotFound('Storage ' . $path . ' is invalid');
|
||||
}
|
||||
}
|
||||
|
@ -117,9 +147,9 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
|
|||
}
|
||||
|
||||
if ($info->getType() === 'dir') {
|
||||
$node = new \OC_Connector_Sabre_Directory($this->fileView, $info);
|
||||
$node = new \OC\Connector\Sabre\Directory($this->fileView, $info);
|
||||
} else {
|
||||
$node = new \OC_Connector_Sabre_File($this->fileView, $info);
|
||||
$node = new \OC\Connector\Sabre\File($this->fileView, $info);
|
||||
}
|
||||
|
||||
$this->cache[$path] = $node;
|
||||
|
@ -146,8 +176,8 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
|
|||
if ($sourceNode instanceof \Sabre\DAV\ICollection and $this->nodeExists($destinationPath)) {
|
||||
throw new \Sabre\DAV\Exception\Forbidden('Could not copy directory ' . $sourceNode . ', target exists');
|
||||
}
|
||||
list($sourceDir,) = \Sabre\DAV\URLUtil::splitPath($sourcePath);
|
||||
list($destinationDir,) = \Sabre\DAV\URLUtil::splitPath($destinationPath);
|
||||
list($sourceDir,) = \Sabre\HTTP\URLUtil::splitPath($sourcePath);
|
||||
list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destinationPath);
|
||||
|
||||
$isMovableMount = false;
|
||||
$sourceMount = $this->mountManager->find($this->fileView->getAbsolutePath($sourcePath));
|
||||
|
@ -183,12 +213,6 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
|
|||
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
|
||||
}
|
||||
|
||||
// update properties
|
||||
$query = \OC_DB::prepare('UPDATE `*PREFIX*properties` SET `propertypath` = ?'
|
||||
. ' WHERE `userid` = ? AND `propertypath` = ?');
|
||||
$query->execute(array(\OC\Files\Filesystem::normalizePath($destinationPath), \OC_User::getUser(),
|
||||
\OC\Files\Filesystem::normalizePath($sourcePath)));
|
||||
|
||||
$this->markDirty($sourceDir);
|
||||
$this->markDirty($destinationDir);
|
||||
|
||||
|
@ -229,7 +253,7 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
|
|||
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage());
|
||||
}
|
||||
|
||||
list($destinationDir,) = \Sabre\DAV\URLUtil::splitPath($destination);
|
||||
list($destinationDir,) = \Sabre\HTTP\URLUtil::splitPath($destination);
|
||||
$this->markDirty($destinationDir);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace OC\Connector\Sabre;
|
|||
|
||||
use OCP\IUserManager;
|
||||
use OCP\IConfig;
|
||||
use \Sabre\DAV\PropPatch;
|
||||
|
||||
class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
|
||||
/** @var IConfig */
|
||||
|
@ -137,7 +138,7 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
|
|||
* @throws \Sabre\DAV\Exception
|
||||
*/
|
||||
public function getGroupMembership($principal) {
|
||||
list($prefix, $name) = \Sabre\DAV\URLUtil::splitPath($principal);
|
||||
list($prefix, $name) = \Sabre\HTTP\URLUtil::splitPath($principal);
|
||||
|
||||
$group_membership = array();
|
||||
if ($prefix === 'principals') {
|
||||
|
@ -174,19 +175,28 @@ class Principal implements \Sabre\DAVACL\PrincipalBackend\BackendInterface {
|
|||
|
||||
/**
|
||||
* @param string $path
|
||||
* @param array $mutations
|
||||
* @param PropPatch $propPatch
|
||||
* @return int
|
||||
*/
|
||||
function updatePrincipal($path, $mutations) {
|
||||
function updatePrincipal($path, PropPatch $propPatch) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $prefixPath
|
||||
* @param array $searchProperties
|
||||
* @param string $test
|
||||
* @return array
|
||||
*/
|
||||
function searchPrincipals($prefixPath, array $searchProperties) {
|
||||
function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof') {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @return string
|
||||
*/
|
||||
function findByUri($uri) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Felix Moeller <mail@felixmoeller.de>
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Robin Appelman <icewind@owncloud.com>
|
||||
* @author Robin McCorkell <rmccorkell@karoshi.org.uk>
|
||||
* @author scambra <sergio@entrecables.com>
|
||||
* @author Scrutinizer Auto-Fixer <auto-fixer@scrutinizer-ci.com>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
use Sabre\DAV\URLUtil;
|
||||
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
/**
|
||||
* This plugin check user quota and deny creating files when they exceeds the quota.
|
||||
|
@ -34,7 +9,7 @@ use Sabre\DAV\URLUtil;
|
|||
* @copyright Copyright (C) 2012 entreCables S.L. All rights reserved.
|
||||
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
|
||||
*/
|
||||
class OC_Connector_Sabre_QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
||||
class QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
||||
|
||||
/**
|
||||
* @var \OC\Files\View
|
||||
|
@ -70,8 +45,8 @@ class OC_Connector_Sabre_QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
|
||||
$this->server = $server;
|
||||
|
||||
$server->subscribeEvent('beforeWriteContent', array($this, 'checkQuota'), 10);
|
||||
$server->subscribeEvent('beforeCreateFile', array($this, 'checkQuota'), 10);
|
||||
$server->on('beforeWriteContent', array($this, 'checkQuota'), 10);
|
||||
$server->on('beforeCreateFile', array($this, 'checkQuota'), 10);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,11 +63,11 @@ class OC_Connector_Sabre_QuotaPlugin extends \Sabre\DAV\ServerPlugin {
|
|||
if (substr($uri, 0, 1) !== '/') {
|
||||
$uri = '/' . $uri;
|
||||
}
|
||||
list($parentUri, $newName) = URLUtil::splitPath($uri);
|
||||
list($parentUri, $newName) = \Sabre\HTTP\URLUtil::splitPath($uri);
|
||||
$req = $this->server->httpRequest;
|
||||
if ($req->getHeader('OC-Chunked')) {
|
||||
$info = OC_FileChunking::decodeName($newName);
|
||||
$chunkHandler = new OC_FileChunking($info);
|
||||
$info = \OC_FileChunking::decodeName($newName);
|
||||
$chunkHandler = new \OC_FileChunking($info);
|
||||
// subtract the already uploaded size to see whether
|
||||
// there is still enough space for the remaining chunks
|
||||
$length -= $chunkHandler->getCurrentSize();
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Bart Visscher <bartv@thisnet.nl>
|
||||
* @author Lukas Reschke <lukas@owncloud.com>
|
||||
* @author Stefan Herbrechtsmeier <stefan@herbrechtsmeier.net>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_Request extends \Sabre\HTTP\Request {
|
||||
/**
|
||||
* Returns the requested uri
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUri() {
|
||||
return \OC::$server->getRequest()->getRequestUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific item from the _SERVER array.
|
||||
*
|
||||
* Do not rely on this feature, it is for internal use only.
|
||||
*
|
||||
* @param string $field
|
||||
* @return string
|
||||
*/
|
||||
public function getRawServerValue($field) {
|
||||
if($field == 'REQUEST_URI') {
|
||||
return $this->getUri();
|
||||
}
|
||||
else{
|
||||
return isset($this->_SERVER[$field])?$this->_SERVER[$field]:null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +1,13 @@
|
|||
<?php
|
||||
namespace OC\Connector\Sabre;
|
||||
|
||||
/**
|
||||
* @author Andreas Fischer <bantu@owncloud.com>
|
||||
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
|
||||
* @author scolebrook <scolebrook@mac.com>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Vincent Petry <pvince81@owncloud.com>
|
||||
* Class \OC\Connector\Sabre\Server
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* This class overrides some methods from @see \Sabre\DAV\Server.
|
||||
*
|
||||
*/
|
||||
class OC_Connector_Sabre_Server extends Sabre\DAV\Server {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $overLoadedUri = null;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
private $ignoreRangeHeader = false;
|
||||
class Server extends \Sabre\DAV\Server {
|
||||
|
||||
/**
|
||||
* @see \Sabre\DAV\Server
|
||||
|
@ -40,261 +15,6 @@ class OC_Connector_Sabre_Server extends Sabre\DAV\Server {
|
|||
public function __construct($treeOrNode = null) {
|
||||
parent::__construct($treeOrNode);
|
||||
self::$exposeVersion = false;
|
||||
}
|
||||
|
||||
public function getRequestUri() {
|
||||
|
||||
if (!is_null($this->overLoadedUri)) {
|
||||
return $this->overLoadedUri;
|
||||
}
|
||||
|
||||
return parent::getRequestUri();
|
||||
}
|
||||
|
||||
public function checkPreconditions($handleAsGET = false) {
|
||||
// chunked upload handling
|
||||
if (isset($_SERVER['HTTP_OC_CHUNKED'])) {
|
||||
$filePath = parent::getRequestUri();
|
||||
list($path, $name) = \Sabre\DAV\URLUtil::splitPath($filePath);
|
||||
$info = OC_FileChunking::decodeName($name);
|
||||
if (!empty($info)) {
|
||||
$filePath = $path . '/' . $info['name'];
|
||||
$this->overLoadedUri = $filePath;
|
||||
}
|
||||
}
|
||||
|
||||
$result = parent::checkPreconditions($handleAsGET);
|
||||
$this->overLoadedUri = null;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getHTTPRange() {
|
||||
if ($this->ignoreRangeHeader) {
|
||||
return null;
|
||||
}
|
||||
return parent::getHTTPRange();
|
||||
}
|
||||
|
||||
protected function httpGet($uri) {
|
||||
$range = $this->getHTTPRange();
|
||||
|
||||
if (OC_App::isEnabled('files_encryption') && $range) {
|
||||
// encryption does not support range requests
|
||||
$this->ignoreRangeHeader = true;
|
||||
}
|
||||
return parent::httpGet($uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Sabre\DAV\Server
|
||||
*/
|
||||
protected function httpPropfind($uri) {
|
||||
|
||||
// $xml = new \Sabre\DAV\XMLReader(file_get_contents('php://input'));
|
||||
$requestedProperties = $this->parsePropFindRequest($this->httpRequest->getBody(true));
|
||||
|
||||
$depth = $this->getHTTPDepth(1);
|
||||
// The only two options for the depth of a propfind is 0 or 1
|
||||
// if ($depth!=0) $depth = 1;
|
||||
|
||||
$newProperties = $this->getPropertiesForPath($uri,$requestedProperties,$depth);
|
||||
|
||||
// This is a multi-status response
|
||||
$this->httpResponse->sendStatus(207);
|
||||
$this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8');
|
||||
$this->httpResponse->setHeader('Vary','Brief,Prefer');
|
||||
|
||||
// Normally this header is only needed for OPTIONS responses, however..
|
||||
// iCal seems to also depend on these being set for PROPFIND. Since
|
||||
// this is not harmful, we'll add it.
|
||||
$features = array('1','3', 'extended-mkcol');
|
||||
foreach($this->plugins as $plugin) {
|
||||
$features = array_merge($features,$plugin->getFeatures());
|
||||
}
|
||||
|
||||
$this->httpResponse->setHeader('DAV',implode(', ',$features));
|
||||
|
||||
$prefer = $this->getHTTPPrefer();
|
||||
$minimal = $prefer['return-minimal'];
|
||||
|
||||
$data = $this->generateMultiStatus($newProperties, $minimal);
|
||||
$this->httpResponse->sendBody($data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Small helper to support PROPFIND with DEPTH_INFINITY.
|
||||
* @param string $path
|
||||
*/
|
||||
private function addPathNodesRecursively(&$nodes, $path) {
|
||||
foreach($this->tree->getChildren($path) as $childNode) {
|
||||
$nodes[$path . '/' . $childNode->getName()] = $childNode;
|
||||
if ($childNode instanceof \Sabre\DAV\ICollection)
|
||||
$this->addPathNodesRecursively($nodes, $path . '/' . $childNode->getName());
|
||||
}
|
||||
}
|
||||
|
||||
public function getPropertiesForPath($path, $propertyNames = array(), $depth = 0) {
|
||||
|
||||
// if ($depth!=0) $depth = 1;
|
||||
|
||||
$path = rtrim($path,'/');
|
||||
|
||||
// This event allows people to intercept these requests early on in the
|
||||
// process.
|
||||
//
|
||||
// We're not doing anything with the result, but this can be helpful to
|
||||
// pre-fetch certain expensive live properties.
|
||||
$this->broadCastEvent('beforeGetPropertiesForPath', array($path, $propertyNames, $depth));
|
||||
|
||||
$returnPropertyList = array();
|
||||
|
||||
$parentNode = $this->tree->getNodeForPath($path);
|
||||
$nodes = array(
|
||||
$path => $parentNode
|
||||
);
|
||||
if ($depth==1 && $parentNode instanceof \Sabre\DAV\ICollection) {
|
||||
foreach($this->tree->getChildren($path) as $childNode)
|
||||
$nodes[$path . '/' . $childNode->getName()] = $childNode;
|
||||
} else if ($depth == self::DEPTH_INFINITY && $parentNode instanceof \Sabre\DAV\ICollection) {
|
||||
$this->addPathNodesRecursively($nodes, $path);
|
||||
}
|
||||
|
||||
// If the propertyNames array is empty, it means all properties are requested.
|
||||
// We shouldn't actually return everything we know though, and only return a
|
||||
// sensible list.
|
||||
$allProperties = count($propertyNames)==0;
|
||||
|
||||
foreach($nodes as $myPath=>$node) {
|
||||
|
||||
$currentPropertyNames = $propertyNames;
|
||||
|
||||
$newProperties = array(
|
||||
'200' => array(),
|
||||
'404' => array(),
|
||||
);
|
||||
|
||||
if ($allProperties) {
|
||||
// Default list of propertyNames, when all properties were requested.
|
||||
$currentPropertyNames = array(
|
||||
'{DAV:}getlastmodified',
|
||||
'{DAV:}getcontentlength',
|
||||
'{DAV:}resourcetype',
|
||||
'{DAV:}quota-used-bytes',
|
||||
'{DAV:}quota-available-bytes',
|
||||
'{DAV:}getetag',
|
||||
'{DAV:}getcontenttype',
|
||||
);
|
||||
}
|
||||
|
||||
// If the resourceType was not part of the list, we manually add it
|
||||
// and mark it for removal. We need to know the resourcetype in order
|
||||
// to make certain decisions about the entry.
|
||||
// WebDAV dictates we should add a / and the end of href's for collections
|
||||
$removeRT = false;
|
||||
if (!in_array('{DAV:}resourcetype',$currentPropertyNames)) {
|
||||
$currentPropertyNames[] = '{DAV:}resourcetype';
|
||||
$removeRT = true;
|
||||
}
|
||||
|
||||
$result = $this->broadcastEvent('beforeGetProperties',array($myPath, $node, &$currentPropertyNames, &$newProperties));
|
||||
// If this method explicitly returned false, we must ignore this
|
||||
// node as it is inaccessible.
|
||||
if ($result===false) continue;
|
||||
|
||||
if (count($currentPropertyNames) > 0) {
|
||||
|
||||
if ($node instanceof \Sabre\DAV\IProperties) {
|
||||
$nodeProperties = $node->getProperties($currentPropertyNames);
|
||||
|
||||
// The getProperties method may give us too much,
|
||||
// properties, in case the implementor was lazy.
|
||||
//
|
||||
// So as we loop through this list, we will only take the
|
||||
// properties that were actually requested and discard the
|
||||
// rest.
|
||||
foreach($currentPropertyNames as $k=>$currentPropertyName) {
|
||||
if (isset($nodeProperties[$currentPropertyName])) {
|
||||
unset($currentPropertyNames[$k]);
|
||||
$newProperties[200][$currentPropertyName] = $nodeProperties[$currentPropertyName];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach($currentPropertyNames as $prop) {
|
||||
|
||||
if (isset($newProperties[200][$prop])) continue;
|
||||
|
||||
switch($prop) {
|
||||
case '{DAV:}getlastmodified' : if ($node->getLastModified()) $newProperties[200][$prop] = new \Sabre\DAV\Property\GetLastModified($node->getLastModified()); break;
|
||||
case '{DAV:}getcontentlength' :
|
||||
if ($node instanceof \Sabre\DAV\IFile) {
|
||||
$size = $node->getSize();
|
||||
if (!is_null($size)) {
|
||||
$newProperties[200][$prop] = 0 + $size;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '{DAV:}quota-used-bytes' :
|
||||
if ($node instanceof \Sabre\DAV\IQuota) {
|
||||
$quotaInfo = $node->getQuotaInfo();
|
||||
$newProperties[200][$prop] = $quotaInfo[0];
|
||||
}
|
||||
break;
|
||||
case '{DAV:}quota-available-bytes' :
|
||||
if ($node instanceof \Sabre\DAV\IQuota) {
|
||||
$quotaInfo = $node->getQuotaInfo();
|
||||
$newProperties[200][$prop] = $quotaInfo[1];
|
||||
}
|
||||
break;
|
||||
case '{DAV:}getetag' : if ($node instanceof \Sabre\DAV\IFile && $etag = $node->getETag()) $newProperties[200][$prop] = $etag; break;
|
||||
case '{DAV:}getcontenttype' : if ($node instanceof \Sabre\DAV\IFile && $ct = $node->getContentType()) $newProperties[200][$prop] = $ct; break;
|
||||
case '{DAV:}supported-report-set' :
|
||||
$reports = array();
|
||||
foreach($this->plugins as $plugin) {
|
||||
$reports = array_merge($reports, $plugin->getSupportedReportSet($myPath));
|
||||
}
|
||||
$newProperties[200][$prop] = new \Sabre\DAV\Property\SupportedReportSet($reports);
|
||||
break;
|
||||
case '{DAV:}resourcetype' :
|
||||
$newProperties[200]['{DAV:}resourcetype'] = new \Sabre\DAV\Property\ResourceType();
|
||||
foreach($this->resourceTypeMapping as $className => $resourceType) {
|
||||
if ($node instanceof $className) $newProperties[200]['{DAV:}resourcetype']->add($resourceType);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// If we were unable to find the property, we will list it as 404.
|
||||
if (!$allProperties && !isset($newProperties[200][$prop])) $newProperties[404][$prop] = null;
|
||||
|
||||
}
|
||||
|
||||
$this->broadcastEvent('afterGetProperties',array(trim($myPath,'/'),&$newProperties, $node));
|
||||
|
||||
$newProperties['href'] = trim($myPath,'/');
|
||||
|
||||
// Its is a WebDAV recommendation to add a trailing slash to collectionnames.
|
||||
// Apple's iCal also requires a trailing slash for principals (rfc 3744), though this is non-standard.
|
||||
if ($myPath!='' && isset($newProperties[200]['{DAV:}resourcetype'])) {
|
||||
$rt = $newProperties[200]['{DAV:}resourcetype'];
|
||||
if ($rt->is('{DAV:}collection') || $rt->is('{DAV:}principal')) {
|
||||
$newProperties['href'] .='/';
|
||||
}
|
||||
}
|
||||
|
||||
// If the resourcetype property was manually added to the requested property list,
|
||||
// we will remove it again.
|
||||
if ($removeRT) unset($newProperties[200]['{DAV:}resourcetype']);
|
||||
|
||||
$returnPropertyList[] = $newProperties;
|
||||
|
||||
}
|
||||
|
||||
return $returnPropertyList;
|
||||
|
||||
$this->enablePropfindDepthInfinity = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,9 +83,10 @@ class TagList extends DAV\Property {
|
|||
* It will only decode tag values.
|
||||
*
|
||||
* @param \DOMElement $dom
|
||||
* @param array $propertyMap
|
||||
* @return \OC\Connector\Sabre\TagList
|
||||
*/
|
||||
static function unserialize(\DOMElement $dom) {
|
||||
static function unserialize(\DOMElement $dom, array $propertyMap) {
|
||||
|
||||
$tags = array();
|
||||
foreach($dom->childNodes as $child) {
|
||||
|
|
|
@ -41,6 +41,9 @@ namespace OC\Connector\Sabre;
|
|||
*
|
||||
*/
|
||||
|
||||
use \Sabre\DAV\PropFind;
|
||||
use \Sabre\DAV\PropPatch;
|
||||
|
||||
class TagsPlugin extends \Sabre\DAV\ServerPlugin
|
||||
{
|
||||
|
||||
|
@ -76,13 +79,19 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin
|
|||
private $cachedTags;
|
||||
|
||||
/**
|
||||
* @var \Sabre\DAV\Tree
|
||||
*/
|
||||
private $tree;
|
||||
|
||||
/**
|
||||
* @param \Sabre\DAV\Tree $tree tree
|
||||
* @param \OCP\ITagManager $tagManager tag manager
|
||||
*/
|
||||
public function __construct(\Sabre\DAV\ObjectTree $objectTree, \OCP\ITagManager $tagManager) {
|
||||
$this->objectTree = $objectTree;
|
||||
public function __construct(\Sabre\DAV\Tree $tree, \OCP\ITagManager $tagManager) {
|
||||
$this->tree = $tree;
|
||||
$this->tagManager = $tagManager;
|
||||
$this->tagger = null;
|
||||
$this->cachedTags = null;
|
||||
$this->cachedTags = array();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,25 +111,8 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin
|
|||
$server->propertyMap[self::TAGS_PROPERTYNAME] = 'OC\\Connector\\Sabre\\TagList';
|
||||
|
||||
$this->server = $server;
|
||||
$this->server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties'));
|
||||
$this->server->subscribeEvent('beforeGetPropertiesForPath', array($this, 'beforeGetPropertiesForPath'));
|
||||
$this->server->subscribeEvent('updateProperties', array($this, 'updateProperties'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches and removes a value from the given array
|
||||
*
|
||||
* @param array $requestedProps
|
||||
* @param string $propName to remove
|
||||
* @return boolean true if the property was present, false otherwise
|
||||
*/
|
||||
private function findAndRemoveProperty(&$requestedProps, $propName) {
|
||||
$index = array_search($propName, $requestedProps);
|
||||
if ($index !== false) {
|
||||
unset($requestedProps[$index]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
$this->server->on('propFind', array($this, 'handleGetProperties'));
|
||||
$this->server->on('propPatch', array($this, 'handleUpdateProperties'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -166,7 +158,10 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin
|
|||
return $this->cachedTags[$fileId];
|
||||
} else {
|
||||
$tags = $this->getTagger()->getTagsForObjects(array($fileId));
|
||||
if ($tags) {
|
||||
if ($tags !== false) {
|
||||
if (empty($tags)) {
|
||||
return array();
|
||||
}
|
||||
return current($tags);
|
||||
}
|
||||
}
|
||||
|
@ -199,109 +194,99 @@ class TagsPlugin extends \Sabre\DAV\ServerPlugin
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-fetch tags info
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $requestedProperties
|
||||
* @param integer $depth
|
||||
* @return void
|
||||
*/
|
||||
public function beforeGetPropertiesForPath(
|
||||
$path,
|
||||
array $requestedProperties,
|
||||
$depth
|
||||
) {
|
||||
$node = $this->objectTree->getNodeForPath($path);
|
||||
if (!($node instanceof \OC_Connector_Sabre_Directory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->findAndRemoveProperty($requestedProperties, self::TAGS_PROPERTYNAME)
|
||||
|| $this->findAndRemoveProperty($requestedProperties, self::FAVORITE_PROPERTYNAME)
|
||||
) {
|
||||
$fileIds = array();
|
||||
// note: pre-fetching only supported for depth <= 1
|
||||
$folderContent = $node->getChildren();
|
||||
// TODO: refactor somehow with the similar array that is created
|
||||
// in getChildren()
|
||||
foreach ($folderContent as $info) {
|
||||
$fileIds[] = $info->getId();
|
||||
}
|
||||
$tags = $this->getTagger()->getTagsForObjects($fileIds);
|
||||
if ($tags) {
|
||||
$this->cachedTags = $tags;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds tags and favorites properties to the response,
|
||||
* if requested.
|
||||
*
|
||||
* @param string $path
|
||||
* @param PropFind $propFind
|
||||
* @param \Sabre\DAV\INode $node
|
||||
* @param array $requestedProperties
|
||||
* @param array $returnedProperties
|
||||
* @return void
|
||||
*/
|
||||
public function beforeGetProperties(
|
||||
$path,
|
||||
\Sabre\DAV\INode $node,
|
||||
array &$requestedProperties,
|
||||
array &$returnedProperties
|
||||
public function handleGetProperties(
|
||||
PropFind $propFind,
|
||||
\Sabre\DAV\INode $node
|
||||
) {
|
||||
if (!($node instanceof \OC_Connector_Sabre_Node)) {
|
||||
if (!($node instanceof \OC\Connector\Sabre\Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// need prefetch ?
|
||||
if ($node instanceof \OC\Connector\Sabre\Directory
|
||||
&& $propFind->getDepth() !== 0
|
||||
&& (!is_null($propFind->getStatus(self::TAGS_PROPERTYNAME))
|
||||
|| !is_null($propFind->getStatus(self::FAVORITE_PROPERTYNAME))
|
||||
)) {
|
||||
// note: pre-fetching only supported for depth <= 1
|
||||
$folderContent = $node->getChildren();
|
||||
$fileIds[] = (int)$node->getId();
|
||||
foreach ($folderContent as $info) {
|
||||
$fileIds[] = (int)$info->getId();
|
||||
}
|
||||
$tags = $this->getTagger()->getTagsForObjects($fileIds);
|
||||
if ($tags === false) {
|
||||
// the tags API returns false on error...
|
||||
$tags = array();
|
||||
}
|
||||
|
||||
$this->cachedTags = $this->cachedTags + $tags;
|
||||
$emptyFileIds = array_diff($fileIds, array_keys($tags));
|
||||
// also cache the ones that were not found
|
||||
foreach ($emptyFileIds as $fileId) {
|
||||
$this->cachedTags[$fileId] = [];
|
||||
}
|
||||
}
|
||||
|
||||
$tags = null;
|
||||
$isFav = null;
|
||||
if ($this->findAndRemoveProperty($requestedProperties, self::TAGS_PROPERTYNAME)) {
|
||||
|
||||
$propFind->handle(self::TAGS_PROPERTYNAME, function() use ($tags, &$isFav, $node) {
|
||||
list($tags, $isFav) = $this->getTagsAndFav($node->getId());
|
||||
$returnedProperties[200][self::TAGS_PROPERTYNAME] = new TagList($tags);
|
||||
}
|
||||
if ($this->findAndRemoveProperty($requestedProperties, self::FAVORITE_PROPERTYNAME)) {
|
||||
if (is_null($tags)) {
|
||||
list($tags, $isFav) = $this->getTagsAndFav($node->getId());
|
||||
return new TagList($tags);
|
||||
});
|
||||
|
||||
$propFind->handle(self::FAVORITE_PROPERTYNAME, function() use ($isFav, $node) {
|
||||
if (is_null($isFav)) {
|
||||
list(, $isFav) = $this->getTagsAndFav($node->getId());
|
||||
}
|
||||
$returnedProperties[200][self::FAVORITE_PROPERTYNAME] = $isFav;
|
||||
}
|
||||
return $isFav;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates tags and favorites properties, if applicable.
|
||||
*
|
||||
* @param string $path
|
||||
* @param \Sabre\DAV\INode $node
|
||||
* @param array $requestedProperties
|
||||
* @param array $returnedProperties
|
||||
* @return bool success status
|
||||
* @param PropPatch $propPatch
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function updateProperties(array &$properties, array &$result, \Sabre\DAV\INode $node) {
|
||||
if (!($node instanceof \OC_Connector_Sabre_Node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fileId = $node->getId();
|
||||
if (isset($properties[self::TAGS_PROPERTYNAME])) {
|
||||
$tagsProp = $properties[self::TAGS_PROPERTYNAME];
|
||||
unset($properties[self::TAGS_PROPERTYNAME]);
|
||||
$this->updateTags($fileId, $tagsProp->getTags());
|
||||
$result[200][self::TAGS_PROPERTYNAME] = new TagList($tagsProp->getTags());
|
||||
}
|
||||
if (isset($properties[self::FAVORITE_PROPERTYNAME])) {
|
||||
$favState = $properties[self::FAVORITE_PROPERTYNAME];
|
||||
unset($properties[self::FAVORITE_PROPERTYNAME]);
|
||||
if ((int)$favState === 1 || $favState === 'true') {
|
||||
$favState = true;
|
||||
$this->getTagger()->tagAs($fileId, self::TAG_FAVORITE);
|
||||
} else {
|
||||
$favState = false;
|
||||
$this->getTagger()->unTag($fileId, self::TAG_FAVORITE);
|
||||
public function handleUpdateProperties($path, PropPatch $propPatch) {
|
||||
$propPatch->handle(self::TAGS_PROPERTYNAME, function($tagList) use ($path) {
|
||||
$node = $this->tree->getNodeForPath($path);
|
||||
if (is_null($node)) {
|
||||
return 404;
|
||||
}
|
||||
$result[200][self::FAVORITE_PROPERTYNAME] = $favState;
|
||||
}
|
||||
return true;
|
||||
$this->updateTags($node->getId(), $tagList->getTags());
|
||||
return true;
|
||||
});
|
||||
|
||||
$propPatch->handle(self::FAVORITE_PROPERTYNAME, function($favState) use ($path) {
|
||||
$node = $this->tree->getNodeForPath($path);
|
||||
if (is_null($node)) {
|
||||
return 404;
|
||||
}
|
||||
if ((int)$favState === 1 || $favState === 'true') {
|
||||
$this->getTagger()->tagAs($node->getId(), self::TAG_FAVORITE);
|
||||
} else {
|
||||
$this->getTagger()->unTag($node->getId(), self::TAG_FAVORITE);
|
||||
}
|
||||
|
||||
if (is_null($favState)) {
|
||||
// confirm deletion
|
||||
return 204;
|
||||
}
|
||||
|
||||
return 200;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -382,7 +382,7 @@ abstract class Common implements \OC\Files\Storage\Storage {
|
|||
* @return string|false
|
||||
*/
|
||||
public function getETag($path) {
|
||||
$ETagFunction = \OC_Connector_Sabre_Node::$ETagFunction;
|
||||
$ETagFunction = \OC\Connector\Sabre\Node::$ETagFunction;
|
||||
if ($ETagFunction) {
|
||||
$hash = call_user_func($ETagFunction, $path);
|
||||
return $hash;
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace OC\Files\Storage;
|
|||
|
||||
use OCP\Files\StorageInvalidException;
|
||||
use OCP\Files\StorageNotAvailableException;
|
||||
use Sabre\DAV\Exception;
|
||||
use Sabre\DAV\ClientHttpException;
|
||||
|
||||
class DAV extends \OC\Files\Storage\Common {
|
||||
protected $password;
|
||||
|
@ -104,6 +104,7 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
);
|
||||
|
||||
$this->client = new \Sabre\DAV\Client($settings);
|
||||
$this->client->setThrowExceptions(true);
|
||||
|
||||
if ($this->secure === true && $this->certPath) {
|
||||
$this->client->addTrustedCertificates($this->certPath);
|
||||
|
@ -152,9 +153,10 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
}
|
||||
\OC\Files\Stream\Dir::register($id, $content);
|
||||
return opendir('fakedir://' . $id);
|
||||
} catch (Exception\NotFound $e) {
|
||||
return false;
|
||||
} catch (\Sabre\DAV\Exception $e) {
|
||||
} catch (ClientHttpException $e) {
|
||||
if ($e->getHttpStatus() === 404) {
|
||||
return false;
|
||||
}
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
@ -174,9 +176,10 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
$responseType = $response["{DAV:}resourcetype"]->resourceType;
|
||||
}
|
||||
return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
|
||||
} catch (Exception\NotFound $e) {
|
||||
return false;
|
||||
} catch (\Sabre\DAV\Exception $e) {
|
||||
} catch (ClientHttpException $e) {
|
||||
if ($e->getHttpStatus() === 404) {
|
||||
return false;
|
||||
}
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
@ -192,9 +195,10 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
try {
|
||||
$this->client->propfind($this->encodePath($path), array('{DAV:}resourcetype'));
|
||||
return true; //no 404 exception
|
||||
} catch (Exception\NotFound $e) {
|
||||
return false;
|
||||
} catch (\Sabre\DAV\Exception $e) {
|
||||
} catch (ClientHttpException $e) {
|
||||
if ($e->getHttpStatus() === 404) {
|
||||
return false;
|
||||
}
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
@ -311,9 +315,10 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
if ($this->file_exists($path)) {
|
||||
try {
|
||||
$this->client->proppatch($this->encodePath($path), array('{DAV:}lastmodified' => $mtime));
|
||||
} catch (Exception\NotImplemented $e) {
|
||||
return false;
|
||||
} catch (\Sabre\DAV\Exception $e) {
|
||||
} catch (ClientHttpException $e) {
|
||||
if ($e->getHttpStatus() === 501) {
|
||||
return false;
|
||||
}
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
@ -367,7 +372,7 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
$this->removeCachedFile($path1);
|
||||
$this->removeCachedFile($path2);
|
||||
return true;
|
||||
} catch (\Sabre\DAV\Exception $e) {
|
||||
} catch (ClientHttpException $e) {
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
@ -385,7 +390,7 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
$this->client->request('COPY', $path1, null, array('Destination' => $path2));
|
||||
$this->removeCachedFile($path2);
|
||||
return true;
|
||||
} catch (\Sabre\DAV\Exception $e) {
|
||||
} catch (ClientHttpException $e) {
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
@ -404,11 +409,12 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
'mtime' => strtotime($response['{DAV:}getlastmodified']),
|
||||
'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
|
||||
);
|
||||
} catch (Exception\NotFound $e) {
|
||||
return array();
|
||||
} catch (\Sabre\DAV\Exception $e) {
|
||||
} catch (ClientHttpException $e) {
|
||||
if ($e->getHttpStatus() === 404) {
|
||||
return array();
|
||||
}
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
return array();
|
||||
} catch (\Exception $e) {
|
||||
// TODO: log for now, but in the future need to wrap/rethrow exception
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
|
@ -433,9 +439,10 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception\NotFound $e) {
|
||||
return false;
|
||||
} catch (\Sabre\DAV\Exception $e) {
|
||||
} catch (ClientHttpException $e) {
|
||||
if ($e->getHttpStatus() === 404) {
|
||||
return false;
|
||||
}
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
@ -478,14 +485,11 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
try {
|
||||
$response = $this->client->request($method, $this->encodePath($path), $body);
|
||||
return $response['statusCode'] == $expected;
|
||||
} catch (Exception\NotFound $e) {
|
||||
if ($method === 'DELETE') {
|
||||
} catch (ClientHttpException $e) {
|
||||
if ($e->getHttpStatus() === 404 && $method === 'DELETE') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
} catch (\Sabre\DAV\Exception $e) {
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
|
@ -591,9 +595,10 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
|
||||
return $remoteMtime > $time;
|
||||
}
|
||||
} catch (Exception\NotFound $e) {
|
||||
return false;
|
||||
} catch (Exception $e) {
|
||||
if ($e->getHttpStatus() === 404) {
|
||||
return false;
|
||||
}
|
||||
$this->convertSabreException($e);
|
||||
return false;
|
||||
}
|
||||
|
@ -603,19 +608,19 @@ class DAV extends \OC\Files\Storage\Common {
|
|||
* Convert sabre DAV exception to a storage exception,
|
||||
* then throw it
|
||||
*
|
||||
* @param \Sabre\Dav\Exception $e sabre exception
|
||||
* @param ClientException $e sabre exception
|
||||
* @throws StorageInvalidException if the storage is invalid, for example
|
||||
* when the authentication expired or is invalid
|
||||
* @throws StorageNotAvailableException if the storage is not available,
|
||||
* which might be temporary
|
||||
*/
|
||||
private function convertSabreException(\Sabre\Dav\Exception $e) {
|
||||
private function convertSabreException(ClientException $e) {
|
||||
\OCP\Util::writeLog('files_external', $e->getMessage(), \OCP\Util::ERROR);
|
||||
if ($e instanceof \Sabre\DAV\Exception\NotAuthenticated) {
|
||||
if ($e->getHttpStatus() === 401) {
|
||||
// either password was changed or was invalid all along
|
||||
throw new StorageInvalidException(get_class($e).': '.$e->getMessage());
|
||||
} else if ($e instanceof \Sabre\DAV\Exception\MethodNotAllowed) {
|
||||
// ignore exception, false will be returned
|
||||
} else if ($e->getHttpStatus() === 405) {
|
||||
// ignore exception for MethodNotAllowed, false will be returned
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Christopher Schäpers <kondou@ts.unde.re>
|
||||
* @author Thomas Tanghus <thomas@tanghus.net>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
namespace OC\VObject;
|
||||
|
||||
/**
|
||||
* This class overrides \Sabre\VObject\Property::serialize() to not
|
||||
* double escape commas and semi-colons in compound properties.
|
||||
*/
|
||||
class CompoundProperty extends \Sabre\VObject\Property\Compound {
|
||||
|
||||
/**
|
||||
* Turns the object back into a serialized blob.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function serialize() {
|
||||
|
||||
$str = $this->name;
|
||||
if ($this->group) {
|
||||
$str = $this->group . '.' . $this->name;
|
||||
}
|
||||
|
||||
foreach($this->parameters as $param) {
|
||||
$str.=';' . $param->serialize();
|
||||
}
|
||||
$src = array(
|
||||
"\n",
|
||||
);
|
||||
$out = array(
|
||||
'\n',
|
||||
);
|
||||
$str.=':' . str_replace($src, $out, $this->value);
|
||||
|
||||
$out = '';
|
||||
while(strlen($str) > 0) {
|
||||
if (strlen($str) > 75) {
|
||||
$out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n";
|
||||
$str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8');
|
||||
} else {
|
||||
$out .= $str . "\r\n";
|
||||
$str = '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Christopher Schäpers <kondou@ts.unde.re>
|
||||
* @author Thomas Tanghus <thomas@tanghus.net>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
namespace OC\VObject;
|
||||
|
||||
/**
|
||||
* This class overrides \Sabre\VObject\Property::serialize() properly
|
||||
* escape commas and semi-colons in string properties.
|
||||
*/
|
||||
class StringProperty extends \Sabre\VObject\Property {
|
||||
|
||||
/**
|
||||
* Turns the object back into a serialized blob.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function serialize() {
|
||||
|
||||
$str = $this->name;
|
||||
if ($this->group) {
|
||||
$str = $this->group . '.' . $this->name;
|
||||
}
|
||||
|
||||
foreach($this->parameters as $param) {
|
||||
$str.=';' . $param->serialize();
|
||||
}
|
||||
|
||||
$src = array(
|
||||
'\\',
|
||||
"\n",
|
||||
';',
|
||||
',',
|
||||
);
|
||||
$out = array(
|
||||
'\\\\',
|
||||
'\n',
|
||||
'\;',
|
||||
'\,',
|
||||
);
|
||||
$value = strtr($this->value, array('\,' => ',', '\;' => ';', '\\\\' => '\\'));
|
||||
$str.=':' . str_replace($src, $out, $value);
|
||||
|
||||
$out = '';
|
||||
while(strlen($str) > 0) {
|
||||
if (strlen($str) > 75) {
|
||||
$out .= mb_strcut($str, 0, 75, 'utf-8') . "\r\n";
|
||||
$str = ' ' . mb_strcut($str, 75, strlen($str), 'utf-8');
|
||||
} else {
|
||||
$out .= $str . "\r\n";
|
||||
$str = '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $out;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Connector\Sabre;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
class CustomPropertiesBackend extends \Test\TestCase {
|
||||
|
||||
/**
|
||||
* @var \Sabre\DAV\Server
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* @var \Sabre\DAV\ObjectTree
|
||||
*/
|
||||
private $tree;
|
||||
|
||||
/**
|
||||
* @var \OC\Connector\Sabre\CustomPropertiesBackend
|
||||
*/
|
||||
private $plugin;
|
||||
|
||||
/**
|
||||
* @var \OCP\IUser
|
||||
*/
|
||||
private $user;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->server = new \Sabre\DAV\Server();
|
||||
$this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$userId = $this->getUniqueID('testcustompropertiesuser');
|
||||
|
||||
$this->user = $this->getMock('\OCP\IUser');
|
||||
$this->user->expects($this->any())
|
||||
->method('getUID')
|
||||
->will($this->returnValue($userId));
|
||||
|
||||
$this->plugin = new \OC\Connector\Sabre\CustomPropertiesBackend(
|
||||
$this->tree,
|
||||
\OC::$server->getDatabaseConnection(),
|
||||
$this->user
|
||||
);
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
$connection = \OC::$server->getDatabaseConnection();
|
||||
$deleteStatement = $connection->prepare(
|
||||
'DELETE FROM `*PREFIX*properties`' .
|
||||
' WHERE `userid` = ?'
|
||||
);
|
||||
$deleteStatement->execute(
|
||||
array(
|
||||
$this->user->getUID(),
|
||||
)
|
||||
);
|
||||
$deleteStatement->closeCursor();
|
||||
}
|
||||
|
||||
private function createTestNode($class) {
|
||||
$node = $this->getMockBuilder($class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$node->expects($this->any())
|
||||
->method('getId')
|
||||
->will($this->returnValue(123));
|
||||
|
||||
$node->expects($this->any())
|
||||
->method('getPath')
|
||||
->will($this->returnValue('/dummypath'));
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function applyDefaultProps($path = '/dummypath') {
|
||||
// properties to set
|
||||
$propPatch = new \Sabre\DAV\PropPatch(array(
|
||||
'customprop' => 'value1',
|
||||
'customprop2' => 'value2',
|
||||
));
|
||||
|
||||
$this->plugin->propPatch(
|
||||
$path,
|
||||
$propPatch
|
||||
);
|
||||
|
||||
$propPatch->commit();
|
||||
|
||||
$this->assertEmpty($propPatch->getRemainingMutations());
|
||||
|
||||
$result = $propPatch->getResult();
|
||||
$this->assertEquals(200, $result['customprop']);
|
||||
$this->assertEquals(200, $result['customprop2']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test setting/getting properties
|
||||
*/
|
||||
public function testSetGetPropertiesForFile() {
|
||||
$node = $this->createTestNode('\OC\Connector\Sabre\File');
|
||||
$this->tree->expects($this->any())
|
||||
->method('getNodeForPath')
|
||||
->with('/dummypath')
|
||||
->will($this->returnValue($node));
|
||||
|
||||
$this->applyDefaultProps();
|
||||
|
||||
$propFind = new \Sabre\DAV\PropFind(
|
||||
'/dummypath',
|
||||
array(
|
||||
'customprop',
|
||||
'customprop2',
|
||||
'unsetprop',
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
$this->plugin->propFind(
|
||||
'/dummypath',
|
||||
$propFind
|
||||
);
|
||||
|
||||
$this->assertEquals('value1', $propFind->get('customprop'));
|
||||
$this->assertEquals('value2', $propFind->get('customprop2'));
|
||||
$this->assertEquals(array('unsetprop'), $propFind->get404Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting properties from directory
|
||||
*/
|
||||
public function testGetPropertiesForDirectory() {
|
||||
$rootNode = $this->createTestNode('\OC\Connector\Sabre\Directory');
|
||||
|
||||
$nodeSub = $this->getMockBuilder('\OC\Connector\Sabre\File')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$nodeSub->expects($this->any())
|
||||
->method('getId')
|
||||
->will($this->returnValue(456));
|
||||
|
||||
$nodeSub->expects($this->any())
|
||||
->method('getPath')
|
||||
->will($this->returnValue('/dummypath/test.txt'));
|
||||
|
||||
$rootNode->expects($this->once())
|
||||
->method('getChildren')
|
||||
->will($this->returnValue(array($nodeSub)));
|
||||
|
||||
$this->tree->expects($this->at(0))
|
||||
->method('getNodeForPath')
|
||||
->with('/dummypath')
|
||||
->will($this->returnValue($rootNode));
|
||||
|
||||
$this->tree->expects($this->at(1))
|
||||
->method('getNodeForPath')
|
||||
->with('/dummypath/test.txt')
|
||||
->will($this->returnValue($nodeSub));
|
||||
|
||||
$this->tree->expects($this->at(2))
|
||||
->method('getNodeForPath')
|
||||
->with('/dummypath')
|
||||
->will($this->returnValue($rootNode));
|
||||
|
||||
$this->tree->expects($this->at(3))
|
||||
->method('getNodeForPath')
|
||||
->with('/dummypath/test.txt')
|
||||
->will($this->returnValue($nodeSub));
|
||||
|
||||
$this->applyDefaultProps('/dummypath');
|
||||
$this->applyDefaultProps('/dummypath/test.txt');
|
||||
|
||||
$propNames = array(
|
||||
'customprop',
|
||||
'customprop2',
|
||||
'unsetprop',
|
||||
);
|
||||
|
||||
$propFindRoot = new \Sabre\DAV\PropFind(
|
||||
'/dummypath',
|
||||
$propNames,
|
||||
1
|
||||
);
|
||||
|
||||
$propFindSub = new \Sabre\DAV\PropFind(
|
||||
'/dummypath/test.txt',
|
||||
$propNames,
|
||||
0
|
||||
);
|
||||
|
||||
$this->plugin->propFind(
|
||||
'/dummypath',
|
||||
$propFindRoot
|
||||
);
|
||||
|
||||
$this->plugin->propFind(
|
||||
'/dummypath/test.txt',
|
||||
$propFindSub
|
||||
);
|
||||
|
||||
// TODO: find a way to assert that no additional SQL queries were
|
||||
// run while doing the second propFind
|
||||
|
||||
$this->assertEquals('value1', $propFindRoot->get('customprop'));
|
||||
$this->assertEquals('value2', $propFindRoot->get('customprop2'));
|
||||
$this->assertEquals(array('unsetprop'), $propFindRoot->get404Properties());
|
||||
|
||||
$this->assertEquals('value1', $propFindSub->get('customprop'));
|
||||
$this->assertEquals('value2', $propFindSub->get('customprop2'));
|
||||
$this->assertEquals(array('unsetprop'), $propFindSub->get404Properties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test delete property
|
||||
*/
|
||||
public function testDeleteProperty() {
|
||||
$node = $this->createTestNode('\OC\Connector\Sabre\File');
|
||||
$this->tree->expects($this->any())
|
||||
->method('getNodeForPath')
|
||||
->with('/dummypath')
|
||||
->will($this->returnValue($node));
|
||||
|
||||
$this->applyDefaultProps();
|
||||
|
||||
$propPatch = new \Sabre\DAV\PropPatch(array(
|
||||
'customprop' => null,
|
||||
));
|
||||
|
||||
$this->plugin->propPatch(
|
||||
'/dummypath',
|
||||
$propPatch
|
||||
);
|
||||
|
||||
$propPatch->commit();
|
||||
|
||||
$this->assertEmpty($propPatch->getRemainingMutations());
|
||||
|
||||
$result = $propPatch->getResult();
|
||||
$this->assertEquals(204, $result['customprop']);
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
|
|||
->method('getPath')
|
||||
->will($this->returnValue(''));
|
||||
|
||||
return new OC_Connector_Sabre_Directory($this->view, $this->info);
|
||||
return new \OC\Connector\Sabre\Directory($this->view, $this->info);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -131,7 +131,7 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
|
|||
->method('getRelativePath')
|
||||
->will($this->returnValue(''));
|
||||
|
||||
$dir = new OC_Connector_Sabre_Directory($this->view, $this->info);
|
||||
$dir = new \OC\Connector\Sabre\Directory($this->view, $this->info);
|
||||
$nodes = $dir->getChildren();
|
||||
|
||||
$this->assertEquals(2, count($nodes));
|
||||
|
@ -139,21 +139,6 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
|
|||
// calling a second time just returns the cached values,
|
||||
// does not call getDirectoryContents again
|
||||
$nodes = $dir->getChildren();
|
||||
|
||||
$properties = array('testprop', OC_Connector_Sabre_Node::GETETAG_PROPERTYNAME);
|
||||
$this->assertEquals(2, count($nodes));
|
||||
$this->assertEquals(
|
||||
array(
|
||||
OC_Connector_Sabre_Node::GETETAG_PROPERTYNAME => '"abc"'
|
||||
),
|
||||
$nodes[0]->getProperties($properties)
|
||||
);
|
||||
$this->assertEquals(
|
||||
array(
|
||||
OC_Connector_Sabre_Node::GETETAG_PROPERTYNAME => '"def"'
|
||||
),
|
||||
$nodes[1]->getProperties($properties)
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetQuotaInfo() {
|
||||
|
@ -182,7 +167,7 @@ class Test_OC_Connector_Sabre_Directory extends \Test\TestCase {
|
|||
->method('getStorage')
|
||||
->will($this->returnValue($storage));
|
||||
|
||||
$dir = new OC_Connector_Sabre_Directory($this->view, $this->info);
|
||||
$dir = new \OC\Connector\Sabre\Directory($this->view, $this->info);
|
||||
$this->assertEquals([200, 800], $dir->getQuotaInfo()); //200 used, 800 free
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
|
|||
'permissions'=>\OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
$file = new OC_Connector_Sabre_File($view, $info);
|
||||
$file = new \OC\Connector\Sabre\File($view, $info);
|
||||
|
||||
// action
|
||||
$file->put('test data');
|
||||
|
@ -52,7 +52,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
|
|||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
$file = new OC_Connector_Sabre_File($view, $info);
|
||||
$file = new \OC\Connector\Sabre\File($view, $info);
|
||||
|
||||
$this->assertNotEmpty($file->put('test data'));
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
|
|||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
$file = new OC_Connector_Sabre_File($view, $info);
|
||||
$file = new \OC\Connector\Sabre\File($view, $info);
|
||||
|
||||
// action
|
||||
$file->put('test data');
|
||||
|
@ -109,7 +109,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
|
|||
$info = new \OC\Files\FileInfo('/super*star.txt', null, null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
$file = new OC_Connector_Sabre_File($view, $info);
|
||||
$file = new \OC\Connector\Sabre\File($view, $info);
|
||||
|
||||
// action
|
||||
$file->put('test data');
|
||||
|
@ -130,7 +130,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
|
|||
$info = new \OC\Files\FileInfo('/super*star.txt', null, null, array(
|
||||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
$file = new OC_Connector_Sabre_File($view, $info);
|
||||
$file = new \OC\Connector\Sabre\File($view, $info);
|
||||
$file->setName('/super*star.txt');
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
|
|||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
$file = new OC_Connector_Sabre_File($view, $info);
|
||||
$file = new \OC\Connector\Sabre\File($view, $info);
|
||||
|
||||
// action
|
||||
$file->put('test data');
|
||||
|
@ -185,7 +185,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
|
|||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
$file = new OC_Connector_Sabre_File($view, $info);
|
||||
$file = new \OC\Connector\Sabre\File($view, $info);
|
||||
|
||||
// action
|
||||
$file->delete();
|
||||
|
@ -203,7 +203,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
|
|||
'permissions' => 0
|
||||
), null);
|
||||
|
||||
$file = new OC_Connector_Sabre_File($view, $info);
|
||||
$file = new \OC\Connector\Sabre\File($view, $info);
|
||||
|
||||
// action
|
||||
$file->delete();
|
||||
|
@ -226,7 +226,7 @@ class Test_OC_Connector_Sabre_File extends \Test\TestCase {
|
|||
'permissions' => \OCP\Constants::PERMISSION_ALL
|
||||
), null);
|
||||
|
||||
$file = new OC_Connector_Sabre_File($view, $info);
|
||||
$file = new \OC\Connector\Sabre\File($view, $info);
|
||||
|
||||
// action
|
||||
$file->delete();
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Connector\Sabre;
|
||||
|
||||
/**
|
||||
* Copyright (c) 2015 Vincent Petry <pvince81@owncloud.com>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
class FilesPlugin extends \Test\TestCase {
|
||||
const GETETAG_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::GETETAG_PROPERTYNAME;
|
||||
const FILEID_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::FILEID_PROPERTYNAME;
|
||||
const SIZE_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::SIZE_PROPERTYNAME;
|
||||
const PERMISSIONS_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::PERMISSIONS_PROPERTYNAME;
|
||||
const GETLASTMODIFIED_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::GETLASTMODIFIED_PROPERTYNAME;
|
||||
const DOWNLOADURL_PROPERTYNAME = \OC\Connector\Sabre\FilesPlugin::DOWNLOADURL_PROPERTYNAME;
|
||||
|
||||
/**
|
||||
* @var \Sabre\DAV\Server
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* @var \Sabre\DAV\ObjectTree
|
||||
*/
|
||||
private $tree;
|
||||
|
||||
/**
|
||||
* @var \OC\Connector\Sabre\FilesPlugin
|
||||
*/
|
||||
private $plugin;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->server = new \Sabre\DAV\Server();
|
||||
$this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->plugin = new \OC\Connector\Sabre\FilesPlugin($this->tree);
|
||||
$this->plugin->initialize($this->server);
|
||||
}
|
||||
|
||||
private function createTestNode($class) {
|
||||
$node = $this->getMockBuilder($class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$node->expects($this->any())
|
||||
->method('getId')
|
||||
->will($this->returnValue(123));
|
||||
|
||||
$this->tree->expects($this->any())
|
||||
->method('getNodeForPath')
|
||||
->with('/dummypath')
|
||||
->will($this->returnValue($node));
|
||||
|
||||
$node->expects($this->any())
|
||||
->method('getFileId')
|
||||
->will($this->returnValue(123));
|
||||
$node->expects($this->any())
|
||||
->method('getEtag')
|
||||
->will($this->returnValue('"abc"'));
|
||||
$node->expects($this->any())
|
||||
->method('getDavPermissions')
|
||||
->will($this->returnValue('R'));
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function testGetPropertiesForFile() {
|
||||
$node = $this->createTestNode('\OC\Connector\Sabre\File');
|
||||
|
||||
$propFind = new \Sabre\DAV\PropFind(
|
||||
'/dummyPath',
|
||||
array(
|
||||
self::GETETAG_PROPERTYNAME,
|
||||
self::FILEID_PROPERTYNAME,
|
||||
self::SIZE_PROPERTYNAME,
|
||||
self::PERMISSIONS_PROPERTYNAME,
|
||||
self::DOWNLOADURL_PROPERTYNAME,
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
$node->expects($this->once())
|
||||
->method('getDirectDownload')
|
||||
->will($this->returnValue(array('url' => 'http://example.com/')));
|
||||
$node->expects($this->never())
|
||||
->method('getSize');
|
||||
|
||||
$this->plugin->handleGetProperties(
|
||||
$propFind,
|
||||
$node
|
||||
);
|
||||
|
||||
$this->assertEquals('"abc"', $propFind->get(self::GETETAG_PROPERTYNAME));
|
||||
$this->assertEquals(123, $propFind->get(self::FILEID_PROPERTYNAME));
|
||||
$this->assertEquals(null, $propFind->get(self::SIZE_PROPERTYNAME));
|
||||
$this->assertEquals('R', $propFind->get(self::PERMISSIONS_PROPERTYNAME));
|
||||
$this->assertEquals('http://example.com/', $propFind->get(self::DOWNLOADURL_PROPERTYNAME));
|
||||
$this->assertEquals(array(self::SIZE_PROPERTYNAME), $propFind->get404Properties());
|
||||
}
|
||||
|
||||
public function testGetPropertiesForDirectory() {
|
||||
$node = $this->createTestNode('\OC\Connector\Sabre\Directory');
|
||||
|
||||
$propFind = new \Sabre\DAV\PropFind(
|
||||
'/dummyPath',
|
||||
array(
|
||||
self::GETETAG_PROPERTYNAME,
|
||||
self::FILEID_PROPERTYNAME,
|
||||
self::SIZE_PROPERTYNAME,
|
||||
self::PERMISSIONS_PROPERTYNAME,
|
||||
self::DOWNLOADURL_PROPERTYNAME,
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
$node->expects($this->never())
|
||||
->method('getDirectDownload');
|
||||
$node->expects($this->once())
|
||||
->method('getSize')
|
||||
->will($this->returnValue(1025));
|
||||
|
||||
$this->plugin->handleGetProperties(
|
||||
$propFind,
|
||||
$node
|
||||
);
|
||||
|
||||
$this->assertEquals('"abc"', $propFind->get(self::GETETAG_PROPERTYNAME));
|
||||
$this->assertEquals(123, $propFind->get(self::FILEID_PROPERTYNAME));
|
||||
$this->assertEquals(1025, $propFind->get(self::SIZE_PROPERTYNAME));
|
||||
$this->assertEquals('R', $propFind->get(self::PERMISSIONS_PROPERTYNAME));
|
||||
$this->assertEquals(null, $propFind->get(self::DOWNLOADURL_PROPERTYNAME));
|
||||
$this->assertEquals(array(self::DOWNLOADURL_PROPERTYNAME), $propFind->get404Properties());
|
||||
}
|
||||
|
||||
public function testUpdateProps() {
|
||||
$node = $this->createTestNode('\OC\Connector\Sabre\File');
|
||||
|
||||
$testDate = 'Fri, 13 Feb 2015 00:01:02 GMT';
|
||||
|
||||
$node->expects($this->once())
|
||||
->method('touch')
|
||||
->with($testDate);
|
||||
|
||||
$node->expects($this->once())
|
||||
->method('setEtag')
|
||||
->with('newetag')
|
||||
->will($this->returnValue(true));
|
||||
|
||||
// properties to set
|
||||
$propPatch = new \Sabre\DAV\PropPatch(array(
|
||||
self::GETETAG_PROPERTYNAME => 'newetag',
|
||||
self::GETLASTMODIFIED_PROPERTYNAME => $testDate
|
||||
));
|
||||
|
||||
$this->plugin->handleUpdateProperties(
|
||||
'/dummypath',
|
||||
$propPatch
|
||||
);
|
||||
|
||||
$propPatch->commit();
|
||||
|
||||
$this->assertEmpty($propPatch->getRemainingMutations());
|
||||
|
||||
$result = $propPatch->getResult();
|
||||
$this->assertEquals(200, $result[self::GETLASTMODIFIED_PROPERTYNAME]);
|
||||
$this->assertEquals(200, $result[self::GETETAG_PROPERTYNAME]);
|
||||
}
|
||||
|
||||
}
|
|
@ -49,7 +49,7 @@ class Node extends \Test\TestCase {
|
|||
->will($this->returnValue($type));
|
||||
$view = $this->getMock('\OC\Files\View');
|
||||
|
||||
$node = new \OC_Connector_Sabre_File($view, $info);
|
||||
$node = new \OC\Connector\Sabre\File($view, $info);
|
||||
$this->assertEquals($expected, $node->getDavPermissions());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Test\OC\Connector\Sabre;
|
|||
|
||||
|
||||
use OC\Files\FileInfo;
|
||||
use OC_Connector_Sabre_Directory;
|
||||
use OC\Connector\Sabre\Directory;
|
||||
use PHPUnit_Framework_TestCase;
|
||||
|
||||
class TestDoubleFileView extends \OC\Files\View {
|
||||
|
@ -103,7 +103,7 @@ class ObjectTree extends \Test\TestCase {
|
|||
|
||||
$info = new FileInfo('', null, null, array(), null);
|
||||
|
||||
$rootDir = new OC_Connector_Sabre_Directory($view, $info);
|
||||
$rootDir = new Directory($view, $info);
|
||||
$objectTree = $this->getMock('\OC\Connector\Sabre\ObjectTree',
|
||||
array('nodeExists', 'getNodeForPath'),
|
||||
array($rootDir, $view));
|
||||
|
@ -119,4 +119,123 @@ class ObjectTree extends \Test\TestCase {
|
|||
$objectTree->move($source, $dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider nodeForPathProvider
|
||||
*/
|
||||
public function testGetNodeForPath(
|
||||
$inputFileName,
|
||||
$fileInfoQueryPath,
|
||||
$outputFileName,
|
||||
$type,
|
||||
$enableChunkingHeader
|
||||
) {
|
||||
|
||||
if ($enableChunkingHeader) {
|
||||
$_SERVER['HTTP_OC_CHUNKED'] = true;
|
||||
}
|
||||
|
||||
$rootNode = $this->getMockBuilder('\OC\Connector\Sabre\Directory')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mountManager = $this->getMock('\OC\Files\Mount\Manager');
|
||||
$view = $this->getMock('\OC\Files\View');
|
||||
$fileInfo = $this->getMock('\OCP\Files\FileInfo');
|
||||
$fileInfo->expects($this->once())
|
||||
->method('getType')
|
||||
->will($this->returnValue($type));
|
||||
$fileInfo->expects($this->once())
|
||||
->method('getName')
|
||||
->will($this->returnValue($outputFileName));
|
||||
|
||||
$view->expects($this->once())
|
||||
->method('getFileInfo')
|
||||
->with($fileInfoQueryPath)
|
||||
->will($this->returnValue($fileInfo));
|
||||
|
||||
$tree = new \OC\Connector\Sabre\ObjectTree();
|
||||
$tree->init($rootNode, $view, $mountManager);
|
||||
|
||||
$node = $tree->getNodeForPath($inputFileName);
|
||||
|
||||
$this->assertNotNull($node);
|
||||
$this->assertEquals($outputFileName, $node->getName());
|
||||
|
||||
if ($type === 'file') {
|
||||
$this->assertTrue($node instanceof \OC\Connector\Sabre\File);
|
||||
} else {
|
||||
$this->assertTrue($node instanceof \OC\Connector\Sabre\Directory);
|
||||
}
|
||||
|
||||
unset($_SERVER['HTTP_OC_CHUNKED']);
|
||||
}
|
||||
|
||||
function nodeForPathProvider() {
|
||||
return array(
|
||||
// regular file
|
||||
array(
|
||||
'regularfile.txt',
|
||||
'regularfile.txt',
|
||||
'regularfile.txt',
|
||||
'file',
|
||||
false
|
||||
),
|
||||
// regular directory
|
||||
array(
|
||||
'regulardir',
|
||||
'regulardir',
|
||||
'regulardir',
|
||||
'dir',
|
||||
false
|
||||
),
|
||||
// regular file with chunking
|
||||
array(
|
||||
'regularfile.txt',
|
||||
'regularfile.txt',
|
||||
'regularfile.txt',
|
||||
'file',
|
||||
true
|
||||
),
|
||||
// regular directory with chunking
|
||||
array(
|
||||
'regulardir',
|
||||
'regulardir',
|
||||
'regulardir',
|
||||
'dir',
|
||||
true
|
||||
),
|
||||
// file with chunky file name
|
||||
array(
|
||||
'regularfile.txt-chunking-123566789-10-1',
|
||||
'regularfile.txt',
|
||||
'regularfile.txt',
|
||||
'file',
|
||||
true
|
||||
),
|
||||
// regular file in subdir
|
||||
array(
|
||||
'subdir/regularfile.txt',
|
||||
'subdir/regularfile.txt',
|
||||
'regularfile.txt',
|
||||
'file',
|
||||
false
|
||||
),
|
||||
// regular directory in subdir
|
||||
array(
|
||||
'subdir/regulardir',
|
||||
'subdir/regulardir',
|
||||
'regulardir',
|
||||
'dir',
|
||||
false
|
||||
),
|
||||
// file with chunky file name in subdir
|
||||
array(
|
||||
'subdir/regularfile.txt-chunking-123566789-10-1',
|
||||
'subdir/regularfile.txt',
|
||||
'regularfile.txt',
|
||||
'file',
|
||||
true
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
namespace Test\Connector\Sabre;
|
||||
|
||||
use \Sabre\DAV\PropPatch;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IConfig;
|
||||
|
||||
|
@ -240,7 +241,7 @@ class Principal extends \Test\TestCase {
|
|||
}
|
||||
|
||||
public function testUpdatePrincipal() {
|
||||
$this->assertSame(0, $this->connector->updatePrincipal('foo', []));
|
||||
$this->assertSame(0, $this->connector->updatePrincipal('foo', new PropPatch(array())));
|
||||
}
|
||||
|
||||
public function testSearchPrincipals() {
|
||||
|
|
|
@ -14,14 +14,14 @@ class Test_OC_Connector_Sabre_QuotaPlugin extends \Test\TestCase {
|
|||
private $server;
|
||||
|
||||
/**
|
||||
* @var OC_Connector_Sabre_QuotaPlugin
|
||||
* @var \OC\Connector\Sabre\QuotaPlugin
|
||||
*/
|
||||
private $plugin;
|
||||
|
||||
private function init($quota) {
|
||||
$view = $this->buildFileViewMock($quota);
|
||||
$this->server = new \Sabre\DAV\Server();
|
||||
$this->plugin = new OC_Connector_Sabre_QuotaPlugin($view);
|
||||
$this->plugin = new \OC\Connector\Sabre\QuotaPlugin($view);
|
||||
$this->plugin->initialize($this->server);
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ class Test_OC_Connector_Sabre_QuotaPlugin extends \Test\TestCase {
|
|||
*/
|
||||
public function testLength($expected, $headers) {
|
||||
$this->init(0);
|
||||
$this->server->httpRequest = new \Sabre\HTTP\Request($headers);
|
||||
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
||||
$length = $this->plugin->getLength();
|
||||
$this->assertEquals($expected, $length);
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class Test_OC_Connector_Sabre_QuotaPlugin extends \Test\TestCase {
|
|||
public function testCheckQuota($quota, $headers) {
|
||||
$this->init($quota);
|
||||
|
||||
$this->server->httpRequest = new Sabre\HTTP\Request($headers);
|
||||
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
||||
$result = $this->plugin->checkQuota('');
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
@ -53,39 +53,39 @@ class Test_OC_Connector_Sabre_QuotaPlugin extends \Test\TestCase {
|
|||
public function testCheckExceededQuota($quota, $headers) {
|
||||
$this->init($quota);
|
||||
|
||||
$this->server->httpRequest = new Sabre\HTTP\Request($headers);
|
||||
$this->server->httpRequest = new \Sabre\HTTP\Request(null, null, $headers);
|
||||
$this->plugin->checkQuota('');
|
||||
}
|
||||
|
||||
public function quotaOkayProvider() {
|
||||
return array(
|
||||
array(1024, array()),
|
||||
array(1024, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')),
|
||||
array(1024, array('HTTP_CONTENT_LENGTH' => '512')),
|
||||
array(1024, array('HTTP_OC_TOTAL_LENGTH' => '1024', 'HTTP_CONTENT_LENGTH' => '512')),
|
||||
// \OCP\Files\FileInfo::SPACE_UNKNOWN = -2
|
||||
array(1024, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
|
||||
array(1024, array('CONTENT-LENGTH' => '512')),
|
||||
array(1024, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
|
||||
// \OCP\Files\FileInfo::SPACE-UNKNOWN = -2
|
||||
array(-2, array()),
|
||||
array(-2, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')),
|
||||
array(-2, array('HTTP_CONTENT_LENGTH' => '512')),
|
||||
array(-2, array('HTTP_OC_TOTAL_LENGTH' => '1024', 'HTTP_CONTENT_LENGTH' => '512')),
|
||||
array(-2, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
|
||||
array(-2, array('CONTENT-LENGTH' => '512')),
|
||||
array(-2, array('OC-TOTAL-LENGTH' => '1024', 'CONTENT-LENGTH' => '512')),
|
||||
);
|
||||
}
|
||||
|
||||
public function quotaExceededProvider() {
|
||||
return array(
|
||||
array(1023, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')),
|
||||
array(511, array('HTTP_CONTENT_LENGTH' => '512')),
|
||||
array(2047, array('HTTP_OC_TOTAL_LENGTH' => '2048', 'HTTP_CONTENT_LENGTH' => '1024')),
|
||||
array(1023, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
|
||||
array(511, array('CONTENT-LENGTH' => '512')),
|
||||
array(2047, array('OC-TOTAL-LENGTH' => '2048', 'CONTENT-LENGTH' => '1024')),
|
||||
);
|
||||
}
|
||||
|
||||
public function lengthProvider() {
|
||||
return array(
|
||||
array(null, array()),
|
||||
array(1024, array('HTTP_X_EXPECTED_ENTITY_LENGTH' => '1024')),
|
||||
array(512, array('HTTP_CONTENT_LENGTH' => '512')),
|
||||
array(2048, array('HTTP_OC_TOTAL_LENGTH' => '2048', 'HTTP_CONTENT_LENGTH' => '1024')),
|
||||
array(4096, array('HTTP_OC_TOTAL_LENGTH' => '2048', 'HTTP_X_EXPECTED_ENTITY_LENGTH' => '4096')),
|
||||
array(1024, array('X-EXPECTED-ENTITY-LENGTH' => '1024')),
|
||||
array(512, array('CONTENT-LENGTH' => '512')),
|
||||
array(2048, array('OC-TOTAL-LENGTH' => '2048', 'CONTENT-LENGTH' => '1024')),
|
||||
array(4096, array('OC-TOTAL-LENGTH' => '2048', 'X-EXPECTED-ENTITY-LENGTH' => '4096')),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ class TagsPlugin extends \Test\TestCase {
|
|||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->server = new \Sabre\DAV\Server();
|
||||
$this->tree = $this->getMockBuilder('\Sabre\DAV\ObjectTree')
|
||||
$this->tree = $this->getMockBuilder('\Sabre\DAV\Tree')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->tagger = $this->getMock('\OCP\ITags');
|
||||
|
@ -59,7 +59,7 @@ class TagsPlugin extends \Test\TestCase {
|
|||
* @dataProvider tagsGetPropertiesDataProvider
|
||||
*/
|
||||
public function testGetProperties($tags, $requestedProperties, $expectedProperties) {
|
||||
$node = $this->getMockBuilder('\OC_Connector_Sabre_Node')
|
||||
$node = $this->getMockBuilder('\OC\Connector\Sabre\Node')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$node->expects($this->any())
|
||||
|
@ -76,29 +76,35 @@ class TagsPlugin extends \Test\TestCase {
|
|||
->with($this->equalTo(array(123)))
|
||||
->will($this->returnValue(array(123 => $tags)));
|
||||
|
||||
$returnedProperties = array();
|
||||
|
||||
$this->plugin->beforeGetProperties(
|
||||
'',
|
||||
$node,
|
||||
$propFind = new \Sabre\DAV\PropFind(
|
||||
'/dummyPath',
|
||||
$requestedProperties,
|
||||
$returnedProperties
|
||||
0
|
||||
);
|
||||
|
||||
$this->assertEquals($expectedProperties, $returnedProperties);
|
||||
$this->plugin->handleGetProperties(
|
||||
$propFind,
|
||||
$node
|
||||
);
|
||||
|
||||
$result = $propFind->getResultForMultiStatus();
|
||||
|
||||
$this->assertEmpty($result[404]);
|
||||
unset($result[404]);
|
||||
$this->assertEquals($expectedProperties, $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider tagsGetPropertiesDataProvider
|
||||
*/
|
||||
public function testPreloadThenGetProperties($tags, $requestedProperties, $expectedProperties) {
|
||||
$node1 = $this->getMockBuilder('\OC_Connector_Sabre_File')
|
||||
$node1 = $this->getMockBuilder('\OC\Connector\Sabre\File')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$node1->expects($this->any())
|
||||
->method('getId')
|
||||
->will($this->returnValue(111));
|
||||
$node2 = $this->getMockBuilder('\OC_Connector_Sabre_File')
|
||||
$node2 = $this->getMockBuilder('\OC\Connector\Sabre\File')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$node2->expects($this->any())
|
||||
|
@ -113,7 +119,7 @@ class TagsPlugin extends \Test\TestCase {
|
|||
$expectedCallCount = 1;
|
||||
}
|
||||
|
||||
$node = $this->getMockBuilder('\OC_Connector_Sabre_Directory')
|
||||
$node = $this->getMockBuilder('\OC\Connector\Sabre\Directory')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$node->expects($this->any())
|
||||
|
@ -123,14 +129,9 @@ class TagsPlugin extends \Test\TestCase {
|
|||
->method('getChildren')
|
||||
->will($this->returnValue(array($node1, $node2)));
|
||||
|
||||
$this->tree->expects($this->once())
|
||||
->method('getNodeForPath')
|
||||
->with('/subdir')
|
||||
->will($this->returnValue($node));
|
||||
|
||||
$this->tagger->expects($this->exactly($expectedCallCount))
|
||||
->method('getTagsForObjects')
|
||||
->with($this->equalTo(array(111, 222)))
|
||||
->with($this->equalTo(array(123, 111, 222)))
|
||||
->will($this->returnValue(
|
||||
array(
|
||||
111 => $tags,
|
||||
|
@ -138,22 +139,41 @@ class TagsPlugin extends \Test\TestCase {
|
|||
)
|
||||
));
|
||||
|
||||
$returnedProperties = array();
|
||||
|
||||
$this->plugin->beforeGetPropertiesForPath(
|
||||
// simulate sabre recursive PROPFIND traversal
|
||||
$propFindRoot = new \Sabre\DAV\PropFind(
|
||||
'/subdir',
|
||||
$requestedProperties,
|
||||
1
|
||||
);
|
||||
|
||||
$this->plugin->beforeGetProperties(
|
||||
$propFind1 = new \Sabre\DAV\PropFind(
|
||||
'/subdir/test.txt',
|
||||
$node1,
|
||||
$requestedProperties,
|
||||
$returnedProperties
|
||||
0
|
||||
);
|
||||
$propFind2 = new \Sabre\DAV\PropFind(
|
||||
'/subdir/test2.txt',
|
||||
$requestedProperties,
|
||||
0
|
||||
);
|
||||
|
||||
$this->assertEquals($expectedProperties, $returnedProperties);
|
||||
$this->plugin->handleGetProperties(
|
||||
$propFindRoot,
|
||||
$node
|
||||
);
|
||||
$this->plugin->handleGetProperties(
|
||||
$propFind1,
|
||||
$node1
|
||||
);
|
||||
$this->plugin->handleGetProperties(
|
||||
$propFind2,
|
||||
$node2
|
||||
);
|
||||
|
||||
$result = $propFind1->getResultForMultiStatus();
|
||||
|
||||
$this->assertEmpty($result[404]);
|
||||
unset($result[404]);
|
||||
$this->assertEquals($expectedProperties, $result);
|
||||
}
|
||||
|
||||
function tagsGetPropertiesDataProvider() {
|
||||
|
@ -193,7 +213,9 @@ class TagsPlugin extends \Test\TestCase {
|
|||
array(
|
||||
array('tag1', 'tag2', self::TAG_FAVORITE),
|
||||
array(),
|
||||
array(),
|
||||
array(
|
||||
200 => array()
|
||||
),
|
||||
),
|
||||
// request both with none set, receive both
|
||||
array(
|
||||
|
@ -212,13 +234,18 @@ class TagsPlugin extends \Test\TestCase {
|
|||
public function testUpdateTags() {
|
||||
// this test will replace the existing tags "tagremove" with "tag1" and "tag2"
|
||||
// and keep "tagkeep"
|
||||
$node = $this->getMockBuilder('\OC_Connector_Sabre_Node')
|
||||
$node = $this->getMockBuilder('\OC\Connector\Sabre\Node')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$node->expects($this->any())
|
||||
->method('getId')
|
||||
->will($this->returnValue(123));
|
||||
|
||||
$this->tree->expects($this->any())
|
||||
->method('getNodeForPath')
|
||||
->with('/dummypath')
|
||||
->will($this->returnValue($node));
|
||||
|
||||
$this->tagger->expects($this->at(0))
|
||||
->method('getTagsForObjects')
|
||||
->with($this->equalTo(array(123)))
|
||||
|
@ -238,58 +265,109 @@ class TagsPlugin extends \Test\TestCase {
|
|||
->with(123, 'tagremove');
|
||||
|
||||
// properties to set
|
||||
$properties = array(
|
||||
$propPatch = new \Sabre\DAV\PropPatch(array(
|
||||
self::TAGS_PROPERTYNAME => new \OC\Connector\Sabre\TagList(array('tag1', 'tag2', 'tagkeep'))
|
||||
);
|
||||
$result = array();
|
||||
));
|
||||
|
||||
$this->plugin->updateProperties(
|
||||
$properties,
|
||||
$result,
|
||||
$node
|
||||
$this->plugin->handleUpdateProperties(
|
||||
'/dummypath',
|
||||
$propPatch
|
||||
);
|
||||
|
||||
$propPatch->commit();
|
||||
|
||||
// all requested properties removed, as they were processed already
|
||||
$this->assertEmpty($properties);
|
||||
$this->assertEmpty($propPatch->getRemainingMutations());
|
||||
|
||||
$this->assertEquals(
|
||||
new \OC\Connector\Sabre\TagList(array('tag1', 'tag2', 'tagkeep')),
|
||||
$result[200][self::TAGS_PROPERTYNAME]
|
||||
);
|
||||
$this->assertFalse(isset($result[200][self::FAVORITE_PROPERTYNAME]));
|
||||
$result = $propPatch->getResult();
|
||||
$this->assertEquals(200, $result[self::TAGS_PROPERTYNAME]);
|
||||
$this->assertFalse(isset($result[self::FAVORITE_PROPERTYNAME]));
|
||||
}
|
||||
|
||||
public function testUpdateFav() {
|
||||
// this test will replace the existing tags "tagremove" with "tag1" and "tag2"
|
||||
// and keep "tagkeep"
|
||||
$node = $this->getMockBuilder('\OC_Connector_Sabre_Node')
|
||||
public function testUpdateTagsFromScratch() {
|
||||
$node = $this->getMockBuilder('\OC\Connector\Sabre\Node')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$node->expects($this->any())
|
||||
->method('getId')
|
||||
->will($this->returnValue(123));
|
||||
|
||||
$this->tree->expects($this->any())
|
||||
->method('getNodeForPath')
|
||||
->with('/dummypath')
|
||||
->will($this->returnValue($node));
|
||||
|
||||
$this->tagger->expects($this->at(0))
|
||||
->method('getTagsForObjects')
|
||||
->with($this->equalTo(array(123)))
|
||||
->will($this->returnValue(array()));
|
||||
|
||||
// then tag as tag1 and tag2
|
||||
$this->tagger->expects($this->at(1))
|
||||
->method('tagAs')
|
||||
->with(123, 'tag1');
|
||||
$this->tagger->expects($this->at(2))
|
||||
->method('tagAs')
|
||||
->with(123, 'tag2');
|
||||
|
||||
// properties to set
|
||||
$propPatch = new \Sabre\DAV\PropPatch(array(
|
||||
self::TAGS_PROPERTYNAME => new \OC\Connector\Sabre\TagList(array('tag1', 'tag2', 'tagkeep'))
|
||||
));
|
||||
|
||||
$this->plugin->handleUpdateProperties(
|
||||
'/dummypath',
|
||||
$propPatch
|
||||
);
|
||||
|
||||
$propPatch->commit();
|
||||
|
||||
// all requested properties removed, as they were processed already
|
||||
$this->assertEmpty($propPatch->getRemainingMutations());
|
||||
|
||||
$result = $propPatch->getResult();
|
||||
$this->assertEquals(200, $result[self::TAGS_PROPERTYNAME]);
|
||||
$this->assertFalse(false, isset($result[self::FAVORITE_PROPERTYNAME]));
|
||||
}
|
||||
|
||||
public function testUpdateFav() {
|
||||
// this test will replace the existing tags "tagremove" with "tag1" and "tag2"
|
||||
// and keep "tagkeep"
|
||||
$node = $this->getMockBuilder('\OC\Connector\Sabre\Node')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$node->expects($this->any())
|
||||
->method('getId')
|
||||
->will($this->returnValue(123));
|
||||
|
||||
$this->tree->expects($this->any())
|
||||
->method('getNodeForPath')
|
||||
->with('/dummypath')
|
||||
->will($this->returnValue($node));
|
||||
|
||||
// set favorite tag
|
||||
$this->tagger->expects($this->once())
|
||||
->method('tagAs')
|
||||
->with(123, self::TAG_FAVORITE);
|
||||
|
||||
// properties to set
|
||||
$properties = array(
|
||||
$propPatch = new \Sabre\DAV\PropPatch(array(
|
||||
self::FAVORITE_PROPERTYNAME => true
|
||||
));
|
||||
|
||||
$this->plugin->handleUpdateProperties(
|
||||
'/dummypath',
|
||||
$propPatch
|
||||
);
|
||||
$result = array();
|
||||
$this->plugin->updateProperties(
|
||||
$properties,
|
||||
$result,
|
||||
$node
|
||||
);
|
||||
|
||||
$propPatch->commit();
|
||||
|
||||
// all requested properties removed, as they were processed already
|
||||
$this->assertEmpty($properties);
|
||||
$this->assertEmpty($propPatch->getRemainingMutations());
|
||||
|
||||
$this->assertTrue($result[200][self::FAVORITE_PROPERTYNAME]);
|
||||
$this->assertFalse(isset($result[200][self::TAGS_PROPERTYNAME]));
|
||||
$result = $propPatch->getResult();
|
||||
$this->assertFalse(false, isset($result[self::TAGS_PROPERTYNAME]));
|
||||
$this->assertEquals(200, isset($result[self::FAVORITE_PROPERTYNAME]));
|
||||
|
||||
// unfavorite now
|
||||
// set favorite tag
|
||||
|
@ -297,18 +375,24 @@ class TagsPlugin extends \Test\TestCase {
|
|||
->method('unTag')
|
||||
->with(123, self::TAG_FAVORITE);
|
||||
|
||||
$properties = array(
|
||||
// properties to set
|
||||
$propPatch = new \Sabre\DAV\PropPatch(array(
|
||||
self::FAVORITE_PROPERTYNAME => false
|
||||
);
|
||||
$result = array();
|
||||
$this->plugin->updateProperties(
|
||||
$properties,
|
||||
$result,
|
||||
$node
|
||||
));
|
||||
|
||||
$this->plugin->handleUpdateProperties(
|
||||
'/dummypath',
|
||||
$propPatch
|
||||
);
|
||||
|
||||
$this->assertFalse($result[200][self::FAVORITE_PROPERTYNAME]);
|
||||
$this->assertFalse(isset($result[200][self::TAGS_PROPERTYNAME]));
|
||||
$propPatch->commit();
|
||||
|
||||
// all requested properties removed, as they were processed already
|
||||
$this->assertEmpty($propPatch->getRemainingMutations());
|
||||
|
||||
$result = $propPatch->getResult();
|
||||
$this->assertFalse(false, isset($result[self::TAGS_PROPERTYNAME]));
|
||||
$this->assertEquals(200, isset($result[self::FAVORITE_PROPERTYNAME]));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
class Test_VObject extends \Test\TestCase {
|
||||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
Sabre\VObject\Property::$classMap['SUMMARY'] = 'OC\VObject\StringProperty';
|
||||
Sabre\VObject\Property::$classMap['ORG'] = 'OC\VObject\CompoundProperty';
|
||||
}
|
||||
|
||||
function testStringProperty() {
|
||||
$property = Sabre\VObject\Property::create('SUMMARY', 'Escape;this,please');
|
||||
$this->assertEquals("SUMMARY:Escape\;this\,please\r\n", $property->serialize());
|
||||
}
|
||||
|
||||
function testCompoundProperty() {
|
||||
|
||||
$arr = array(
|
||||
'ABC, Inc.',
|
||||
'North American Division',
|
||||
'Marketing;Sales',
|
||||
);
|
||||
|
||||
$property = Sabre\VObject\Property::create('ORG');
|
||||
$property->setParts($arr);
|
||||
|
||||
$this->assertEquals('ABC\, Inc.;North American Division;Marketing\;Sales', $property->value);
|
||||
$this->assertEquals('ORG:ABC\, Inc.;North American Division;Marketing\;Sales' . "\r\n", $property->serialize());
|
||||
$this->assertEquals(3, count($property->getParts()));
|
||||
$parts = $property->getParts();
|
||||
$this->assertEquals('Marketing;Sales', $parts[2]);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue