diff --git a/apps/dav/lib/Meta/MetaFile.php b/apps/dav/lib/Meta/MetaFile.php new file mode 100644 index 000000000000..3053f75817ee --- /dev/null +++ b/apps/dav/lib/Meta/MetaFile.php @@ -0,0 +1,80 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OCA\DAV\Meta; + + +use Sabre\DAV\File; + +class MetaFile extends File { + + /** @var \OCP\Files\File */ + private $file; + + /** + * MetaFolder constructor. + * + * @param \OCP\Files\File $file + */ + public function __construct(\OCP\Files\File $file) { + $this->file = $file; + } + + /** + * @inheritdoc + */ + function getName() { + return $this->file->getName(); + } + + /** + * @inheritdoc + */ + function getSize() { + return $this->file->getSize(); + } + + /** + * @inheritdoc + */ + public function get() { + return $this->file->fopen('r'); + } + + /** + * @inheritdoc + */ + public function getContentType() { + return $this->file->getMimeType(); + } + + /** + * @inheritdoc + */ + public function getLastModified() { + return $this->file->getMTime(); + } + + public function getETag() { + return $this->file->getEtag(); + } +} diff --git a/apps/dav/lib/Meta/MetaFolder.php b/apps/dav/lib/Meta/MetaFolder.php new file mode 100644 index 000000000000..46082d69a777 --- /dev/null +++ b/apps/dav/lib/Meta/MetaFolder.php @@ -0,0 +1,72 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OCA\DAV\Meta; + + +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\Node; +use Sabre\DAV\Collection; + +class MetaFolder extends Collection { + + /** @var Folder */ + private $folder; + + /** + * MetaFolder constructor. + * + * @param Folder $folder + */ + public function __construct(Folder $folder) { + $this->folder = $folder; + } + + /** + * @inheritdoc + */ + function getChildren() { + $nodes = $this->folder->getDirectoryListing(); + return array_map(function($node) { + return static::nodeFactory($node); + }, $nodes); + } + + /** + * @inheritdoc + */ + function getName() { + return $this->folder->getName(); + } + + public static function nodeFactory(Node $node) { + if ($node instanceof Folder) { + return new MetaFolder($node); + } + if ($node instanceof File) { + return new MetaFile($node); + } + throw new \InvalidArgumentException(); + } + +} diff --git a/apps/dav/lib/Meta/RootCollection.php b/apps/dav/lib/Meta/RootCollection.php new file mode 100644 index 000000000000..cf3b55a93bcc --- /dev/null +++ b/apps/dav/lib/Meta/RootCollection.php @@ -0,0 +1,74 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OCA\DAV\Meta; + + +use OCP\Files\File; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\Node; +use OCP\Files\NotFoundException; +use Sabre\DAV\Collection; +use Sabre\DAV\Exception\MethodNotAllowed; +use Sabre\DAV\Exception\NotFound; + +class RootCollection extends Collection { + + /** @var IRootFolder */ + private $rootFolder; + + /** + * RootCollection constructor. + * + * @param IRootFolder $rootFolder + */ + public function __construct(IRootFolder $rootFolder) { + $this->rootFolder = $rootFolder; + } + + /** + * @inheritdoc + */ + public function getChild($name) { + try { + $child = $this->rootFolder->get("meta/$name"); + return MetaFolder::nodeFactory($child); + } catch (NotFoundException $ex) { + throw new NotFound(); + } + } + + /** + * @inheritdoc + */ + function getChildren() { + throw new MethodNotAllowed('Listing members of this collection is disabled'); + } + + /** + * @inheritdoc + */ + function getName() { + return 'meta'; + } +} diff --git a/apps/dav/lib/RootCollection.php b/apps/dav/lib/RootCollection.php index 8965c0c92550..15679220cc32 100644 --- a/apps/dav/lib/RootCollection.php +++ b/apps/dav/lib/RootCollection.php @@ -106,7 +106,8 @@ public function __construct() { $systemTagCollection, $systemTagRelationsCollection, $uploadCollection, - $avatarCollection + $avatarCollection, + new \OCA\DAV\Meta\RootCollection(\OC::$server->getRootFolder()) ]; parent::__construct('root', $children); diff --git a/apps/federation/tests/BackgroundJob/GetSharedSecretTest.php b/apps/federation/tests/BackgroundJob/GetSharedSecretTest.php index 6b5805943ab9..beb48138b67d 100644 --- a/apps/federation/tests/BackgroundJob/GetSharedSecretTest.php +++ b/apps/federation/tests/BackgroundJob/GetSharedSecretTest.php @@ -26,7 +26,6 @@ use OCA\Federation\BackgroundJob\GetSharedSecret; -use OCA\Files_Sharing\Tests\TestCase; use OCA\Federation\DbHandler; use OCA\Federation\TrustedServers; use OCP\AppFramework\Http; @@ -35,6 +34,7 @@ use OCP\Http\Client\IResponse; use OCP\ILogger; use OCP\IURLGenerator; +use Test\TestCase; /** * Class GetSharedSecretTest diff --git a/apps/files_versions/lib/Storage.php b/apps/files_versions/lib/Storage.php index 50b3c5522856..95866d2824a7 100644 --- a/apps/files_versions/lib/Storage.php +++ b/apps/files_versions/lib/Storage.php @@ -461,6 +461,10 @@ public static function getVersions($uid, $filename, $userFullPath = '') { $versions[$key]['path'] = Filesystem::normalizePath($pathinfo['dirname'] . '/' . $filename); $versions[$key]['name'] = $versionedFile; $versions[$key]['size'] = $view->filesize($dir . '/' . $entryName); + $versions[$key]['timestamp'] = $timestamp; + $versions[$key]['etag'] = $view->getETag($dir . '/' . $entryName); + $versions[$key]['storage_location'] = "$dir/$entryName"; + $versions[$key]['owner'] = $uid; } } } @@ -832,4 +836,9 @@ protected static function getExpiration(){ return self::$application->getContainer()->query('Expiration'); } + public static function getContentOfVersion($uid, $storage_location) { + $users_view = new View('/'.$uid); + return $users_view->fopen($storage_location, 'r'); + } + } diff --git a/lib/private/AvatarManager.php b/lib/private/AvatarManager.php index 7d4ab5eb605e..ebdf9156e7c4 100644 --- a/lib/private/AvatarManager.php +++ b/lib/private/AvatarManager.php @@ -86,8 +86,6 @@ public function getAvatar($userId) { throw new \Exception('user does not exist'); } - $userId = $user->getUID(); - $avatarsFolder = $this->getAvatarFolder($user); return new Avatar($avatarsFolder, $this->l, $user, $this->logger); } diff --git a/lib/private/Files/Meta/MetaFileIdNode.php b/lib/private/Files/Meta/MetaFileIdNode.php new file mode 100644 index 000000000000..b5e5cec0ccff --- /dev/null +++ b/lib/private/Files/Meta/MetaFileIdNode.php @@ -0,0 +1,174 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OC\Files\Meta; + +use OC\Files\Node\AbstractFolder; +use OCP\Constants; +use OCP\Files\FileInfo; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; + +/** + * Class MetaFileIdNode - this class represents the file id part of the meta endpoint + * + * @package OC\Files\Meta + */ +class MetaFileIdNode extends AbstractFolder { + + /** @var int */ + private $fileId; + /** @var MetaRootNode */ + private $parentNode; + /** @var IRootFolder */ + private $root; + + /** + * MetaFileIdNode constructor. + * + * @param MetaRootNode $parentNode + * @param int $fileId + */ + public function __construct(MetaRootNode $parentNode, IRootFolder $root, $fileId) { + $this->parentNode = $parentNode; + $this->fileId = $fileId; + $this->root = $root; + } + + /** + * @inheritdoc + */ + public function isEncrypted() { + return false; + } + + /** + * @inheritdoc + */ + public function isShared() { + return false; + } + + /** + * @inheritdoc + */ + public function isMounted() { + return false; + } + + /** + * @inheritdoc + */ + public function getDirectoryListing() { + return [ + new MetaVersionCollection($this->fileId, $this->root) + ]; + } + + /** + * @inheritdoc + */ + public function get($path) { + $pieces = explode('/', $path); + if($pieces[0] === 'v') { + array_shift($pieces); + $node = new MetaVersionCollection($this->fileId, $this->root); + if (empty($pieces)) { + return $node; + } + return $node->get(implode('/', $pieces)); + } + throw new NotFoundException(); + + } + + /** + * @inheritdoc + */ + public function getFreeSpace() { + return FileInfo::SPACE_UNKNOWN; + } + + /** + * @inheritdoc + */ + public function getPath() { + return $this->getInternalPath(); + } + + /** + * @inheritdoc + */ + public function getInternalPath() { + return "/meta/{$this->fileId}"; + } + + /** + * @inheritdoc + */ + public function getPermissions() { + return Constants::PERMISSION_READ; + } + + /** + * @inheritdoc + */ + public function isReadable() { + return true; + } + + /** + * @inheritdoc + */ + public function isUpdateable() { + return false; + } + + /** + * @inheritdoc + */ + public function isDeletable() { + return false; + } + + /** + * @inheritdoc + */ + public function isShareable() { + return false; + } + + /** + * @inheritdoc + */ + public function getParent() { + return $this->parentNode; + } + + /** + * @inheritdoc + */ + public function getName() { + return "{$this->fileId}"; + } + +} diff --git a/lib/private/Files/Meta/MetaFileVersionNode.php b/lib/private/Files/Meta/MetaFileVersionNode.php new file mode 100644 index 000000000000..56cd033838a4 --- /dev/null +++ b/lib/private/Files/Meta/MetaFileVersionNode.php @@ -0,0 +1,128 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OC\Files\Meta; + + +use OC\Files\Node\AbstractFile; +use OC\Files\Node\File; +use OCP\Files\IRootFolder; +use OCP\Files\Storage\IVersionedStorage; +use OCP\Files\NotPermittedException; +use OCP\Files\Storage; + +/** + * Class MetaFileVersionNode - this class represents a version of a file in the + * meta endpoint + * + * @package OC\Files\Meta + */ +class MetaFileVersionNode extends AbstractFile { + + /** @var string */ + private $versionId; + /** @var MetaVersionCollection */ + private $parent; + /** @var IVersionedStorage */ + private $storage; + /** @var string */ + private $internalPath; + /** @var IRootFolder */ + private $root; + /** @var array */ + private $versionInfo; + + /** + * MetaFileVersionNode constructor. + * + * @param MetaVersionCollection $parent + * @param IRootFolder $root + * @param array $version + * @param Storage $storage + * @param string $internalPath + */ + public function __construct(MetaVersionCollection $parent, + IRootFolder $root, + array $version, Storage $storage, $internalPath) { + $this->parent = $parent; + $this->versionId = $version['version']; + $this->versionInfo = $version; + $this->storage = $storage; + $this->internalPath = $internalPath; + $this->root = $root; + } + + /** + * @inheritdoc + */ + public function getName() { + return $this->versionId; + } + + /** + * @inheritdoc + */ + public function getSize() { + return isset($this->versionInfo['size']) ? $this->versionInfo['size'] : null; + } + + /** + * @inheritdoc + */ + public function getContent() { + $handle = $this->fopen('r+'); + $data = stream_get_contents($handle); + fclose($handle); + + return $data; + } + + /** + * @inheritdoc + */ + public function copy($targetPath) { + $target = $this->root->get($targetPath); + if ($target instanceof File && $target->getId() === $this->parent->getId()) { + $this->storage->restoreVersion($this->internalPath, $this->versionId); + return; + } + + // for now we only allow restoring of a version + throw new NotPermittedException(); + } + + public function getMTime() { + return isset($this->versionInfo['timestamp']) ? $this->versionInfo['timestamp'] : null; + } + + public function getMimetype() { + return isset($this->versionInfo['mime-type']) ? $this->versionInfo['mime-type'] : 'application/octet-stream'; + } + + public function getEtag() { + return isset($this->versionInfo['etag']) ? $this->versionInfo['etag'] : null; + } + + public function fopen($mode) { + return $this->storage->getContentOfVersion($this->internalPath, $this->versionId); + } +} diff --git a/lib/private/Files/Meta/MetaRootNode.php b/lib/private/Files/Meta/MetaRootNode.php new file mode 100644 index 000000000000..dbf9a1f55f44 --- /dev/null +++ b/lib/private/Files/Meta/MetaRootNode.php @@ -0,0 +1,166 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OC\Files\Meta; + + +use OC\Files\Node\AbstractFolder; +use OCP\Constants; +use OCP\Files\FileInfo; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; + +/** + * Class MetaRootNode - this class represents the root node of the meta endpoint + * + * @package OC\Files\Meta + */ +class MetaRootNode extends AbstractFolder { + + /** @var IRootFolder */ + private $rootFolder; + + public function __construct(IRootFolder $rootFolder) { + $this->rootFolder = $rootFolder; + } + /** + * @inheritdoc + */ + public function isEncrypted() { + return false; + } + + /** + * @inheritdoc + */ + public function isShared() { + return false; + } + + /** + * @inheritdoc + */ + public function isMounted() { + return false; + } + + /** + * @inheritdoc + */ + public function getDirectoryListing() { + // TODO: in debug mode we might want to return the list of all fileids + return []; + } + + /** + * @inheritdoc + */ + public function get($path) { + $pieces = explode('/', $path); + $fileId = (int)$pieces[0]; + + // check if file exists + if (empty($this->rootFolder->getById($fileId))) { + throw new NotFoundException(); + } + + array_shift($pieces); + $node = new MetaFileIdNode($this, $this->rootFolder, $fileId); + if (empty($pieces)) { + return $node; + } + return $node->get(implode('/', $pieces)); + } + + /** + * @inheritdoc + */ + public function getById($id) { + return [ + $this->get("$id") + ]; + } + + /** + * @inheritdoc + */ + public function getFreeSpace() { + return FileInfo::SPACE_UNKNOWN; + } + + /** + * @inheritdoc + */ + public function isCreatable() { + return false; + } + + /** + * @inheritdoc + */ + public function getPath() { + return $this->getName(); + } + + /** + * @inheritdoc + */ + public function getPermissions() { + return Constants::PERMISSION_READ; + } + + /** + * @inheritdoc + */ + public function isReadable() { + // TODO: false if not debug + return true; + } + + /** + * @inheritdoc + */ + public function isUpdateable() { + return false; + } + + /** + * @inheritdoc + */ + public function isDeletable() { + return false; + } + + /** + * @inheritdoc + */ + public function isShareable() { + return false; + } + + /** + * @inheritdoc + */ + public function getName() { + return 'meta'; + } +} diff --git a/lib/private/Files/Meta/MetaVersionCollection.php b/lib/private/Files/Meta/MetaVersionCollection.php new file mode 100644 index 000000000000..8e81b1dfbdef --- /dev/null +++ b/lib/private/Files/Meta/MetaVersionCollection.php @@ -0,0 +1,125 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OC\Files\Meta; + + +use OC\Files\Node\AbstractFolder; +use OCP\Files\IRootFolder; +use OCP\Files\Storage\IVersionedStorage; +use OC\Files\View; +use OCP\Files\NotFoundException; +use OCP\Files\Storage; + +/** + * Class MetaVersionCollection - this class represents the versions sub folder + * of a file + * + * @package OC\Files\Meta + */ +class MetaVersionCollection extends AbstractFolder { + + /** @var int */ + private $fileId; + /** @var IRootFolder */ + private $root; + + /** + * MetaVersionCollection constructor. + * + * @param int $fileId + * @param IRootFolder $root + */ + public function __construct($fileId, IRootFolder $root) { + $this->fileId = $fileId; + $this->root = $root; + } + + /** + * @inheritdoc + */ + public function isEncrypted() { + return false; + } + + /** + * @inheritdoc + */ + public function isShared() { + return false; + } + + /** + * @inheritdoc + */ + public function getDirectoryListing() { + $view = new View(); + $path = $view->getPath($this->fileId); + /** @var Storage $storage */ + list($storage, $internalPath) = $view->resolvePath($path); + if (!$storage->instanceOfStorage(IVersionedStorage::class)) { + return []; + } + $mimeType = $view->getMimeType($path); + /** @var IVersionedStorage | Storage $storage */ + $versions = $storage->getVersions($internalPath); + return array_map(function($version) use ($storage, $internalPath, $mimeType) { + $version['mime-type'] = isset($version['mime-type']) ? $version['mime-type'] : $mimeType; + return new MetaFileVersionNode($this, $this->root, $version, $storage, $internalPath); + }, $versions); + } + + /** + * @inheritdoc + */ + public function get($path) { + $pieces = explode('/', $path); + if (count($pieces) !== 1) { + throw new NotFoundException(); + } + $versionId = $pieces[0]; + $view = new View(); + $path = $view->getPath($this->fileId); + /** @var Storage $storage */ + list($storage, $internalPath) = $view->resolvePath($path); + if (!$storage->instanceOfStorage(IVersionedStorage::class)) { + throw new NotFoundException(); + } + /** @var IVersionedStorage | Storage $storage */ + $version = $storage->getVersion($internalPath, $versionId); + if ($version === null) { + throw new NotFoundException(); + } + return new MetaFileVersionNode($this, $this->root, $version, $storage, $internalPath); + } + + /** + * @inheritdoc + */ + public function getId() { + return $this->fileId; + } + + public function getName() { + return "v"; + } +} diff --git a/lib/private/Files/Node/AbstractFile.php b/lib/private/Files/Node/AbstractFile.php new file mode 100644 index 000000000000..5b6697fbc5c4 --- /dev/null +++ b/lib/private/Files/Node/AbstractFile.php @@ -0,0 +1,72 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OC\Files\Node; + + +use OCP\Files\FileInfo; +use OCP\Files\NotPermittedException; + +class AbstractFile extends AbstractNode implements \OCP\Files\File { + + /** + * @inheritdoc + */ + public function getContent() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function putContent($data) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function fopen($mode) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function hash($type, $raw = false) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getMimetype() { + return 'application/octet-stream'; + } + + /** + * @inheritdoc + */ + public function getType() { + return FileInfo::TYPE_FILE; + } +} diff --git a/lib/private/Files/Node/AbstractFolder.php b/lib/private/Files/Node/AbstractFolder.php new file mode 100644 index 000000000000..299f1c8eeedd --- /dev/null +++ b/lib/private/Files/Node/AbstractFolder.php @@ -0,0 +1,142 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OC\Files\Node; + + +use OC\Files\FileInfo; +use OCP\Files\NotFoundException; +use OCP\Files\NotPermittedException; + +class AbstractFolder extends AbstractNode implements \OCP\Files\Folder { + + /** + * @inheritdoc + */ + public function getMimetype() { + return 'httpd/unix-directory'; + } + + /** + * @inheritdoc + */ + public function getType() { + return FileInfo::TYPE_FOLDER; + } + + /** + * @inheritdoc + */ + public function isSubNode($node) { + return strpos($node->getPath(), $this->getPath()) === 0; + } + + /** + * @inheritdoc + */ + public function getDirectoryListing() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function get($path) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function nodeExists($path) { + try { + $this->get($path); + return true; + } catch (NotFoundException $ex) { + return false; + } + } + + /** + * @inheritdoc + */ + public function newFolder($path) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function newFile($path) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function search($query) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function searchByMime($mimetype) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function searchByTag($tag, $userId) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getById($id) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getFreeSpace() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getNonExistingName($name) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getRelativePath($path) { + throw new NotPermittedException(); + } + +} diff --git a/lib/private/Files/Node/AbstractNode.php b/lib/private/Files/Node/AbstractNode.php new file mode 100644 index 000000000000..411762621fa7 --- /dev/null +++ b/lib/private/Files/Node/AbstractNode.php @@ -0,0 +1,257 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OC\Files\Node; + +use OCP\Files\NotPermittedException; + +abstract class AbstractNode implements \OCP\Files\Node { + + /** + * @inheritdoc + */ + public function getMimePart() { + $mime = $this->getMimetype(); + $parts = explode('/', $mime, 2); + return $parts[0]; + } + + /** + * @inheritdoc + */ + public function getFullPath($path) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getRelativePath($path) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function isEncrypted() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function isCreatable() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function isShared() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function isMounted() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getMountPoint() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getOwner() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getChecksum() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function move($targetPath) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function delete() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function copy($targetPath) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function touch($mtime = null) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getStorage() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getPath() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getInternalPath() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getId() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function stat() { + return [ + 'mtime' => $this->getMTime(), + 'size' => $this->getSize(), + ]; + } + + /** + * @inheritdoc + */ + public function getMTime() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getSize() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getEtag() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getPermissions() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function isReadable() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function isUpdateable() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function isDeletable() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function isShareable() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getParent() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function getName() { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function lock($type) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function changeLock($targetType) { + throw new NotPermittedException(); + } + + /** + * @inheritdoc + */ + public function unlock($type) { + throw new NotPermittedException(); + } +} diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php index b9116580386a..2d725e47ec8d 100644 --- a/lib/private/Files/Node/Root.php +++ b/lib/private/Files/Node/Root.php @@ -29,8 +29,10 @@ namespace OC\Files\Node; -use OC\Files\Mount\Manager; +use OC\Files\Meta\MetaRootNode; use OC\Files\Mount\MountPoint; +use OC\User\NoUserException; +use OCP\Constants; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OC\Hooks\PublicEmitter; @@ -179,6 +181,10 @@ public function get($path) { $path = $this->normalizePath($path); if ($this->isValidPath($path)) { $fullPath = $this->getFullPath($path); + $virtualNode = $this->resolveVirtualNode($fullPath); + if ($virtualNode !== null) { + return $virtualNode; + } $fileInfo = $this->view->getFileInfo($fullPath); if ($fileInfo) { return $this->createNode($fullPath, $fileInfo); @@ -283,7 +289,7 @@ public function getEtag() { * @return int */ public function getPermissions() { - return \OCP\Constants::PERMISSION_CREATE; + return Constants::PERMISSION_CREATE; } /** @@ -334,13 +340,14 @@ public function getName() { * * @param String $userId user ID * @return \OCP\Files\Folder + * @throws NoUserException */ public function getUserFolder($userId) { $userObject = \OC::$server->getUserManager()->get($userId); if (is_null($userObject)) { \OCP\Util::writeLog('files', 'Backends provided no user object for ' . $userId, \OCP\Util::ERROR); - throw new \OC\User\NoUserException('Backends provided no user object for ' . $userId); + throw new NoUserException('Backends provided no user object for ' . $userId); } $userId = $userObject->getUID(); @@ -365,4 +372,18 @@ public function getUserFolder($userId) { return $folder; } + + private function resolveVirtualNode($fullPath) { + $pieces = explode('/', $fullPath); + if ($pieces[1] !== 'meta') { + return null; + } + array_shift($pieces); + array_shift($pieces); + $node = new MetaRootNode($this); + if (empty($pieces)) { + return $node; + } + return $node->get(implode('/', $pieces)); + } } diff --git a/lib/private/Files/Storage/Common.php b/lib/private/Files/Storage/Common.php index 1c56606f9610..c14fa71f6858 100644 --- a/lib/private/Files/Storage/Common.php +++ b/lib/private/Files/Storage/Common.php @@ -44,11 +44,14 @@ use OC\Files\Cache\Updater; use OC\Files\Filesystem; use OC\Files\Cache\Watcher; +use OCP\Constants; +use OCP\Files\FileInfo; use OCP\Files\FileNameTooLongException; use OCP\Files\InvalidCharacterInPathException; use OCP\Files\InvalidPathException; use OCP\Files\ReservedWordException; use OCP\Files\Storage\ILockingStorage; +use OCP\Files\Storage\IVersionedStorage; use OCP\Lock\ILockingProvider; /** @@ -62,7 +65,7 @@ * Some \OC\Files\Storage\Common methods call functions which are first defined * in classes which extend it, e.g. $this->stat() . */ -abstract class Common implements Storage, ILockingStorage { +abstract class Common implements Storage, ILockingStorage, IVersionedStorage { use LocalTempFileTrait; @@ -151,19 +154,19 @@ public function isSharable($path) { public function getPermissions($path) { $permissions = 0; if ($this->isCreatable($path)) { - $permissions |= \OCP\Constants::PERMISSION_CREATE; + $permissions |= Constants::PERMISSION_CREATE; } if ($this->isReadable($path)) { - $permissions |= \OCP\Constants::PERMISSION_READ; + $permissions |= Constants::PERMISSION_READ; } if ($this->isUpdatable($path)) { - $permissions |= \OCP\Constants::PERMISSION_UPDATE; + $permissions |= Constants::PERMISSION_UPDATE; } if ($this->isDeletable($path)) { - $permissions |= \OCP\Constants::PERMISSION_DELETE; + $permissions |= Constants::PERMISSION_DELETE; } if ($this->isSharable($path)) { - $permissions |= \OCP\Constants::PERMISSION_SHARE; + $permissions |= Constants::PERMISSION_SHARE; } return $permissions; } @@ -259,7 +262,7 @@ private function addLocalFolder($path, $target) { $dh = $this->opendir($path); if (is_resource($dh)) { while (($file = readdir($dh)) !== false) { - if (!\OC\Files\Filesystem::isIgnoredDir($file)) { + if (!Filesystem::isIgnoredDir($file)) { if ($this->is_dir($path . '/' . $file)) { mkdir($target . '/' . $file); $this->addLocalFolder($path . '/' . $file, $target . '/' . $file); @@ -282,7 +285,7 @@ protected function searchInDir($query, $dir = '') { $dh = $this->opendir($dir); if (is_resource($dh)) { while (($item = readdir($dh)) !== false) { - if (\OC\Files\Filesystem::isIgnoredDir($item)) continue; + if (Filesystem::isIgnoredDir($item)) continue; if (strstr(strtolower($item), strtolower($query)) !== false) { $files[] = $dir . '/' . $item; } @@ -446,7 +449,7 @@ public function test() { * @return int|false */ public function free_space($path) { - return \OCP\Files\FileInfo::SPACE_UNKNOWN; + return FileInfo::SPACE_UNKNOWN; } /** @@ -620,7 +623,7 @@ public function moveFromStorage(\OCP\Files\Storage $sourceStorage, $sourceIntern */ public function getMetaData($path) { $permissions = $this->getPermissions($path); - if (!$permissions & \OCP\Constants::PERMISSION_READ) { + if (!$permissions & Constants::PERMISSION_READ) { //can't read, nothing we can do return null; } @@ -684,4 +687,52 @@ public function getAvailability() { public function setAvailability($isAvailable) { $this->getStorageCache()->setAvailability($isAvailable); } + public function getVersions($internalPath) { + // KISS implementation + if (!\OC_App::isEnabled('files_versions')) { + return []; + } + list ($uid, $filename) = $this->convertInternalPathToGlobalPath($internalPath); + + return array_values( + \OCA\Files_Versions\Storage::getVersions($uid, $filename)); + } + + /** + * @param $internalPath + * @return array + */ + private function convertInternalPathToGlobalPath($internalPath) { + $mounts = \OC::$server->getMountManager()->findByStorageId($this->getId()); + $mount = end($mounts); + $p = $mount->getMountPoint() . $internalPath; + $p = explode('/', ltrim($p, '/')); + array_shift($p); + array_shift($p); + $p = implode('/', $p); + $o = explode('/', $mount->getMountPoint()); + return [$o[1], $p]; + } + + public function getVersion($internalPath, $versionId) { + $versions = $this->getVersions($internalPath); + $versions = array_filter($versions, function ($version) use($versionId){ + return $version['version'] === $versionId; + }); + return array_shift($versions); + } + + public function getContentOfVersion($internalPath, $versionId) { + $v = $this->getVersion($internalPath, $versionId); + return \OCA\Files_Versions\Storage::getContentOfVersion($v['owner'], $v['storage_location']); + } + + public function restoreVersion($internalPath, $versionId) { + // KISS implementation + if (!\OC_App::isEnabled('files_versions')) { + return; + } + list ($uid, $filename) = $this->convertInternalPathToGlobalPath($internalPath); + \OCA\Files_Versions\Storage::rollback($filename, $versionId); + } } diff --git a/lib/private/Files/Storage/Local.php b/lib/private/Files/Storage/Local.php index d1cc475225b5..180d354e9f08 100644 --- a/lib/private/Files/Storage/Local.php +++ b/lib/private/Files/Storage/Local.php @@ -41,7 +41,7 @@ /** * for local filestore, we only have to map the paths */ -class Local extends \OC\Files\Storage\Common { +class Local extends Common { protected $datadir; protected $dataDirLength; @@ -412,7 +412,7 @@ public function getETag($path) { * @param string $targetInternalPath * @return bool */ - public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath) { + public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime = false) { if ($sourceStorage->instanceOfStorage('\OC\Files\Storage\Local')) { /** * @var \OC\Files\Storage\Local $sourceStorage @@ -420,7 +420,7 @@ public function copyFromStorage(\OCP\Files\Storage $sourceStorage, $sourceIntern $rootStorage = new Local(['datadir' => '/']); return $rootStorage->copy($sourceStorage->getSourcePath($sourceInternalPath), $this->getSourcePath($targetInternalPath)); } else { - return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); + return parent::copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath, $preserveMtime); } } diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php index 270b27020674..c622c2fa8230 100644 --- a/lib/private/Files/Storage/Wrapper/Encryption.php +++ b/lib/private/Files/Storage/Wrapper/Encryption.php @@ -887,10 +887,15 @@ protected function getFullPath($path) { * read first block of encrypted file, typically this will contain the * encryption header * - * @param string $path + * @param string|resource $path * @return string */ protected function readFirstBlock($path) { + if (is_resource($path)) { + $firstBlock = fread($path, $this->util->getHeaderSize()); + rewind($path); + return $firstBlock; + } $firstBlock = ''; if ($this->storage->file_exists($path)) { $handle = $this->storage->fopen($path, 'r'); @@ -903,14 +908,16 @@ protected function readFirstBlock($path) { /** * return header size of given file * - * @param string $path + * @param string|resource $path * @return int */ protected function getHeaderSize($path) { $headerSize = 0; - $realFile = $this->util->stripPartialFileExtension($path); - if ($this->storage->file_exists($realFile)) { - $path = $realFile; + if (!is_resource($path)) { + $realFile = $this->util->stripPartialFileExtension($path); + if ($this->storage->file_exists($realFile)) { + $path = $realFile; + } } $firstBlock = $this->readFirstBlock($path); @@ -952,14 +959,18 @@ protected function parseRawHeader($rawHeader) { /** * read header from file * - * @param string $path + * @param string|resource $path * @return array */ protected function getHeader($path) { - $realFile = $this->util->stripPartialFileExtension($path); - $exists = $this->storage->file_exists($realFile); - if ($exists) { - $path = $realFile; + if (is_resource($path)) { + $exists = false; + } else { + $realFile = $this->util->stripPartialFileExtension($path); + $exists = $this->storage->file_exists($realFile); + if ($exists) { + $path = $realFile; + } } $firstBlock = $this->readFirstBlock($path); diff --git a/lib/public/Files/Storage/IVersionedStorage.php b/lib/public/Files/Storage/IVersionedStorage.php new file mode 100644 index 000000000000..55e60b501b83 --- /dev/null +++ b/lib/public/Files/Storage/IVersionedStorage.php @@ -0,0 +1,72 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace OCP\Files\Storage; + +/** + * Interface IVersionedStorage - storage layer to access version of a file + * + * @package OCP\Files\Storage + * @since 10.1.0 + */ +interface IVersionedStorage { + + /** + * List all versions for the given file + * + * @param string $internalPath + * @return array + * @since 10.1.0 + */ + public function getVersions($internalPath); + + /** + * Get one explicit version for the given file + * + * @param string $internalPath + * @param string $versionId + * @return array + * @since 10.1.0 + */ + public function getVersion($internalPath, $versionId); + + /** + * Get the content of a given version of a given file as stream resource + * + * @param string $internalPath + * @param string $versionId + * @return resource + * @since 10.1.0 + */ + public function getContentOfVersion($internalPath, $versionId); + + /** + * Restore the given version of a given file + * + * @param string $internalPath + * @param string $versionId + * @return void + * @since 10.1.0 + */ + public function restoreVersion($internalPath, $versionId); + +} diff --git a/tests/integration/data/davtest.txt b/tests/integration/data/davtest.txt new file mode 100644 index 000000000000..09c3a96be2f5 --- /dev/null +++ b/tests/integration/data/davtest.txt @@ -0,0 +1 @@ +Dav-Test \ No newline at end of file diff --git a/tests/integration/features/bootstrap/WebDav.php b/tests/integration/features/bootstrap/WebDav.php index 09c93c55748b..e9b7d02d97a7 100644 --- a/tests/integration/features/bootstrap/WebDav.php +++ b/tests/integration/features/bootstrap/WebDav.php @@ -488,6 +488,48 @@ public function listFolder($user, $path, $folderDepth, $properties = null) { return $response; } + public function listVersionFolder($user, $path, $folderDepth, $properties = null) { + $client = $this->getSabreClient($user); + if (!$properties) { + $properties = [ + '{DAV:}getetag' + ]; + } + + try { + $response = $client->propfind($this->makeSabrePathNotForFiles($path), $properties, $folderDepth); + } catch (Sabre\HTTP\ClientHttpException $e) { + $response = $e->getResponse(); + } + return $response; + } + + /** + * @Then the version folder of file :path for user :user contains :count elements + * @param $path + * @param $count + * @param $user + */ + public function theVersionFolderOfFileContainsElements($path, $user, $count) { + $fileId = $this->getFileIdForPath($user, $path); + $elements = $this->listVersionFolder($user, '/meta/'.$fileId.'/v', 1); + PHPUnit_Framework_Assert::assertEquals($count, count($elements)-1); + } + + /** + * @Then the content length of file :path with version index :index for user :user in versions folder is :length + * @param $path + * @param $index + * @param $user + * @param $length + */ + public function theContentLengthOfFileForUserInVersionsFolderIs($path, $index, $user, $length) { + $fileId = $this->getFileIdForPath($user, $path); + $elements = $this->listVersionFolder($user, '/meta/'.$fileId.'/v', 1, ['{DAV:}getcontentlength']); + $elements = array_values($elements); + PHPUnit_Framework_Assert::assertEquals($length, $elements[1]['{DAV:}getcontentlength']); + } + /* Returns the elements of a report command * @param string $user * @param string $path diff --git a/tests/integration/features/dav-versions.feature b/tests/integration/features/dav-versions.feature new file mode 100644 index 000000000000..613002fb3bd1 --- /dev/null +++ b/tests/integration/features/dav-versions.feature @@ -0,0 +1,28 @@ +Feature: dav-versions + Background: + Given using api version "2" + Given using new dav path + + Scenario: Upload file and no version is available + Given user "user0" exists + And as an "user0" + When user "user0" uploads file "data/davtest.txt" to "/davtest.txt" + Then the version folder of file "/davtest.txt" for user "user0" contains "0" elements + + Scenario: Upload a file twice and versions are available + Given user "user0" exists + And as an "user0" + When user "user0" uploads file "data/davtest.txt" to "/davtest.txt" + Then user "user0" uploads file "data/davtest.txt" to "/davtest.txt" + And the version folder of file "/davtest.txt" for user "user0" contains "1" elements + And the content length of file "/davtest.txt" with version index "1" for user "user0" in versions folder is "8" + + Scenario: Remove a file + Given user "user0" exists + And as an "user0" + And user "user0" uploads file "data/davtest.txt" to "/davtest.txt" + And user "user0" uploads file "data/davtest.txt" to "/davtest.txt" + And the version folder of file "/davtest.txt" for user "user0" contains "1" elements + And user "user0" deletes file "/davtest.txt" + When user "user0" uploads file "data/davtest.txt" to "/davtest.txt" + Then the version folder of file "/davtest.txt" for user "user0" contains "0" elements diff --git a/tests/lib/AvatarManagerTest.php b/tests/lib/AvatarManagerTest.php index e9b2e69a6bb6..ccff5fd24c99 100644 --- a/tests/lib/AvatarManagerTest.php +++ b/tests/lib/AvatarManagerTest.php @@ -113,10 +113,6 @@ public function testGetAvatarValidUserDifferentCasing() { ->with('vaLid-USER') ->willReturn($user); - $user->expects($this->once()) - ->method('getUID') - ->willReturn('valid-user'); - $folder = $this->createMock(Folder::class); $this->avatarManager->expects($this->once()) ->method('getAvatarFolder') diff --git a/tests/lib/Files/MetaFilesTest.php b/tests/lib/Files/MetaFilesTest.php new file mode 100644 index 000000000000..2f02c78642d8 --- /dev/null +++ b/tests/lib/Files/MetaFilesTest.php @@ -0,0 +1,102 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace Test\Files; + + +use OC\Files\Meta\MetaFileIdNode; +use OC\Files\Meta\MetaFileVersionNode; +use OC\Files\Meta\MetaRootNode; +use OC\Files\Meta\MetaVersionCollection; +use OC\Files\View; +use OCA\Files_Versions\Hooks; +use OCP\Files\Folder; +use Test\TestCase; +use Test\Traits\UserTrait; + +/** + * Class MetaFilesTest + * + * @package Test\Files + * @group DB + */ +class MetaFilesTest extends TestCase { + use UserTrait; + + protected function tearDown() { + self::logout(); + parent::tearDown(); + } + + public function testMetaInNodeAPI() { + // workaround: re-setup versions hooks + Hooks::connectHooks(); + + // create user + $userId = 'meta-data-user'; + $this->createUser($userId); + $this->loginAsUser($userId); + + // create file + $fileName = "$userId/files/" . $this->getUniqueID('file') . '.txt'; + $view = new View(); + $view->file_put_contents($fileName, '1234'); + $info = $view->getFileInfo($fileName); + + // work on node api + /** @var Folder $metaNodeOfFile */ + $metaNodeOfFile = \OC::$server->getRootFolder()->get("meta"); + $this->assertInstanceOf(MetaRootNode::class, $metaNodeOfFile); + $this->assertEquals([], $metaNodeOfFile->getDirectoryListing()); + + $metaNodeOfFile = \OC::$server->getRootFolder()->get("meta/{$info->getId()}"); + $this->assertInstanceOf(MetaFileIdNode::class, $metaNodeOfFile); + $children = $metaNodeOfFile->getDirectoryListing(); + $this->assertEquals(1, count($children)); + $this->assertInstanceOf(MetaVersionCollection::class, $children[0]); + + $metaNodeOfFile = \OC::$server->getRootFolder()->get("meta/{$info->getId()}/v"); + $this->assertInstanceOf(MetaVersionCollection::class, $metaNodeOfFile); + $children = $metaNodeOfFile->getDirectoryListing(); + $this->assertEquals(0, count($children)); + + // write again to get another version + $view->file_put_contents($fileName, '1234567890'); + $children = $metaNodeOfFile->getDirectoryListing(); + $this->assertEquals(1, count($children)); + $this->assertInstanceOf(MetaFileVersionNode::class, $children[0]); + + $versionId = $children[0]->getName(); + $metaNodeOfFile = \OC::$server->getRootFolder()->get("meta/{$info->getId()}/v/$versionId"); + $this->assertInstanceOf(MetaFileVersionNode::class, $metaNodeOfFile); + $this->assertEquals($versionId, $metaNodeOfFile->getName()); + /** @var MetaFileVersionNode $metaNodeOfFile */ + $this->assertEquals('1234', $metaNodeOfFile->getContent()); + + // restore a version using move + $target = \OC::$server->getRootFolder()->get($fileName); + $this->assertEquals('1234567890', $target->getContent()); + $metaNodeOfFile->copy($fileName); + $this->assertEquals('1234', $target->getContent()); + + } +} diff --git a/tests/lib/Files/Node/AbstractFileTest.php b/tests/lib/Files/Node/AbstractFileTest.php new file mode 100644 index 000000000000..6f1d6361512b --- /dev/null +++ b/tests/lib/Files/Node/AbstractFileTest.php @@ -0,0 +1,91 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace Test\Files\Node; + + +use OC\Files\Node\AbstractFile; +use OCP\Files\FileInfo; +use Test\TestCase; + +class AbstractFileTest extends TestCase { + + public function testMime() { + /** @var AbstractFile | \PHPUnit_Framework_MockObject_MockObject $node */ + $node = new AbstractFile(); + $this->assertEquals('application/octet-stream', $node->getMimetype()); + $this->assertEquals('application', $node->getMimePart()); + $this->assertEquals(FileInfo::TYPE_FILE, $node->getType()); + } + + /** + * @expectedException \OCP\Files\NotPermittedException + * @dataProvider providesOperations + */ + public function testOperations($operation) { + /** @var AbstractFile | \PHPUnit_Framework_MockObject_MockObject $node */ + $node = $this->getMockForAbstractClass(AbstractFile::class); + $node->$operation(''); + } + + public function providesOperations() { + return [ + ['getId'], + ['getFullPath'], + ['getRelativePath'], + ['isEncrypted'], + ['isCreatable'], + ['isShared'], + ['isMounted'], + ['getMountPoint'], + ['getOwner'], + ['getChecksum'], + ['move'], + ['delete'], + ['copy'], + ['touch'], + ['getStorage'], + ['getPath'], + ['getInternalPath'], + ['getId'], + ['stat'], + ['getMTime'], + ['getSize'], + ['getEtag'], + ['getPermissions'], + ['isReadable'], + ['isUpdateable'], + ['isDeletable'], + ['isShareable'], + ['getParent'], + ['getName'], + ['lock'], + ['changeLock'], + ['unlock'], + // file methods + ['getContent'], + ['putContent'], + ['fopen'], + ['hash'], + ]; + } +} diff --git a/tests/lib/Files/Node/AbstractFolderTest.php b/tests/lib/Files/Node/AbstractFolderTest.php new file mode 100644 index 000000000000..2235913f1aa2 --- /dev/null +++ b/tests/lib/Files/Node/AbstractFolderTest.php @@ -0,0 +1,99 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace Test\Files\Node; + + +use OC\Files\Node\AbstractFolder; +use OCP\Files\FileInfo; +use Test\TestCase; + +class AbstractFolderTest extends TestCase { + + public function testMimeAndGetType() { + /** @var AbstractFolder | \PHPUnit_Framework_MockObject_MockObject $node */ + $node = $this->getMockForAbstractClass(AbstractFolder::class); + $this->assertEquals('httpd/unix-directory', $node->getMimetype()); + $this->assertEquals('httpd', $node->getMimePart()); + $this->assertEquals(FileInfo::TYPE_FOLDER, $node->getType()); + } + + /** + * @expectedException \OCP\Files\NotPermittedException + * @dataProvider providesOperations + */ + public function testOperations($operation) { + /** @var AbstractFolder | \PHPUnit_Framework_MockObject_MockObject $node */ + $node = $this->getMockForAbstractClass(AbstractFolder::class); + $node->$operation('', ''); + } + + public function providesOperations() { + return [ + ['getId'], + ['getFullPath'], + ['getRelativePath'], + ['isEncrypted'], + ['isCreatable'], + ['isShared'], + ['isMounted'], + ['getMountPoint'], + ['getOwner'], + ['getChecksum'], + ['move'], + ['delete'], + ['copy'], + ['touch'], + ['getStorage'], + ['getPath'], + ['getInternalPath'], + ['getId'], + ['stat'], + ['getMTime'], + ['getSize'], + ['getEtag'], + ['getPermissions'], + ['isReadable'], + ['isUpdateable'], + ['isDeletable'], + ['isShareable'], + ['getParent'], + ['getName'], + ['lock'], + ['changeLock'], + ['unlock'], + // folder methods + ['getDirectoryListing'], + ['get'], + ['nodeExists'], + ['newFolder'], + ['newFile'], + ['search'], + ['searchByMime'], + ['searchByTag'], + ['getById'], + ['getFreeSpace'], + ['getNonExistingName'], + ['getRelativePath'], + ]; + } +} diff --git a/tests/lib/Files/Node/AbstractNodeTest.php b/tests/lib/Files/Node/AbstractNodeTest.php new file mode 100644 index 000000000000..d2de9336841a --- /dev/null +++ b/tests/lib/Files/Node/AbstractNodeTest.php @@ -0,0 +1,85 @@ + + * + * @copyright Copyright (c) 2017, ownCloud GmbH + * @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 + * + */ + + +namespace Test\Files\Node; + + +use OC\Files\Node\AbstractNode; +use Test\TestCase; + +class AbstractNodeTest extends TestCase { + + public function testMime() { + /** @var AbstractNode | \PHPUnit_Framework_MockObject_MockObject $node */ + $node = $this->getMockForAbstractClass(AbstractNode::class); + $node->expects($this->any())->method('getMimetype')->willReturn('foo/bar'); + $this->assertEquals('foo/bar', $node->getMimetype()); + $this->assertEquals('foo', $node->getMimePart()); + } + + /** + * @expectedException \OCP\Files\NotPermittedException + * @dataProvider providesOperations + */ + public function testOperations($operation) { + /** @var AbstractNode | \PHPUnit_Framework_MockObject_MockObject $node */ + $node = $this->getMockForAbstractClass(AbstractNode::class); + $node->$operation(''); + } + + public function providesOperations() { + return [ + ['getId'], + ['getFullPath'], + ['getRelativePath'], + ['isEncrypted'], + ['isCreatable'], + ['isShared'], + ['isMounted'], + ['getMountPoint'], + ['getOwner'], + ['getChecksum'], + ['move'], + ['delete'], + ['copy'], + ['touch'], + ['getStorage'], + ['getPath'], + ['getInternalPath'], + ['getId'], + ['stat'], + ['getMTime'], + ['getSize'], + ['getEtag'], + ['getPermissions'], + ['isReadable'], + ['isUpdateable'], + ['isDeletable'], + ['isShareable'], + ['getParent'], + ['getName'], + ['lock'], + ['changeLock'], + ['unlock'], + ]; + } +}