aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/admin_audit/appinfo/info.xml3
-rw-r--r--apps/admin_audit/composer/composer/autoload_classmap.php1
-rw-r--r--apps/admin_audit/composer/composer/autoload_static.php1
-rw-r--r--apps/admin_audit/lib/AppInfo/Application.php98
-rw-r--r--apps/admin_audit/lib/BackgroundJobs/Rotate.php52
-rw-r--r--apps/dav/lib/Connector/Sabre/Directory.php11
-rw-r--r--apps/dav/lib/Connector/Sabre/File.php22
-rw-r--r--apps/dav/lib/Connector/Sabre/Node.php2
-rw-r--r--apps/dav/tests/unit/Connector/Sabre/ExceptionLoggerPluginTest.php2
-rw-r--r--apps/files/css/files.scss3
-rw-r--r--apps/files/img/quota.svg1
-rw-r--r--apps/files/templates/appnavigation.php2
-rw-r--r--apps/files_external/js/settings.js12
-rw-r--r--apps/files_external/l10n/de.js1
-rw-r--r--apps/files_external/l10n/de.json1
-rw-r--r--apps/files_external/l10n/de_DE.js1
-rw-r--r--apps/files_external/l10n/de_DE.json1
-rw-r--r--apps/files_external/l10n/fr.js1
-rw-r--r--apps/files_external/l10n/fr.json1
-rw-r--r--apps/files_external/l10n/it.js1
-rw-r--r--apps/files_external/l10n/it.json1
-rw-r--r--apps/files_external/l10n/pt_BR.js1
-rw-r--r--apps/files_external/l10n/pt_BR.json1
-rw-r--r--apps/files_external/l10n/ru.js1
-rw-r--r--apps/files_external/l10n/ru.json1
-rw-r--r--apps/files_external/l10n/tr.js1
-rw-r--r--apps/files_external/l10n/tr.json1
-rw-r--r--apps/files_external/lib/Command/ListCommand.php3
-rw-r--r--apps/files_external/lib/Lib/Storage/OwnCloud.php4
-rw-r--r--apps/files_external/templates/settings.php1
-rw-r--r--apps/files_external/tests/js/settingsSpec.js3
-rw-r--r--apps/files_sharing/lib/External/Storage.php3
-rw-r--r--apps/files_sharing/tests/js/sharedfilelistSpec.js6
-rw-r--r--apps/files_versions/appinfo/info.xml9
-rw-r--r--apps/files_versions/composer/composer/autoload_classmap.php6
-rw-r--r--apps/files_versions/composer/composer/autoload_static.php6
-rw-r--r--apps/files_versions/lib/AppInfo/Application.php13
-rw-r--r--apps/files_versions/lib/Sabre/RestoreFolder.php86
-rw-r--r--apps/files_versions/lib/Sabre/RootCollection.php65
-rw-r--r--apps/files_versions/lib/Sabre/VersionCollection.php102
-rw-r--r--apps/files_versions/lib/Sabre/VersionFile.php94
-rw-r--r--apps/files_versions/lib/Sabre/VersionHome.php90
-rw-r--r--apps/files_versions/lib/Sabre/VersionRoot.php100
43 files changed, 742 insertions, 73 deletions
diff --git a/apps/admin_audit/appinfo/info.xml b/apps/admin_audit/appinfo/info.xml
index 054ed9580f2..3006551b409 100644
--- a/apps/admin_audit/appinfo/info.xml
+++ b/apps/admin_audit/appinfo/info.xml
@@ -17,4 +17,7 @@
<dependencies>
<nextcloud min-version="14" max-version="14" />
</dependencies>
+ <background-jobs>
+ <job>OCA\AdminAudit\BackgroundJobs\Rotate</job>
+ </background-jobs>
</info>
diff --git a/apps/admin_audit/composer/composer/autoload_classmap.php b/apps/admin_audit/composer/composer/autoload_classmap.php
index c08200c7c20..95ddaac7452 100644
--- a/apps/admin_audit/composer/composer/autoload_classmap.php
+++ b/apps/admin_audit/composer/composer/autoload_classmap.php
@@ -18,4 +18,5 @@ return array(
'OCA\\AdminAudit\\Actions\\UserManagement' => $baseDir . '/../lib/Actions/UserManagement.php',
'OCA\\AdminAudit\\Actions\\Versions' => $baseDir . '/../lib/Actions/Versions.php',
'OCA\\AdminAudit\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
+ 'OCA\\AdminAudit\\BackgroundJobs\\Rotate' => $baseDir . '/../lib/BackgroundJobs/Rotate.php',
);
diff --git a/apps/admin_audit/composer/composer/autoload_static.php b/apps/admin_audit/composer/composer/autoload_static.php
index ef088bd22d9..1c01a35ceb2 100644
--- a/apps/admin_audit/composer/composer/autoload_static.php
+++ b/apps/admin_audit/composer/composer/autoload_static.php
@@ -33,6 +33,7 @@ class ComposerStaticInitAdminAudit
'OCA\\AdminAudit\\Actions\\UserManagement' => __DIR__ . '/..' . '/../lib/Actions/UserManagement.php',
'OCA\\AdminAudit\\Actions\\Versions' => __DIR__ . '/..' . '/../lib/Actions/Versions.php',
'OCA\\AdminAudit\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
+ 'OCA\\AdminAudit\\BackgroundJobs\\Rotate' => __DIR__ . '/..' . '/../lib/BackgroundJobs/Rotate.php',
);
public static function getInitializer(ClassLoader $loader)
diff --git a/apps/admin_audit/lib/AppInfo/Application.php b/apps/admin_audit/lib/AppInfo/Application.php
index df39e3eb111..77b76885a20 100644
--- a/apps/admin_audit/lib/AppInfo/Application.php
+++ b/apps/admin_audit/lib/AppInfo/Application.php
@@ -53,8 +53,26 @@ use OCP\Share;
class Application extends App {
+ /** @var ILogger */
+ protected $logger;
+
public function __construct() {
parent::__construct('admin_audit');
+ $this->initLogger();
+ }
+
+ public function initLogger() {
+ $c = $this->getContainer()->getServer();
+ $config = $c->getConfig();
+
+ $default = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/audit.log';
+ $logFile = $config->getAppValue('admin_audit', 'logfile', $default);
+ if($logFile === null) {
+ $this->logger = $c->getLogger();
+ return;
+ }
+ $this->logger = $c->getLogFactory()->getCustomLogger($logFile);
+
}
public function register() {
@@ -65,26 +83,24 @@ class Application extends App {
* Register hooks in order to log them
*/
protected function registerHooks() {
- $logger = $this->getContainer()->getServer()->getLogger();
-
- $this->userManagementHooks($logger);
- $this->groupHooks($logger);
- $this->authHooks($logger);
+ $this->userManagementHooks();
+ $this->groupHooks();
+ $this->authHooks();
- $this->consoleHooks($logger);
- $this->appHooks($logger);
+ $this->consoleHooks();
+ $this->appHooks();
- $this->sharingHooks($logger);
+ $this->sharingHooks();
- $this->fileHooks($logger);
- $this->trashbinHooks($logger);
- $this->versionsHooks($logger);
+ $this->fileHooks();
+ $this->trashbinHooks();
+ $this->versionsHooks();
- $this->securityHooks($logger);
+ $this->securityHooks();
}
- protected function userManagementHooks(ILogger $logger) {
- $userActions = new UserManagement($logger);
+ protected function userManagementHooks() {
+ $userActions = new UserManagement($this->logger);
Util::connectHook('OC_User', 'post_createUser', $userActions, 'create');
Util::connectHook('OC_User', 'post_deleteUser', $userActions, 'delete');
@@ -97,8 +113,8 @@ class Application extends App {
$userSession->listen('\OC\User', 'postUnassignedUserId', [$userActions, 'unassign']);
}
- protected function groupHooks(ILogger $logger) {
- $groupActions = new GroupManagement($logger);
+ protected function groupHooks() {
+ $groupActions = new GroupManagement($this->logger);
/** @var IGroupManager|Manager $groupManager */
$groupManager = $this->getContainer()->getServer()->getGroupManager();
@@ -108,8 +124,8 @@ class Application extends App {
$groupManager->listen('\OC\Group', 'postCreate', [$groupActions, 'createGroup']);
}
- protected function sharingHooks(ILogger $logger) {
- $shareActions = new Sharing($logger);
+ protected function sharingHooks() {
+ $shareActions = new Sharing($this->logger);
Util::connectHook(Share::class, 'post_shared', $shareActions, 'shared');
Util::connectHook(Share::class, 'post_unshare', $shareActions, 'unshare');
@@ -119,42 +135,42 @@ class Application extends App {
Util::connectHook(Share::class, 'share_link_access', $shareActions, 'shareAccessed');
}
- protected function authHooks(ILogger $logger) {
- $authActions = new Auth($logger);
+ protected function authHooks() {
+ $authActions = new Auth($this->logger);
Util::connectHook('OC_User', 'pre_login', $authActions, 'loginAttempt');
Util::connectHook('OC_User', 'post_login', $authActions, 'loginSuccessful');
Util::connectHook('OC_User', 'logout', $authActions, 'logout');
}
- protected function appHooks(ILogger $logger) {
+ protected function appHooks() {
$eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher();
- $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, function(ManagerEvent $event) use ($logger) {
- $appActions = new AppManagement($logger);
+ $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, function(ManagerEvent $event) {
+ $appActions = new AppManagement($this->logger);
$appActions->enableApp($event->getAppID());
});
- $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, function(ManagerEvent $event) use ($logger) {
- $appActions = new AppManagement($logger);
+ $eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, function(ManagerEvent $event) {
+ $appActions = new AppManagement($this->logger);
$appActions->enableAppForGroups($event->getAppID(), $event->getGroups());
});
- $eventDispatcher->addListener(ManagerEvent::EVENT_APP_DISABLE, function(ManagerEvent $event) use ($logger) {
- $appActions = new AppManagement($logger);
+ $eventDispatcher->addListener(ManagerEvent::EVENT_APP_DISABLE, function(ManagerEvent $event) {
+ $appActions = new AppManagement($this->logger);
$appActions->disableApp($event->getAppID());
});
}
- protected function consoleHooks(ILogger $logger) {
+ protected function consoleHooks() {
$eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher();
- $eventDispatcher->addListener(ConsoleEvent::EVENT_RUN, function(ConsoleEvent $event) use ($logger) {
- $appActions = new Console($logger);
+ $eventDispatcher->addListener(ConsoleEvent::EVENT_RUN, function(ConsoleEvent $event) {
+ $appActions = new Console($this->logger);
$appActions->runCommand($event->getArguments());
});
}
- protected function fileHooks(ILogger $logger) {
- $fileActions = new Files($logger);
+ protected function fileHooks() {
+ $fileActions = new Files($this->logger);
$eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher();
$eventDispatcher->addListener(
IPreview::EVENT,
@@ -215,26 +231,26 @@ class Application extends App {
);
}
- protected function versionsHooks(ILogger $logger) {
- $versionsActions = new Versions($logger);
+ protected function versionsHooks() {
+ $versionsActions = new Versions($this->logger);
Util::connectHook('\OCP\Versions', 'rollback', $versionsActions, 'rollback');
Util::connectHook('\OCP\Versions', 'delete',$versionsActions, 'delete');
}
- protected function trashbinHooks(ILogger $logger) {
- $trashActions = new Trashbin($logger);
+ protected function trashbinHooks() {
+ $trashActions = new Trashbin($this->logger);
Util::connectHook('\OCP\Trashbin', 'preDelete', $trashActions, 'delete');
Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $trashActions, 'restore');
}
- protected function securityHooks(ILogger $logger) {
+ protected function securityHooks() {
$eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher();
- $eventDispatcher->addListener(IProvider::EVENT_SUCCESS, function(GenericEvent $event) use ($logger) {
- $security = new Security($logger);
+ $eventDispatcher->addListener(IProvider::EVENT_SUCCESS, function(GenericEvent $event) {
+ $security = new Security($this->logger);
$security->twofactorSuccess($event->getSubject(), $event->getArguments());
});
- $eventDispatcher->addListener(IProvider::EVENT_FAILED, function(GenericEvent $event) use ($logger) {
- $security = new Security($logger);
+ $eventDispatcher->addListener(IProvider::EVENT_FAILED, function(GenericEvent $event) {
+ $security = new Security($this->logger);
$security->twofactorFailed($event->getSubject(), $event->getArguments());
});
}
diff --git a/apps/admin_audit/lib/BackgroundJobs/Rotate.php b/apps/admin_audit/lib/BackgroundJobs/Rotate.php
new file mode 100644
index 00000000000..421ee65d643
--- /dev/null
+++ b/apps/admin_audit/lib/BackgroundJobs/Rotate.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * @copyright Copyright (c) 2018 Arthur Schiwon <blizzz@arthur-schiwon.de>
+ *
+ * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\AdminAudit\BackgroundJobs;
+
+use OC\BackgroundJob\TimedJob;
+use OCP\Log\RotationTrait;
+
+class Rotate extends TimedJob {
+ use RotationTrait;
+
+ public function __construct() {
+ $this->setInterval(60*60*3);
+ }
+
+ protected function run($argument) {
+ $config = \OC::$server->getConfig();
+ $default = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/audit.log';
+ $this->filePath = $config->getAppValue('admin_audit', 'logfile', $default);
+
+ if($this->filePath === '') {
+ // default log file, nothing to do
+ return;
+ }
+
+ $this->maxSize = $config->getSystemValue('log_rotate_size', 100 * 1024 * 1024);
+
+ if($this->shouldRotateBySize()) {
+ $this->rotate();
+ }
+ }
+}
diff --git a/apps/dav/lib/Connector/Sabre/Directory.php b/apps/dav/lib/Connector/Sabre/Directory.php
index a7b8ea1755e..aaf5f54ec26 100644
--- a/apps/dav/lib/Connector/Sabre/Directory.php
+++ b/apps/dav/lib/Connector/Sabre/Directory.php
@@ -28,6 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
+
namespace OCA\DAV\Connector\Sabre;
use OC\Files\View;
@@ -147,8 +148,16 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node
$info = new \OC\Files\FileInfo($path, null, null, [], null);
}
$node = new \OCA\DAV\Connector\Sabre\File($this->fileView, $info);
+
+ // only allow 1 process to upload a file at once but still allow reading the file while writing the part file
$node->acquireLock(ILockingProvider::LOCK_SHARED);
- return $node->put($data);
+ $this->fileView->lockFile($path . '.upload.part', ILockingProvider::LOCK_EXCLUSIVE);
+
+ $result = $node->put($data);
+
+ $this->fileView->unlockFile($path . '.upload.part', ILockingProvider::LOCK_EXCLUSIVE);
+ $node->releaseLock(ILockingProvider::LOCK_SHARED);
+ return $result;
} catch (\OCP\Files\StorageNotAvailableException $e) {
throw new \Sabre\DAV\Exception\ServiceUnavailable($e->getMessage(), $e->getCode(), $e);
} catch (InvalidPathException $ex) {
diff --git a/apps/dav/lib/Connector/Sabre/File.php b/apps/dav/lib/Connector/Sabre/File.php
index 45b31c2e11d..bbd6717d94f 100644
--- a/apps/dav/lib/Connector/Sabre/File.php
+++ b/apps/dav/lib/Connector/Sabre/File.php
@@ -51,6 +51,7 @@ use OCP\Files\InvalidContentException;
use OCP\Files\InvalidPathException;
use OCP\Files\LockNotAcquiredException;
use OCP\Files\NotPermittedException;
+use OCP\Files\Storage;
use OCP\Files\StorageNotAvailableException;
use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
@@ -135,8 +136,9 @@ class File extends Node implements IFile {
}
}
+ /** @var Storage $partStorage */
list($partStorage) = $this->fileView->resolvePath($this->path);
- $needsPartFile = $this->needsPartFile($partStorage) && (strlen($this->path) > 1);
+ $needsPartFile = $partStorage->needsPartFile() && (strlen($this->path) > 1);
if ($needsPartFile) {
// mark file as partial while uploading (ignored by the scanner)
@@ -443,8 +445,9 @@ class File extends Node implements IFile {
}
if ($chunk_handler->isComplete()) {
+ /** @var Storage $storage */
list($storage,) = $this->fileView->resolvePath($path);
- $needsPartFile = $this->needsPartFile($storage);
+ $needsPartFile = $storage->needsPartFile();
$partFile = null;
$targetPath = $path . '/' . $info['name'];
@@ -530,21 +533,6 @@ class File extends Node implements IFile {
}
/**
- * Returns whether a part file is needed for the given storage
- * or whether the file can be assembled/uploaded directly on the
- * target storage.
- *
- * @param \OCP\Files\Storage $storage
- * @return bool true if the storage needs part file handling
- */
- private function needsPartFile($storage) {
- // TODO: in the future use ChunkHandler provided by storage
- return !$storage->instanceOfStorage('OCA\Files_Sharing\External\Storage') &&
- !$storage->instanceOfStorage('OC\Files\Storage\OwnCloud') &&
- $storage->needsPartFile();
- }
-
- /**
* Convert the given exception to a SabreException instance
*
* @param \Exception $e
diff --git a/apps/dav/lib/Connector/Sabre/Node.php b/apps/dav/lib/Connector/Sabre/Node.php
index fd237b604a9..9e78d21a39d 100644
--- a/apps/dav/lib/Connector/Sabre/Node.php
+++ b/apps/dav/lib/Connector/Sabre/Node.php
@@ -272,7 +272,7 @@ abstract class Node implements \Sabre\DAV\INode {
$mountpointpath = substr($mountpointpath, 0, -1);
}
- if ($mountpointpath === $this->info->getPath()) {
+ if (!$mountpoint->getOption('readonly', false) && $mountpointpath === $this->info->getPath()) {
$permissions |= \OCP\Constants::PERMISSION_DELETE | \OCP\Constants::PERMISSION_UPDATE;
}
}
diff --git a/apps/dav/tests/unit/Connector/Sabre/ExceptionLoggerPluginTest.php b/apps/dav/tests/unit/Connector/Sabre/ExceptionLoggerPluginTest.php
index c1d48a7ce5d..1de9333207f 100644
--- a/apps/dav/tests/unit/Connector/Sabre/ExceptionLoggerPluginTest.php
+++ b/apps/dav/tests/unit/Connector/Sabre/ExceptionLoggerPluginTest.php
@@ -69,7 +69,7 @@ class ExceptionLoggerPluginTest extends TestCase {
});
$this->server = new Server();
- $this->logger = new TestLogger(Log\File::class, $config);
+ $this->logger = new TestLogger(new Log\File(\OC::$SERVERROOT.'/data/nextcloud.log', '', $config), $config);
$this->plugin = new PluginToTest('unit-test', $this->logger);
$this->plugin->initialize($this->server);
}
diff --git a/apps/files/css/files.scss b/apps/files/css/files.scss
index b89332248f7..d2d810c1e6c 100644
--- a/apps/files/css/files.scss
+++ b/apps/files/css/files.scss
@@ -105,9 +105,6 @@
.nav-icon-trashbin {
background-image: url('../img/delete.svg?v=1');
}
-.nav-icon-quota {
- background-image: url('../img/quota.svg?v=1');
-}
#app-navigation .nav-files a.nav-icon-files {
width: auto;
diff --git a/apps/files/img/quota.svg b/apps/files/img/quota.svg
deleted file mode 100644
index 691cb29efce..00000000000
--- a/apps/files/img/quota.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" viewBox="0 0 16 16" width="16" version="1.1"><path d="m8 1c-3.86 0-7 3.15-7 7s3.15 7 7 7c3.86 0 7-3.15 7-7 0-3.86-3.15-7-7-7zm0 1.75c2.91 0 5.25 2.34 5.25 5.25 0 1.42-0.56 2.7-1.47 3.644l-3.78-3.644z"/></svg>
diff --git a/apps/files/templates/appnavigation.php b/apps/files/templates/appnavigation.php
index a85e2515a92..c811ace8abe 100644
--- a/apps/files/templates/appnavigation.php
+++ b/apps/files/templates/appnavigation.php
@@ -15,7 +15,7 @@
if ($_['quota'] !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
?>has-tooltip" title="<?php p($_['usage_relative'] . '%');
} ?>">
- <a href="#" class="nav-icon-quota svg">
+ <a href="#" class="icon-quota svg">
<p id="quotatext"><?php
if ($_['quota'] !== \OCP\Files\FileInfo::SPACE_UNLIMITED) {
p($l->t('%s of %s used', [$_['usage'], $_['total_space']]));
diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js
index ffe1e972071..983348397d1 100644
--- a/apps/files_external/js/settings.js
+++ b/apps/files_external/js/settings.js
@@ -48,6 +48,12 @@ var MOUNT_OPTIONS_DROPDOWN_TEMPLATE =
' <label for="mountOptionsEncoding">{{mountOptionsEncodingLabel}}</label>'+
' </span>'+
' </li>'+
+ ' <li class="optionRow">' +
+ ' <span class="menuitem">' +
+ ' <input id="mountOptionsReadOnly" class="checkbox" name="readonly" type="checkbox" value="true"/>' +
+ ' <label for="mountOptionsReadOnly">{{t "files_external" "Read only"}}</label>' +
+ ' </span>' +
+ ' </li>' +
' </ul>'+
'</div>';
@@ -916,7 +922,8 @@ MountConfigListView.prototype = _.extend({
'previews': true,
'enable_sharing': false,
'filesystem_check_changes': 1,
- 'encoding_compatibility': false
+ 'encoding_compatibility': false,
+ 'readonly': false,
}));
}
@@ -1303,7 +1310,8 @@ MountConfigListView.prototype = _.extend({
'previews',
'filesystem_check_changes',
'enable_sharing',
- 'encoding_compatibility'
+ 'encoding_compatibility',
+ 'readonly'
];
if (this._encryptionEnabled) {
visibleOptions.push('encrypt');
diff --git a/apps/files_external/l10n/de.js b/apps/files_external/l10n/de.js
index 6fafc3e5489..eefbbe8c409 100644
--- a/apps/files_external/l10n/de.js
+++ b/apps/files_external/l10n/de.js
@@ -112,6 +112,7 @@ OC.L10N.register(
"Check for changes" : "Auf Änderungen prüfen",
"Never" : "Nie",
"Once every direct access" : "Einmal bei jedem Direktzugriff",
+ "Read only" : "Schreibgeschützt",
"Folder name" : "Ordnername",
"External storage" : "Externer Speicher",
"Authentication" : "Authentifizierung",
diff --git a/apps/files_external/l10n/de.json b/apps/files_external/l10n/de.json
index 89f089605b9..50c07260636 100644
--- a/apps/files_external/l10n/de.json
+++ b/apps/files_external/l10n/de.json
@@ -110,6 +110,7 @@
"Check for changes" : "Auf Änderungen prüfen",
"Never" : "Nie",
"Once every direct access" : "Einmal bei jedem Direktzugriff",
+ "Read only" : "Schreibgeschützt",
"Folder name" : "Ordnername",
"External storage" : "Externer Speicher",
"Authentication" : "Authentifizierung",
diff --git a/apps/files_external/l10n/de_DE.js b/apps/files_external/l10n/de_DE.js
index ca2d37523b2..13e44ab0cb9 100644
--- a/apps/files_external/l10n/de_DE.js
+++ b/apps/files_external/l10n/de_DE.js
@@ -112,6 +112,7 @@ OC.L10N.register(
"Check for changes" : "Auf Änderungen prüfen",
"Never" : "Nie",
"Once every direct access" : "Einmal bei jedem Direktzugriff",
+ "Read only" : "Schreibgeschützt",
"Folder name" : "Ordnername",
"External storage" : "Externer Speicher",
"Authentication" : "Authentifizierung",
diff --git a/apps/files_external/l10n/de_DE.json b/apps/files_external/l10n/de_DE.json
index 4ab53e25cbc..1f19a325427 100644
--- a/apps/files_external/l10n/de_DE.json
+++ b/apps/files_external/l10n/de_DE.json
@@ -110,6 +110,7 @@
"Check for changes" : "Auf Änderungen prüfen",
"Never" : "Nie",
"Once every direct access" : "Einmal bei jedem Direktzugriff",
+ "Read only" : "Schreibgeschützt",
"Folder name" : "Ordnername",
"External storage" : "Externer Speicher",
"Authentication" : "Authentifizierung",
diff --git a/apps/files_external/l10n/fr.js b/apps/files_external/l10n/fr.js
index 7533b976a14..a3b12150d45 100644
--- a/apps/files_external/l10n/fr.js
+++ b/apps/files_external/l10n/fr.js
@@ -112,6 +112,7 @@ OC.L10N.register(
"Check for changes" : "Rechercher les modifications",
"Never" : "Jamais",
"Once every direct access" : "Une fois à chaque accès direct",
+ "Read only" : "Lecture seule",
"Folder name" : "Nom du dossier",
"External storage" : "Stockage externe",
"Authentication" : "Authentification",
diff --git a/apps/files_external/l10n/fr.json b/apps/files_external/l10n/fr.json
index 73b8bc28c5b..8b0bc077c0e 100644
--- a/apps/files_external/l10n/fr.json
+++ b/apps/files_external/l10n/fr.json
@@ -110,6 +110,7 @@
"Check for changes" : "Rechercher les modifications",
"Never" : "Jamais",
"Once every direct access" : "Une fois à chaque accès direct",
+ "Read only" : "Lecture seule",
"Folder name" : "Nom du dossier",
"External storage" : "Stockage externe",
"Authentication" : "Authentification",
diff --git a/apps/files_external/l10n/it.js b/apps/files_external/l10n/it.js
index 26cf94da6d5..f8ac97f6f68 100644
--- a/apps/files_external/l10n/it.js
+++ b/apps/files_external/l10n/it.js
@@ -112,6 +112,7 @@ OC.L10N.register(
"Check for changes" : "Controlla le modifiche",
"Never" : "Mai",
"Once every direct access" : "Una volta per ogni accesso diretto",
+ "Read only" : "Sola lettura",
"Folder name" : "Nome della cartella",
"External storage" : "Archiviazione esterna",
"Authentication" : "Autenticazione",
diff --git a/apps/files_external/l10n/it.json b/apps/files_external/l10n/it.json
index a8151db2395..6495f32fc8d 100644
--- a/apps/files_external/l10n/it.json
+++ b/apps/files_external/l10n/it.json
@@ -110,6 +110,7 @@
"Check for changes" : "Controlla le modifiche",
"Never" : "Mai",
"Once every direct access" : "Una volta per ogni accesso diretto",
+ "Read only" : "Sola lettura",
"Folder name" : "Nome della cartella",
"External storage" : "Archiviazione esterna",
"Authentication" : "Autenticazione",
diff --git a/apps/files_external/l10n/pt_BR.js b/apps/files_external/l10n/pt_BR.js
index f1624a0f9ea..a04fc14c8a3 100644
--- a/apps/files_external/l10n/pt_BR.js
+++ b/apps/files_external/l10n/pt_BR.js
@@ -112,6 +112,7 @@ OC.L10N.register(
"Check for changes" : "Verifique se há alterações",
"Never" : "Nunca",
"Once every direct access" : "Uma vez a cada acesso direto",
+ "Read only" : "Somente leitura",
"Folder name" : "Nome da pasta",
"External storage" : "Armazenamento Externo",
"Authentication" : "Autenticação",
diff --git a/apps/files_external/l10n/pt_BR.json b/apps/files_external/l10n/pt_BR.json
index 80d6ba18e09..bfe10a37539 100644
--- a/apps/files_external/l10n/pt_BR.json
+++ b/apps/files_external/l10n/pt_BR.json
@@ -110,6 +110,7 @@
"Check for changes" : "Verifique se há alterações",
"Never" : "Nunca",
"Once every direct access" : "Uma vez a cada acesso direto",
+ "Read only" : "Somente leitura",
"Folder name" : "Nome da pasta",
"External storage" : "Armazenamento Externo",
"Authentication" : "Autenticação",
diff --git a/apps/files_external/l10n/ru.js b/apps/files_external/l10n/ru.js
index 39e02bdabde..fbb90ba4a89 100644
--- a/apps/files_external/l10n/ru.js
+++ b/apps/files_external/l10n/ru.js
@@ -112,6 +112,7 @@ OC.L10N.register(
"Check for changes" : "Проверять изменения",
"Never" : "Никогда",
"Once every direct access" : "Каждый раз при прямом доступе",
+ "Read only" : "Только чтение",
"Folder name" : "Имя папки",
"External storage" : "Внешнее хранилище",
"Authentication" : "Способ авторизации",
diff --git a/apps/files_external/l10n/ru.json b/apps/files_external/l10n/ru.json
index 387b9087209..ff6df5b9a55 100644
--- a/apps/files_external/l10n/ru.json
+++ b/apps/files_external/l10n/ru.json
@@ -110,6 +110,7 @@
"Check for changes" : "Проверять изменения",
"Never" : "Никогда",
"Once every direct access" : "Каждый раз при прямом доступе",
+ "Read only" : "Только чтение",
"Folder name" : "Имя папки",
"External storage" : "Внешнее хранилище",
"Authentication" : "Способ авторизации",
diff --git a/apps/files_external/l10n/tr.js b/apps/files_external/l10n/tr.js
index 9d854556b97..bcc1c64cc0c 100644
--- a/apps/files_external/l10n/tr.js
+++ b/apps/files_external/l10n/tr.js
@@ -112,6 +112,7 @@ OC.L10N.register(
"Check for changes" : "Değişiklikleri denetle",
"Never" : "Asla",
"Once every direct access" : "Her doğrudan erişimde bir kez",
+ "Read only" : "Salt okunur",
"Folder name" : "Klasör adı",
"External storage" : "Dış depolama",
"Authentication" : "Kimlik Doğrulama",
diff --git a/apps/files_external/l10n/tr.json b/apps/files_external/l10n/tr.json
index 4376d41228c..73ebf0c7759 100644
--- a/apps/files_external/l10n/tr.json
+++ b/apps/files_external/l10n/tr.json
@@ -110,6 +110,7 @@
"Check for changes" : "Değişiklikleri denetle",
"Never" : "Asla",
"Once every direct access" : "Her doğrudan erişimde bir kez",
+ "Read only" : "Salt okunur",
"Folder name" : "Klasör adı",
"External storage" : "Dış depolama",
"Authentication" : "Kimlik Doğrulama",
diff --git a/apps/files_external/lib/Command/ListCommand.php b/apps/files_external/lib/Command/ListCommand.php
index efb2669e281..89bdcf5e5d6 100644
--- a/apps/files_external/lib/Command/ListCommand.php
+++ b/apps/files_external/lib/Command/ListCommand.php
@@ -192,7 +192,8 @@ class ListCommand extends Base {
'previews' => true,
'filesystem_check_changes' => 1,
'enable_sharing' => false,
- 'encoding_compatibility' => false
+ 'encoding_compatibility' => false,
+ 'readonly' => false,
];
$rows = array_map(function (StorageConfig $config) use ($userId, $defaultMountOptions, $full) {
$storageConfig = $config->getBackendOptions();
diff --git a/apps/files_external/lib/Lib/Storage/OwnCloud.php b/apps/files_external/lib/Lib/Storage/OwnCloud.php
index d56e6b66145..3ee2b70ef22 100644
--- a/apps/files_external/lib/Lib/Storage/OwnCloud.php
+++ b/apps/files_external/lib/Lib/Storage/OwnCloud.php
@@ -73,4 +73,8 @@ class OwnCloud extends \OC\Files\Storage\DAV{
parent::__construct($params);
}
+
+ public function needsPartFile() {
+ return false;
+ }
}
diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php
index 895be719ab4..236faf37d6d 100644
--- a/apps/files_external/templates/settings.php
+++ b/apps/files_external/templates/settings.php
@@ -12,6 +12,7 @@
$l->t("Check for changes");
$l->t("Never");
$l->t("Once every direct access");
+ $l->t('Read only');
script('files_external', 'settings');
style('files_external', 'settings');
diff --git a/apps/files_external/tests/js/settingsSpec.js b/apps/files_external/tests/js/settingsSpec.js
index 56bdcff8345..fbbb341c307 100644
--- a/apps/files_external/tests/js/settingsSpec.js
+++ b/apps/files_external/tests/js/settingsSpec.js
@@ -376,7 +376,8 @@ describe('OCA.External.Settings tests', function() {
previews: true,
enable_sharing: false,
filesystem_check_changes: 0,
- encoding_compatibility: false
+ encoding_compatibility: false,
+ readonly: false
});
});
});
diff --git a/apps/files_sharing/lib/External/Storage.php b/apps/files_sharing/lib/External/Storage.php
index 638f82f7027..a631a029aba 100644
--- a/apps/files_sharing/lib/External/Storage.php
+++ b/apps/files_sharing/lib/External/Storage.php
@@ -366,4 +366,7 @@ class Storage extends DAV implements ISharedStorage {
return $permissions;
}
+ public function needsPartFile() {
+ return false;
+ }
}
diff --git a/apps/files_sharing/tests/js/sharedfilelistSpec.js b/apps/files_sharing/tests/js/sharedfilelistSpec.js
index 492a7255c61..0897e9c956d 100644
--- a/apps/files_sharing/tests/js/sharedfilelistSpec.js
+++ b/apps/files_sharing/tests/js/sharedfilelistSpec.js
@@ -727,7 +727,8 @@ describe('OCA.Sharing.FileList tests', function() {
etag: 'abc',
shareOwner: 'User One',
recipients: 'User Two',
- mountType: 'external-root'
+ mountType: 'external-root',
+ sharePermissions: OC.PERMISSION_READ,
}]);
$tr = fileList.$el.find('tr:first');
@@ -749,7 +750,8 @@ describe('OCA.Sharing.FileList tests', function() {
etag: 'abc',
shareOwner: 'User One',
recipients: 'User Two',
- mountType: 'external-root'
+ mountType: 'external-root',
+ sharePermissions: OC.PERMISSION_READ | OC.PERMISSION_SHARE,
}]);
$tr = fileList.$el.find('tr:first');
diff --git a/apps/files_versions/appinfo/info.xml b/apps/files_versions/appinfo/info.xml
index 8f7e4d7b716..3edce7775fc 100644
--- a/apps/files_versions/appinfo/info.xml
+++ b/apps/files_versions/appinfo/info.xml
@@ -8,7 +8,7 @@
This application automatically maintains older versions of files that are changed. When enabled, a hidden versions folder is provisioned in every user’s directory and is used to store old file versions. A user can revert to an older version through the web interface at any time, with the replaced file becoming a version. The app automatically manages the versions folder to ensure the user doesn’t run out of Quota because of versions.
In addition to the expiry of versions, the versions app makes certain never to use more than 50% of the user’s currently available free space. If stored versions exceed this limit, the app will delete the oldest versions first until it meets this limit. More information is available in the Versions documentation.
</description>
- <version>1.7.0</version>
+ <version>1.7.1</version>
<licence>agpl</licence>
<author>Frank Karlitschek</author>
<author>Bjoern Schiessle</author>
@@ -16,6 +16,7 @@
<default_enable/>
<types>
<filesystem/>
+ <dav/>
</types>
<documentation>
<user>user-versions</user>
@@ -34,4 +35,10 @@
<command>OCA\Files_Versions\Command\CleanUp</command>
<command>OCA\Files_Versions\Command\ExpireVersions</command>
</commands>
+
+ <sabre>
+ <collections>
+ <collection>OCA\Files_Versions\Sabre\RootCollection</collection>
+ </collections>
+ </sabre>
</info>
diff --git a/apps/files_versions/composer/composer/autoload_classmap.php b/apps/files_versions/composer/composer/autoload_classmap.php
index 05dad7f7c5f..4bb112b4f11 100644
--- a/apps/files_versions/composer/composer/autoload_classmap.php
+++ b/apps/files_versions/composer/composer/autoload_classmap.php
@@ -16,5 +16,11 @@ return array(
'OCA\\Files_Versions\\Events\\CreateVersionEvent' => $baseDir . '/../lib/Events/CreateVersionEvent.php',
'OCA\\Files_Versions\\Expiration' => $baseDir . '/../lib/Expiration.php',
'OCA\\Files_Versions\\Hooks' => $baseDir . '/../lib/Hooks.php',
+ 'OCA\\Files_Versions\\Sabre\\RestoreFolder' => $baseDir . '/../lib/Sabre/RestoreFolder.php',
+ 'OCA\\Files_Versions\\Sabre\\RootCollection' => $baseDir . '/../lib/Sabre/RootCollection.php',
+ 'OCA\\Files_Versions\\Sabre\\VersionCollection' => $baseDir . '/../lib/Sabre/VersionCollection.php',
+ 'OCA\\Files_Versions\\Sabre\\VersionFile' => $baseDir . '/../lib/Sabre/VersionFile.php',
+ 'OCA\\Files_Versions\\Sabre\\VersionHome' => $baseDir . '/../lib/Sabre/VersionHome.php',
+ 'OCA\\Files_Versions\\Sabre\\VersionRoot' => $baseDir . '/../lib/Sabre/VersionRoot.php',
'OCA\\Files_Versions\\Storage' => $baseDir . '/../lib/Storage.php',
);
diff --git a/apps/files_versions/composer/composer/autoload_static.php b/apps/files_versions/composer/composer/autoload_static.php
index 9ac3b049030..29bc592b41c 100644
--- a/apps/files_versions/composer/composer/autoload_static.php
+++ b/apps/files_versions/composer/composer/autoload_static.php
@@ -31,6 +31,12 @@ class ComposerStaticInitFiles_Versions
'OCA\\Files_Versions\\Events\\CreateVersionEvent' => __DIR__ . '/..' . '/../lib/Events/CreateVersionEvent.php',
'OCA\\Files_Versions\\Expiration' => __DIR__ . '/..' . '/../lib/Expiration.php',
'OCA\\Files_Versions\\Hooks' => __DIR__ . '/..' . '/../lib/Hooks.php',
+ 'OCA\\Files_Versions\\Sabre\\RestoreFolder' => __DIR__ . '/..' . '/../lib/Sabre/RestoreFolder.php',
+ 'OCA\\Files_Versions\\Sabre\\RootCollection' => __DIR__ . '/..' . '/../lib/Sabre/RootCollection.php',
+ 'OCA\\Files_Versions\\Sabre\\VersionCollection' => __DIR__ . '/..' . '/../lib/Sabre/VersionCollection.php',
+ 'OCA\\Files_Versions\\Sabre\\VersionFile' => __DIR__ . '/..' . '/../lib/Sabre/VersionFile.php',
+ 'OCA\\Files_Versions\\Sabre\\VersionHome' => __DIR__ . '/..' . '/../lib/Sabre/VersionHome.php',
+ 'OCA\\Files_Versions\\Sabre\\VersionRoot' => __DIR__ . '/..' . '/../lib/Sabre/VersionRoot.php',
'OCA\\Files_Versions\\Storage' => __DIR__ . '/..' . '/../lib/Storage.php',
);
diff --git a/apps/files_versions/lib/AppInfo/Application.php b/apps/files_versions/lib/AppInfo/Application.php
index e09299c8bc8..4431fbf51bf 100644
--- a/apps/files_versions/lib/AppInfo/Application.php
+++ b/apps/files_versions/lib/AppInfo/Application.php
@@ -23,6 +23,7 @@
namespace OCA\Files_Versions\AppInfo;
+use OCA\DAV\Connector\Sabre\Principal;
use OCP\AppFramework\App;
use OCA\Files_Versions\Expiration;
use OCP\AppFramework\Utility\ITimeFactory;
@@ -48,5 +49,17 @@ class Application extends App {
$c->query(ITimeFactory::class)
);
});
+
+ /*
+ * Register $principalBackend for the DAV collection
+ */
+ $container->registerService('principalBackend', function () {
+ return new Principal(
+ \OC::$server->getUserManager(),
+ \OC::$server->getGroupManager(),
+ \OC::$server->getShareManager(),
+ \OC::$server->getUserSession()
+ );
+ });
}
}
diff --git a/apps/files_versions/lib/Sabre/RestoreFolder.php b/apps/files_versions/lib/Sabre/RestoreFolder.php
new file mode 100644
index 00000000000..c398d02692b
--- /dev/null
+++ b/apps/files_versions/lib/Sabre/RestoreFolder.php
@@ -0,0 +1,86 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Files_Versions\Sabre;
+
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\ICollection;
+use Sabre\DAV\IMoveTarget;
+use Sabre\DAV\INode;
+
+
+class RestoreFolder implements ICollection, IMoveTarget {
+
+ /** @var string */
+ protected $userId;
+
+ public function __construct(string $userId) {
+ $this->userId = $userId;
+ }
+
+ public function createFile($name, $data = null) {
+ throw new Forbidden();
+ }
+
+ public function createDirectory($name) {
+ throw new Forbidden();
+ }
+
+ public function getChild($name) {
+ return null;
+ }
+
+ public function delete() {
+ throw new Forbidden();
+ }
+
+ public function getName() {
+ return 'restore';
+ }
+
+ public function setName($name) {
+ throw new Forbidden();
+ }
+
+ public function getLastModified(): int {
+ return 0;
+ }
+
+ public function getChildren(): array {
+ return [];
+ }
+
+ public function childExists($name): bool {
+ return false;
+ }
+
+ public function moveInto($targetName, $sourcePath, INode $sourceNode): bool {
+ if (!($sourceNode instanceof VersionFile)) {
+ return false;
+ }
+
+ return $sourceNode->rollBack();
+ }
+
+}
diff --git a/apps/files_versions/lib/Sabre/RootCollection.php b/apps/files_versions/lib/Sabre/RootCollection.php
new file mode 100644
index 00000000000..397f1c55891
--- /dev/null
+++ b/apps/files_versions/lib/Sabre/RootCollection.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Versions\Sabre;
+
+use OCP\Files\IRootFolder;
+use Sabre\DAV\INode;
+use Sabre\DAVACL\AbstractPrincipalCollection;
+use Sabre\DAVACL\PrincipalBackend;
+
+class RootCollection extends AbstractPrincipalCollection {
+
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ public function __construct(PrincipalBackend\BackendInterface $principalBackend,
+ IRootFolder $rootFolder) {
+ parent::__construct($principalBackend, 'principals/users');
+
+ $this->rootFolder = $rootFolder;
+ }
+
+ /**
+ * This method returns a node for a principal.
+ *
+ * The passed array contains principal information, and is guaranteed to
+ * at least contain a uri item. Other properties may or may not be
+ * supplied by the authentication backend.
+ *
+ * @param array $principalInfo
+ * @return INode
+ */
+ public function getChildForPrincipal(array $principalInfo) {
+ list(,$name) = \Sabre\Uri\split($principalInfo['uri']);
+ $user = \OC::$server->getUserSession()->getUser();
+ if (is_null($user) || $name !== $user->getUID()) {
+ throw new \Sabre\DAV\Exception\Forbidden();
+ }
+ return new VersionHome($principalInfo, $this->rootFolder);
+ }
+
+ public function getName() {
+ return 'versions';
+ }
+
+}
diff --git a/apps/files_versions/lib/Sabre/VersionCollection.php b/apps/files_versions/lib/Sabre/VersionCollection.php
new file mode 100644
index 00000000000..481a5f491c3
--- /dev/null
+++ b/apps/files_versions/lib/Sabre/VersionCollection.php
@@ -0,0 +1,102 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Versions\Sabre;
+
+use OCA\Files_Versions\Storage;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\ICollection;
+
+class VersionCollection implements ICollection {
+ /** @var Folder */
+ private $userFolder;
+
+ /** @var File */
+ private $file;
+
+ /** @var string */
+ private $userId;
+
+ public function __construct(Folder $userFolder, File $file, string $userId) {
+ $this->userFolder = $userFolder;
+ $this->file = $file;
+ $this->userId = $userId;
+ }
+
+ public function createFile($name, $data = null) {
+ throw new Forbidden();
+ }
+
+ public function createDirectory($name) {
+ throw new Forbidden();
+ }
+
+ public function getChild($name) {
+ /** @var VersionFile[] $versions */
+ $versions = $this->getChildren();
+
+ foreach ($versions as $version) {
+ if ($version->getName() === $name) {
+ return $version;
+ }
+ }
+
+ throw new NotFound();
+ }
+
+ public function getChildren(): array {
+ $versions = Storage::getVersions($this->userId, $this->userFolder->getRelativePath($this->file->getPath()));
+
+ return array_map(function (array $data) {
+ return new VersionFile($data, $this->userFolder->getParent());
+ }, $versions);
+ }
+
+ public function childExists($name): bool {
+ try {
+ $this->getChild($name);
+ return true;
+ } catch (NotFound $e) {
+ return false;
+ }
+ }
+
+ public function delete() {
+ throw new Forbidden();
+ }
+
+ public function getName(): string {
+ return (string)$this->file->getId();
+ }
+
+ public function setName($name) {
+ throw new Forbidden();
+ }
+
+ public function getLastModified(): int {
+ return 0;
+ }
+}
diff --git a/apps/files_versions/lib/Sabre/VersionFile.php b/apps/files_versions/lib/Sabre/VersionFile.php
new file mode 100644
index 00000000000..347058448fc
--- /dev/null
+++ b/apps/files_versions/lib/Sabre/VersionFile.php
@@ -0,0 +1,94 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Versions\Sabre;
+
+use OCA\Files_Versions\Storage;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\NotFoundException;
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\IFile;
+
+class VersionFile implements IFile {
+ /** @var array */
+ private $data;
+
+ /** @var Folder */
+ private $userRoot;
+
+ public function __construct(array $data, Folder $userRoot) {
+ $this->data = $data;
+ $this->userRoot = $userRoot;
+ }
+
+ public function put($data) {
+ throw new Forbidden();
+ }
+
+ public function get() {
+ try {
+ /** @var Folder $versions */
+ $versions = $this->userRoot->get('files_versions');
+ /** @var File $version */
+ $version = $versions->get($this->data['path'].'.v'.$this->data['version']);
+ } catch (NotFoundException $e) {
+ throw new NotFound();
+ }
+
+ return $version->fopen('rb');
+ }
+
+ public function getContentType(): string {
+ return $this->data['mimetype'];
+ }
+
+ public function getETag(): string {
+ return $this->data['version'];
+ }
+
+ public function getSize(): int {
+ return $this->data['size'];
+ }
+
+ public function delete() {
+ throw new Forbidden();
+ }
+
+ public function getName(): string {
+ return $this->data['version'];
+ }
+
+ public function setName($name) {
+ throw new Forbidden();
+ }
+
+ public function getLastModified(): int {
+ return (int)$this->data['version'];
+ }
+
+ public function rollBack(): bool {
+ return Storage::rollback($this->data['path'], $this->data['version']);
+ }
+}
diff --git a/apps/files_versions/lib/Sabre/VersionHome.php b/apps/files_versions/lib/Sabre/VersionHome.php
new file mode 100644
index 00000000000..7a99d2376d4
--- /dev/null
+++ b/apps/files_versions/lib/Sabre/VersionHome.php
@@ -0,0 +1,90 @@
+<?php
+/**
+ * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Versions\Sabre;
+
+use OCP\Files\IRootFolder;
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\ICollection;
+
+class VersionHome implements ICollection {
+
+ /** @var array */
+ private $principalInfo;
+
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ public function __construct(array $principalInfo, IRootFolder $rootFolder) {
+ $this->principalInfo = $principalInfo;
+ $this->rootFolder = $rootFolder;
+ }
+
+ public function delete() {
+ throw new Forbidden();
+ }
+
+ public function getName(): string {
+ list(,$name) = \Sabre\Uri\split($this->principalInfo['uri']);
+ return $name;
+ }
+
+ public function setName($name) {
+ throw new Forbidden();
+ }
+
+ public function createFile($name, $data = null) {
+ throw new Forbidden();
+ }
+
+ public function createDirectory($name) {
+ throw new Forbidden();
+ }
+
+ public function getChild($name) {
+ list(,$userId) = \Sabre\Uri\split($this->principalInfo['uri']);
+
+ if ($name === 'versions') {
+ return new VersionRoot($userId, $this->rootFolder);
+ }
+ if ($name === 'restore') {
+ return new RestoreFolder($userId);
+ }
+ }
+
+ public function getChildren() {
+ list(,$userId) = \Sabre\Uri\split($this->principalInfo['uri']);
+
+ return [
+ new VersionRoot($userId, $this->rootFolder),
+ new RestoreFolder($userId),
+ ];
+ }
+
+ public function childExists($name) {
+ return $name === 'versions' || $name === 'restore';
+ }
+
+ public function getLastModified() {
+ return 0;
+ }
+}
diff --git a/apps/files_versions/lib/Sabre/VersionRoot.php b/apps/files_versions/lib/Sabre/VersionRoot.php
new file mode 100644
index 00000000000..743b1c6ef1b
--- /dev/null
+++ b/apps/files_versions/lib/Sabre/VersionRoot.php
@@ -0,0 +1,100 @@
+<?php
+declare(strict_types=1);
+/**
+ * @copyright 2018, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Versions\Sabre;
+
+use OCP\Files\File;
+use OCP\Files\IRootFolder;
+use Sabre\DAV\Exception\Forbidden;
+use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\ICollection;
+
+class VersionRoot implements ICollection {
+
+ /** @var string */
+ private $userId;
+
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ public function __construct(string $userId, IRootFolder $rootFolder) {
+ $this->userId = $userId;
+ $this->rootFolder = $rootFolder;
+ }
+
+ public function delete() {
+ throw new Forbidden();
+ }
+
+ public function getName(): string {
+ return 'versions';
+ }
+
+ public function setName($name) {
+ throw new Forbidden();
+ }
+
+ public function createFile($name, $data = null) {
+ throw new Forbidden();
+ }
+
+ public function createDirectory($name) {
+ throw new Forbidden();
+ }
+
+ public function getChild($name) {
+ $userFolder = $this->rootFolder->getUserFolder($this->userId);
+
+ $fileId = (int)$name;
+ $nodes = $userFolder->getById($fileId);
+
+ if ($nodes === []) {
+ throw new NotFound();
+ }
+
+ $node = array_pop($nodes);
+
+ if (!$node instanceof File) {
+ throw new NotFound();
+ }
+
+ return new VersionCollection($userFolder, $node, $this->userId);
+ }
+
+ public function getChildren(): array {
+ return [];
+ }
+
+ public function childExists($name): bool {
+ try {
+ $this->getChild($name);
+ return true;
+ } catch (NotFound $e) {
+ return false;
+ }
+ }
+
+ public function getLastModified(): int {
+ return 0;
+ }
+}