summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/encryption/lib/Controller/StatusController.php2
-rw-r--r--apps/encryption/templates/settings-personal.php2
-rw-r--r--apps/files/appinfo/info.xml3
-rw-r--r--apps/files/lib/Command/ScanAppData.php284
-rw-r--r--apps/files/lib/Command/TransferOwnership.php37
-rw-r--r--apps/files_external/js/settings.js14
-rw-r--r--apps/files_external/lib/Lib/Storage/OwnCloud.php2
-rw-r--r--apps/files_external/templates/settings.php8
-rw-r--r--apps/files_external/tests/js/settingsSpec.js13
-rw-r--r--apps/files_sharing/lib/SharedStorage.php20
-rw-r--r--apps/files_sharing/tests/SharedStorageTest.php38
-rw-r--r--apps/files_trashbin/lib/Helper.php11
-rw-r--r--apps/files_trashbin/lib/Trashbin.php6
13 files changed, 409 insertions, 31 deletions
diff --git a/apps/encryption/lib/Controller/StatusController.php b/apps/encryption/lib/Controller/StatusController.php
index 6882475e972..0776a84ceb4 100644
--- a/apps/encryption/lib/Controller/StatusController.php
+++ b/apps/encryption/lib/Controller/StatusController.php
@@ -79,7 +79,7 @@ class StatusController extends Controller {
case Session::NOT_INITIALIZED:
$status = 'interactionNeeded';
$message = (string)$this->l->t(
- 'Encryption app is enabled but your keys are not initialized, please log-out and log-in again'
+ 'Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again.'
);
break;
case Session::INIT_SUCCESSFUL:
diff --git a/apps/encryption/templates/settings-personal.php b/apps/encryption/templates/settings-personal.php
index 2ea55e15c80..6ab4bf6f5f4 100644
--- a/apps/encryption/templates/settings-personal.php
+++ b/apps/encryption/templates/settings-personal.php
@@ -9,7 +9,7 @@ script('core', 'multiselect');
<?php if ($_["initialized"] === \OCA\Encryption\Session::NOT_INITIALIZED ): ?>
- <?php p($l->t("Encryption App is enabled but your keys are not initialized, please log-out and log-in again")); ?>
+ <?php p($l->t("Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again.")); ?>
<?php elseif ( $_["initialized"] === \OCA\Encryption\Session::INIT_EXECUTED ): ?>
<p>
diff --git a/apps/files/appinfo/info.xml b/apps/files/appinfo/info.xml
index d956a237767..8b5678b331a 100644
--- a/apps/files/appinfo/info.xml
+++ b/apps/files/appinfo/info.xml
@@ -6,7 +6,7 @@
<licence>AGPL</licence>
<author>Robin Appelman, Vincent Petry</author>
<default_enable/>
- <version>1.7.1</version>
+ <version>1.7.2</version>
<types>
<filesystem/>
</types>
@@ -52,6 +52,7 @@
<command>OCA\Files\Command\Scan</command>
<command>OCA\Files\Command\DeleteOrphanedFiles</command>
<command>OCA\Files\Command\TransferOwnership</command>
+ <command>OCA\Files\Command\ScanAppData</command>
</commands>
<navigation>
diff --git a/apps/files/lib/Command/ScanAppData.php b/apps/files/lib/Command/ScanAppData.php
new file mode 100644
index 00000000000..365e2e3cb2e
--- /dev/null
+++ b/apps/files/lib/Command/ScanAppData.php
@@ -0,0 +1,284 @@
+<?php
+
+
+namespace OCA\Files\Command;
+
+use Doctrine\DBAL\Connection;
+use OC\Core\Command\Base;
+use OC\Core\Command\InterruptedException;
+use OC\ForbiddenException;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Files\StorageNotAvailableException;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\IUserManager;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Helper\Table;
+
+class ScanAppData extends Base {
+
+ /** @var IRootFolder */
+ protected $root;
+ /** @var IConfig */
+ protected $config;
+ /** @var float */
+ protected $execTime = 0;
+ /** @var int */
+ protected $foldersCounter = 0;
+ /** @var int */
+ protected $filesCounter = 0;
+
+ public function __construct(IRootFolder $rootFolder, IConfig $config) {
+ parent::__construct();
+
+ $this->root = $rootFolder;
+ $this->config = $config;
+ }
+
+ protected function configure() {
+ parent::configure();
+
+ $this
+ ->setName('files:scan-app-data')
+ ->setDescription('rescan the AppData folder')
+ ->addOption(
+ 'quiet',
+ 'q',
+ InputOption::VALUE_NONE,
+ 'suppress any output'
+ )
+ ->addOption(
+ 'verbose',
+ '-v|vv|vvv',
+ InputOption::VALUE_NONE,
+ 'verbose the output'
+ );
+ }
+
+ public function checkScanWarning($fullPath, OutputInterface $output) {
+ $normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
+ $path = basename($fullPath);
+
+ if ($normalizedPath !== $path) {
+ $output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
+ }
+ }
+
+ protected function scanFiles($verbose, OutputInterface $output) {
+ try {
+ $appData = $this->getAppDataFolder();
+ } catch (NotFoundException $e) {
+ $output->writeln('NoAppData folder found');
+ return;
+ }
+
+ $connection = $this->reconnectToDatabase($output);
+ $scanner = new \OC\Files\Utils\Scanner(null, $connection, \OC::$server->getLogger());
+ # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
+ # printout and count
+ if ($verbose) {
+ $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
+ $output->writeln("\tFile <info>$path</info>");
+ $this->filesCounter += 1;
+ if ($this->hasBeenInterrupted()) {
+ throw new InterruptedException();
+ }
+ });
+ $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
+ $output->writeln("\tFolder <info>$path</info>");
+ $this->foldersCounter += 1;
+ if ($this->hasBeenInterrupted()) {
+ throw new InterruptedException();
+ }
+ });
+ $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
+ $output->writeln("Error while scanning, storage not available (" . $e->getMessage() . ")");
+ });
+ # count only
+ } else {
+ $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function () use ($output) {
+ $this->filesCounter += 1;
+ if ($this->hasBeenInterrupted()) {
+ throw new InterruptedException();
+ }
+ });
+ $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function () use ($output) {
+ $this->foldersCounter += 1;
+ if ($this->hasBeenInterrupted()) {
+ throw new InterruptedException();
+ }
+ });
+ }
+ $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) {
+ $this->checkScanWarning($path, $output);
+ });
+ $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) {
+ $this->checkScanWarning($path, $output);
+ });
+
+ try {
+ $scanner->scan($appData->getPath());
+ } catch (ForbiddenException $e) {
+ $output->writeln("<error>Storage not writable</error>");
+ $output->writeln("Make sure you're running the scan command only as the user the web server runs as");
+ } catch (InterruptedException $e) {
+ # exit the function if ctrl-c has been pressed
+ $output->writeln('Interrupted by user');
+ } catch (\Exception $e) {
+ $output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
+ $output->writeln('<error>' . $e->getTraceAsString() . '</error>');
+ }
+ }
+
+
+ protected function execute(InputInterface $input, OutputInterface $output) {
+ # no messaging level option means: no full printout but statistics
+ # $quiet means no print at all
+ # $verbose means full printout including statistics
+ # -q -v full stat
+ # 0 0 no yes
+ # 0 1 yes yes
+ # 1 -- no no (quiet overrules verbose)
+ $verbose = $input->getOption('verbose');
+ $quiet = $input->getOption('quiet');
+ # restrict the verbosity level to VERBOSITY_VERBOSE
+ if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
+ $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
+ }
+ if ($quiet) {
+ $verbose = false;
+ }
+
+ $output->writeln("\nScanning AppData for files");
+
+ $this->initTools();
+
+ $this->scanFiles($verbose, $output);
+
+ # stat: printout statistics if $quiet was not set
+ if (!$quiet) {
+ $this->presentStats($output);
+ }
+ }
+
+ /**
+ * Initialises some useful tools for the Command
+ */
+ protected function initTools() {
+ // Start the timer
+ $this->execTime = -microtime(true);
+ // Convert PHP errors to exceptions
+ set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
+ }
+
+ /**
+ * Processes PHP errors as exceptions in order to be able to keep track of problems
+ *
+ * @see https://secure.php.net/manual/en/function.set-error-handler.php
+ *
+ * @param int $severity the level of the error raised
+ * @param string $message
+ * @param string $file the filename that the error was raised in
+ * @param int $line the line number the error was raised
+ *
+ * @throws \ErrorException
+ */
+ public function exceptionErrorHandler($severity, $message, $file, $line) {
+ if (!(error_reporting() & $severity)) {
+ // This error code is not included in error_reporting
+ return;
+ }
+ throw new \ErrorException($message, 0, $severity, $file, $line);
+ }
+
+ /**
+ * @param OutputInterface $output
+ */
+ protected function presentStats(OutputInterface $output) {
+ // Stop the timer
+ $this->execTime += microtime(true);
+ $output->writeln("");
+
+ $headers = [
+ 'Folders', 'Files', 'Elapsed time'
+ ];
+
+ $this->showSummary($headers, null, $output);
+ }
+
+ /**
+ * Shows a summary of operations
+ *
+ * @param string[] $headers
+ * @param string[] $rows
+ * @param OutputInterface $output
+ */
+ protected function showSummary($headers, $rows, OutputInterface $output) {
+ $niceDate = $this->formatExecTime();
+ if (!$rows) {
+ $rows = [
+ $this->foldersCounter,
+ $this->filesCounter,
+ $niceDate,
+ ];
+ }
+ $table = new Table($output);
+ $table
+ ->setHeaders($headers)
+ ->setRows([$rows]);
+ $table->render();
+ }
+
+
+ /**
+ * Formats microtime into a human readable format
+ *
+ * @return string
+ */
+ protected function formatExecTime() {
+ list($secs, $tens) = explode('.', sprintf("%.1f", ($this->execTime)));
+
+ # if you want to have microseconds add this: . '.' . $tens;
+ return date('H:i:s', $secs);
+ }
+
+ /**
+ * @return \OCP\IDBConnection
+ */
+ protected function reconnectToDatabase(OutputInterface $output) {
+ /** @var Connection | IDBConnection $connection*/
+ $connection = \OC::$server->getDatabaseConnection();
+ try {
+ $connection->close();
+ } catch (\Exception $ex) {
+ $output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
+ }
+ while (!$connection->isConnected()) {
+ try {
+ $connection->connect();
+ } catch (\Exception $ex) {
+ $output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
+ sleep(60);
+ }
+ }
+ return $connection;
+ }
+
+ /**
+ * @return \OCP\Files\Folder
+ * @throws NotFoundException
+ */
+ private function getAppDataFolder() {
+ $instanceId = $this->config->getSystemValue('instanceid', null);
+
+ if ($instanceId === null) {
+ throw new NotFoundException();
+ }
+
+ return $this->root->get('appdata_'.$instanceId);
+ }
+}
diff --git a/apps/files/lib/Command/TransferOwnership.php b/apps/files/lib/Command/TransferOwnership.php
index 96281b5226c..aa07cf9de91 100644
--- a/apps/files/lib/Command/TransferOwnership.php
+++ b/apps/files/lib/Command/TransferOwnership.php
@@ -34,6 +34,7 @@ use OCP\IUserManager;
use OCP\Share\IManager;
use OCP\Share\IShare;
use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@@ -66,6 +67,9 @@ class TransferOwnership extends Command {
private $destinationUser;
/** @var string */
+ private $sourcePath;
+
+ /** @var string */
private $finalTarget;
public function __construct(IUserManager $userManager, IManager $shareManager, IMountManager $mountManager) {
@@ -88,6 +92,13 @@ class TransferOwnership extends Command {
'destination-user',
InputArgument::REQUIRED,
'user who will be the new owner of the files'
+ )
+ ->addOption(
+ 'path',
+ null,
+ InputOption::VALUE_REQUIRED,
+ 'selectively provide the path to transfer. For example --path="folder_name"',
+ ''
);
}
@@ -107,6 +118,8 @@ class TransferOwnership extends Command {
$this->sourceUser = $sourceUserObject->getUID();
$this->destinationUser = $destinationUserObject->getUID();
+ $sourcePathOption = ltrim($input->getOption('path'), '/');
+ $this->sourcePath = rtrim($this->sourceUser . '/files/' . $sourcePathOption, '/');
// target user has to be ready
if (!\OC::$server->getEncryptionManager()->isReadyForUser($this->destinationUser)) {
@@ -121,6 +134,12 @@ class TransferOwnership extends Command {
Filesystem::initMountPoints($this->sourceUser);
Filesystem::initMountPoints($this->destinationUser);
+ $view = new View();
+ if (!$view->is_dir($this->sourcePath)) {
+ $output->writeln("<error>Unknown path provided: $sourcePathOption</error>");
+ return 1;
+ }
+
// analyse source folder
$this->analyse($output);
@@ -155,7 +174,8 @@ class TransferOwnership extends Command {
$progress = new ProgressBar($output);
$progress->start();
$self = $this;
- $this->walkFiles($view, "$this->sourceUser/files",
+
+ $this->walkFiles($view, $this->sourcePath,
function (FileInfo $fileInfo) use ($progress, $self) {
if ($fileInfo->getType() === FileInfo::TYPE_FOLDER) {
// only analyze into folders from main storage,
@@ -216,9 +236,18 @@ class TransferOwnership extends Command {
protected function transfer(OutputInterface $output) {
$view = new View();
$output->writeln("Transferring files to $this->finalTarget ...");
- $view->rename("$this->sourceUser/files", $this->finalTarget);
- // because the files folder is moved away we need to recreate it
- $view->mkdir("$this->sourceUser/files");
+
+ // This change will help user to transfer the folder specified using --path option.
+ // Else only the content inside folder is transferred which is not correct.
+ if($this->sourcePath !== "$this->sourceUser/files") {
+ $view->mkdir($this->finalTarget);
+ $this->finalTarget = $this->finalTarget . '/' . basename($this->sourcePath);
+ }
+ $view->rename($this->sourcePath, $this->finalTarget);
+ if (!is_dir("$this->sourceUser/files")) {
+ // because the files folder is moved away we need to recreate it
+ $view->mkdir("$this->sourceUser/files");
+ }
}
/**
diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js
index 0270b7a6957..976c0c00b89 100644
--- a/apps/files_external/js/settings.js
+++ b/apps/files_external/js/settings.js
@@ -719,6 +719,10 @@ MountConfigListView.prototype = _.extend({
self.deleteStorageConfig($(this).closest('tr'));
});
+ this.$el.on('click', 'td.save>img', function () {
+ self.saveStorageConfig($(this).closest('tr'));
+ });
+
this.$el.on('click', 'td.mountOptionsToggle>img', function() {
self._showMountOptionsDropdown($(this).closest('tr'));
});
@@ -737,13 +741,6 @@ MountConfigListView.prototype = _.extend({
highlightInput($target);
var $tr = $target.closest('tr');
this.updateStatus($tr, null);
-
- var timer = $tr.data('save-timer');
- clearTimeout(timer);
- timer = setTimeout(function() {
- self.saveStorageConfig($tr, null, timer);
- }, 2000);
- $tr.data('save-timer', timer);
},
_onSelectBackend: function(event) {
@@ -813,8 +810,7 @@ MountConfigListView.prototype = _.extend({
$tr.data('storageConfig', storageConfig);
$tr.show();
- $tr.find('td').last().attr('class', 'remove');
- $tr.find('td.mountOptionsToggle').removeClass('hidden');
+ $tr.find('td.mountOptionsToggle, td.save, td.remove').removeClass('hidden');
$tr.find('td').last().removeAttr('style');
$tr.removeAttr('id');
$tr.find('select#selectBackend');
diff --git a/apps/files_external/lib/Lib/Storage/OwnCloud.php b/apps/files_external/lib/Lib/Storage/OwnCloud.php
index 4a10844a770..427b55a4a54 100644
--- a/apps/files_external/lib/Lib/Storage/OwnCloud.php
+++ b/apps/files_external/lib/Lib/Storage/OwnCloud.php
@@ -23,6 +23,7 @@
*/
namespace OCA\Files_External\Lib\Storage;
+use Sabre\DAV\Client;
/**
* ownCloud backend for external storage based on DAV backend.
@@ -69,6 +70,7 @@ class OwnCloud extends \OC\Files\Storage\DAV{
$params['host'] = $host;
$params['root'] = $contextPath . self::OC_URL_SUFFIX . $root;
+ $params['authType'] = Client::AUTH_BASIC;
parent::__construct($params);
}
diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php
index 53d2412425c..9d8c179dd32 100644
--- a/apps/files_external/templates/settings.php
+++ b/apps/files_external/templates/settings.php
@@ -150,13 +150,19 @@
/>
<input type="hidden" class="mountOptions" value="" />
</td>
- <td class="hidden">
+ <td class="remove hidden">
<img class="svg"
alt="<?php p($l->t('Delete')); ?>"
title="<?php p($l->t('Delete')); ?>"
src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"
/>
</td>
+ <td class="save hidden">
+ <img alt="<?php p($l->t('Save')); ?>"
+ title="<?php p($l->t('Save')); ?>"
+ src="<?php print_unescaped(image_path('core', 'actions/checkmark.svg')); ?>"
+ />
+ </td>
</tr>
</tbody>
</table>
diff --git a/apps/files_external/tests/js/settingsSpec.js b/apps/files_external/tests/js/settingsSpec.js
index 8f01c16b38c..2639f634b26 100644
--- a/apps/files_external/tests/js/settingsSpec.js
+++ b/apps/files_external/tests/js/settingsSpec.js
@@ -46,7 +46,8 @@ describe('OCA.External.Settings tests', function() {
'<input type="hidden" class="applicableUsers">' +
'</td>' +
'<td class="mountOptionsToggle"><input type="hidden" class="mountOptions"/><img class="svg action"/></td>' +
- '<td><img alt="Delete" title="Delete" class="svg action"/></td>' +
+ '<td class="remove"><img alt="Delete" title="Delete" class="svg action"/></td>' +
+ '<td class="save"><img alt="Save" title="Save" class="svg action"/></td>' +
'</tr>' +
'</tbody>' +
'</table>'
@@ -195,7 +196,7 @@ describe('OCA.External.Settings tests', function() {
$tr = view.$el.find('tr:first');
selectBackend('\\OC\\TestBackend');
});
- it('saves storage after editing config', function() {
+ it('saves storage after clicking the save button', function() {
var $field1 = $tr.find('input[data-parameter=field1]');
expect($field1.length).toEqual(1);
$field1.val('test');
@@ -205,7 +206,8 @@ describe('OCA.External.Settings tests', function() {
expect($mountOptionsField.length).toEqual(1);
$mountOptionsField.val(JSON.stringify({previews:true}));
- clock.tick(4000);
+ var $saveButton = $tr.find('td.save img');
+ $saveButton.click();
expect(fakeServer.requests.length).toEqual(1);
var request = fakeServer.requests[0];
@@ -242,11 +244,6 @@ describe('OCA.External.Settings tests', function() {
// but after closing the dropdown
expect(fakeServer.requests.length).toEqual(1);
});
- // TODO: tests with "applicableUsers" and "applicableGroups"
- // TODO: test with missing mount point value
- // TODO: test with personal mounts (no applicable fields)
- // TODO: test save triggers: paste, keyup, checkbox
- // TODO: test "custom" field with addScript
// TODO: status indicator
});
describe('validate storage configuration', function() {
diff --git a/apps/files_sharing/lib/SharedStorage.php b/apps/files_sharing/lib/SharedStorage.php
index 888cbfda143..ddbc9b8a898 100644
--- a/apps/files_sharing/lib/SharedStorage.php
+++ b/apps/files_sharing/lib/SharedStorage.php
@@ -31,16 +31,16 @@
namespace OCA\Files_Sharing;
-use OC\Files\Filesystem;
use OC\Files\Cache\FailedCache;
+use OC\Files\Filesystem;
use OC\Files\Storage\Wrapper\PermissionsMask;
-use OCA\Files_Sharing\ISharedStorage;
use OC\Files\Storage\FailedStorage;
use OCP\Constants;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorage;
use OCP\Lock\ILockingProvider;
+use OC\User\NoUserException;
/**
* Convert target path to source path and pass the function call to the correct storage provider
@@ -99,6 +99,7 @@ class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedSto
private function getSourceRootInfo() {
if (is_null($this->sourceRootInfo)) {
if (is_null($this->superShare->getNodeCacheEntry())) {
+ $this->init();
$this->sourceRootInfo = $this->nonMaskedStorage->getCache()->get($this->rootPath);
} else {
$this->sourceRootInfo = $this->superShare->getNodeCacheEntry();
@@ -121,13 +122,25 @@ class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedSto
'mask' => $this->superShare->getPermissions()
]);
} catch (NotFoundException $e) {
+ // original file not accessible or deleted, set FailedStorage
+ $this->storage = new FailedStorage(['exception' => $e]);
+ $this->cache = new FailedCache();
+ $this->rootPath = '';
+ } catch (NoUserException $e) {
+ // sharer user deleted, set FailedStorage
$this->storage = new FailedStorage(['exception' => $e]);
+ $this->cache = new FailedCache();
$this->rootPath = '';
} catch (\Exception $e) {
$this->storage = new FailedStorage(['exception' => $e]);
+ $this->cache = new FailedCache();
$this->rootPath = '';
$this->logger->logException($e);
}
+
+ if (!$this->nonMaskedStorage) {
+ $this->nonMaskedStorage = $this->storage;
+ }
}
/**
@@ -344,6 +357,9 @@ class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedSto
if (!$storage) {
$storage = $this;
}
+ if ($this->storage instanceof FailedStorage) {
+ return new FailedCache();
+ }
$this->cache = new \OCA\Files_Sharing\Cache($storage, $this->getSourceRootInfo(), $this->superShare);
return $this->cache;
}
diff --git a/apps/files_sharing/tests/SharedStorageTest.php b/apps/files_sharing/tests/SharedStorageTest.php
index eaa138b0f70..7d007cb6414 100644
--- a/apps/files_sharing/tests/SharedStorageTest.php
+++ b/apps/files_sharing/tests/SharedStorageTest.php
@@ -28,6 +28,11 @@
namespace OCA\Files_Sharing\Tests;
+use OCA\Files_Sharing\SharedStorage;
+use OCP\Share\IShare;
+use OC\Files\View;
+use OCP\Files\NotFoundException;
+
/**
* Class SharedStorageTest
*
@@ -559,4 +564,37 @@ class SharedStorageTest extends TestCase {
$this->shareManager->deleteShare($share);
}
+
+ public function testInitWithNonExistingUser() {
+ $share = $this->createMock(IShare::class);
+ $share->method('getShareOwner')->willReturn('unexist');
+ $ownerView = $this->createMock(View::class);
+ $storage = new SharedStorage([
+ 'ownerView' => $ownerView,
+ 'superShare' => $share,
+ 'groupedShares' => [$share],
+ 'user' => 'user1',
+ ]);
+
+ // trigger init
+ $this->assertInstanceOf(\OC\Files\Storage\FailedStorage::class, $storage->getSourceStorage());
+ $this->assertInstanceOf(\OC\Files\Cache\FailedCache::class, $storage->getCache());
+ }
+
+ public function testInitWithNotFoundSource() {
+ $share = $this->createMock(IShare::class);
+ $share->method('getShareOwner')->willReturn(self::TEST_FILES_SHARING_API_USER1);
+ $ownerView = $this->createMock(View::class);
+ $ownerView->method('getPath')->will($this->throwException(new NotFoundException()));
+ $storage = new SharedStorage([
+ 'ownerView' => $ownerView,
+ 'superShare' => $share,
+ 'groupedShares' => [$share],
+ 'user' => 'user1',
+ ]);
+
+ // trigger init
+ $this->assertInstanceOf(\OC\Files\Storage\FailedStorage::class, $storage->getSourceStorage());
+ $this->assertInstanceOf(\OC\Files\Cache\FailedCache::class, $storage->getCache());
+ }
}
diff --git a/apps/files_trashbin/lib/Helper.php b/apps/files_trashbin/lib/Helper.php
index 9c312443164..a309d533e54 100644
--- a/apps/files_trashbin/lib/Helper.php
+++ b/apps/files_trashbin/lib/Helper.php
@@ -72,8 +72,9 @@ class Helper {
$timestamp = substr(pathinfo($parts[0], PATHINFO_EXTENSION), 1);
}
$originalPath = '';
- if (isset($originalLocations[$id][$timestamp])) {
- $originalPath = $originalLocations[$id][$timestamp];
+ $originalName = substr($entryName, 0, -strlen($timestamp)-2);
+ if (isset($originalLocations[$originalName][$timestamp])) {
+ $originalPath = $originalLocations[$originalName][$timestamp];
if (substr($originalPath, -1) === '/') {
$originalPath = substr($originalPath, 0, -1);
}
@@ -90,7 +91,11 @@ class Helper {
'permissions' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE
);
if ($originalPath) {
- $i['extraData'] = $originalPath . '/' . $id;
+ if ($originalPath !== '.') {
+ $i['extraData'] = $originalPath . '/' . $originalName;
+ } else {
+ $i['extraData'] = $originalName;
+ }
}
$result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i, $mount);
}
diff --git a/apps/files_trashbin/lib/Trashbin.php b/apps/files_trashbin/lib/Trashbin.php
index 2e66a6b96e1..78f0c9212f9 100644
--- a/apps/files_trashbin/lib/Trashbin.php
+++ b/apps/files_trashbin/lib/Trashbin.php
@@ -256,7 +256,11 @@ class Trashbin {
}
if ($sourceStorage->file_exists($sourceInternalPath)) { // failed to delete the original file, abort
- $sourceStorage->unlink($sourceInternalPath);
+ if ($sourceStorage->is_dir($sourceInternalPath)) {
+ $sourceStorage->rmdir($sourceInternalPath);
+ } else {
+ $sourceStorage->unlink($sourceInternalPath);
+ }
return false;
}