diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/encryption/lib/Controller/StatusController.php | 2 | ||||
-rw-r--r-- | apps/encryption/templates/settings-personal.php | 2 | ||||
-rw-r--r-- | apps/files/appinfo/info.xml | 3 | ||||
-rw-r--r-- | apps/files/lib/Command/ScanAppData.php | 284 | ||||
-rw-r--r-- | apps/files/lib/Command/TransferOwnership.php | 37 | ||||
-rw-r--r-- | apps/files_external/js/settings.js | 14 | ||||
-rw-r--r-- | apps/files_external/lib/Lib/Storage/OwnCloud.php | 2 | ||||
-rw-r--r-- | apps/files_external/templates/settings.php | 8 | ||||
-rw-r--r-- | apps/files_external/tests/js/settingsSpec.js | 13 | ||||
-rw-r--r-- | apps/files_sharing/lib/SharedStorage.php | 20 | ||||
-rw-r--r-- | apps/files_sharing/tests/SharedStorageTest.php | 38 | ||||
-rw-r--r-- | apps/files_trashbin/lib/Helper.php | 11 | ||||
-rw-r--r-- | apps/files_trashbin/lib/Trashbin.php | 6 |
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; } |