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'],
+ ];
+ }
+}