From bbdd9249dccfa19a40759ce1fe6095eed83328d2 Mon Sep 17 00:00:00 2001 From: provokateurin Date: Wed, 18 Sep 2024 18:03:48 +0200 Subject: [PATCH] chore(deps): Update nextcloud/coding-standard to v1.3.0 Signed-off-by: provokateurin --- lib/ACL/ACLCacheWrapper.php | 8 ++ lib/ACL/ACLManager.php | 5 + lib/ACL/ACLStorageWrapper.php | 18 +++ lib/ACL/Rule.php | 2 + lib/ACL/RuleManager.php | 9 +- lib/AppInfo/Application.php | 3 + lib/AppInfo/Capabilities.php | 1 + lib/AuthorizedAdminSettingMiddleware.php | 3 +- lib/BackgroundJob/ExpireGroupTrash.php | 3 +- lib/CacheListener.php | 4 +- lib/Command/ACL.php | 11 +- lib/Command/Create.php | 1 + lib/Command/Delete.php | 2 + lib/Command/ExpireGroup/ExpireGroupTrash.php | 3 +- .../ExpireGroup/ExpireGroupVersions.php | 3 +- .../ExpireGroup/ExpireGroupVersionsTrash.php | 2 +- lib/Command/FolderCommand.php | 3 + lib/Command/Group.php | 7 + lib/Command/ListCommand.php | 8 ++ lib/Command/Quota.php | 3 + lib/Command/Rename.php | 2 + lib/Command/Scan.php | 3 + lib/Command/Trashbin/Cleanup.php | 3 + lib/Controller/FolderController.php | 28 ++++ lib/DAV/ACLPlugin.php | 9 ++ lib/DAV/GroupFoldersHome.php | 2 + lib/DAV/RootCollection.php | 1 + lib/Folder/FolderManager.php | 14 +- lib/Listeners/NodeRenamedListener.php | 1 + .../Version1000000Date20210216085047.php | 1 + .../Version102020Date20180806161449.php | 1 + lib/Mount/CacheRootPermissionsMask.php | 1 + lib/Mount/GroupFolderEncryptionJail.php | 2 + lib/Mount/GroupFolderStorage.php | 5 + lib/Mount/MountProvider.php | 9 +- lib/Mount/RootEntryCache.php | 2 + lib/Mount/RootPermissionsMask.php | 3 + lib/Service/DelegationService.php | 4 +- lib/Service/FoldersFilter.php | 1 + lib/Settings/Admin.php | 2 +- lib/Settings/Section.php | 2 +- lib/Trash/GroupTrashItem.php | 2 + lib/Trash/TrashBackend.php | 32 ++++- lib/Trash/TrashManager.php | 3 + lib/Versions/ExpireManager.php | 3 + lib/Versions/GroupVersionsExpireManager.php | 3 +- lib/Versions/VersionsBackend.php | 9 ++ tests/ACL/ACLManagerTest.php | 1 + tests/ACL/ACLScannerTest.php | 1 + tests/ACL/RuleManagerTest.php | 1 + tests/Folder/FolderManagerTest.php | 3 + vendor-bin/cs-fixer/composer.json | 2 +- vendor-bin/cs-fixer/composer.lock | 129 +++++++++++++++++- 53 files changed, 360 insertions(+), 24 deletions(-) diff --git a/lib/ACL/ACLCacheWrapper.php b/lib/ACL/ACLCacheWrapper.php index 7c0fb3182..67fd4e67a 100644 --- a/lib/ACL/ACLCacheWrapper.php +++ b/lib/ACL/ACLCacheWrapper.php @@ -31,7 +31,9 @@ private function getACLPermissionsForPath(string $path, array $rules = []) { } else { $minPermissions = Constants::PERMISSION_READ; } + $canRead = ($permissions & $minPermissions) === $minPermissions; + return $canRead ? $permissions : 0; } @@ -49,12 +51,14 @@ protected function formatCacheEntry($entry, array $rules = []) { return false; } } + return $entry; } public function getFolderContentsById($fileId) { $results = $this->getCache()->getFolderContentsById($fileId); $rules = $this->preloadEntries($results); + return array_filter(array_map(function ($entry) use ($rules) { return $this->formatCacheEntry($entry, $rules); }, $results)); @@ -63,18 +67,21 @@ public function getFolderContentsById($fileId) { public function search($pattern) { $results = $this->getCache()->search($pattern); $this->preloadEntries($results); + return array_filter(array_map($this->formatCacheEntry(...), $results)); } public function searchByMime($mimetype) { $results = $this->getCache()->searchByMime($mimetype); $this->preloadEntries($results); + return array_filter(array_map($this->formatCacheEntry(...), $results)); } public function searchQuery(ISearchQuery $query) { $results = $this->getCache()->searchQuery($query); $this->preloadEntries($results); + return array_filter(array_map($this->formatCacheEntry(...), $results)); } @@ -86,6 +93,7 @@ private function preloadEntries(array $entries): array { $paths = array_map(function (ICacheEntry $entry) { return $entry->getPath(); }, $entries); + return $this->aclManager->getRelevantRulesForPath($paths, false); } } diff --git a/lib/ACL/ACLManager.php b/lib/ACL/ACLManager.php index 9de0b626c..ebecf693b 100644 --- a/lib/ACL/ACLManager.php +++ b/lib/ACL/ACLManager.php @@ -69,6 +69,7 @@ private function getRules(array $paths, bool $cache = true): array { if ($cache) { $this->ruleCache->set($path, $rulesForPath); } + $rules[$path] = $rulesForPath; } } @@ -98,6 +99,7 @@ private function getRelevantPaths(string $path): array { $rootTrashedItemDate = (int)substr($rootTrashedItemName, $separatorPos + 2); $rootTrashedItemName = substr($rootTrashedItemName, 0, $separatorPos); } + while ($path !== '') { $paths[] = $path; $path = dirname($path); @@ -133,6 +135,7 @@ public function getRelevantRulesForPath(array $paths, bool $cache = true): array foreach ($paths as $path) { $allPaths = array_unique(array_merge($allPaths, $this->getRelevantPaths($path))); } + return $this->getRules($allPaths, $cache); } @@ -152,6 +155,7 @@ public function getPermissionsForPathFromRules(string $path, array $rules): int $path = ltrim($path, '/'); $relevantPaths = $this->getRelevantPaths($path); $rules = array_intersect_key($rules, array_flip($relevantPaths)); + return $this->calculatePermissionsForPath($rules); } @@ -194,6 +198,7 @@ private function calculatePermissionsForPath(array $rules): int { } $mergedRule = Rule::mergeRules($rulesPerMapping); + return $mergedRule->applyPermissions(Constants::PERMISSION_ALL); } else { // first combine all rules with the same path, then apply them on top of the current permissions diff --git a/lib/ACL/ACLStorageWrapper.php b/lib/ACL/ACLStorageWrapper.php index b80948a85..83845e5a8 100644 --- a/lib/ACL/ACLStorageWrapper.php +++ b/lib/ACL/ACLStorageWrapper.php @@ -33,6 +33,7 @@ private function getACLPermissionsForPath(string $path) { } else { $canRead = $permissions & Constants::PERMISSION_READ; } + return $canRead ? $permissions : 0; } @@ -74,15 +75,18 @@ public function rename($source, $target) { return $this->checkPermissions($target, Constants::PERMISSION_CREATE) && parent::rename($source, $target); } } + $permissions = $this->file_exists($target) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE; $sourceParent = dirname($source); if ($sourceParent === '.') { $sourceParent = ''; } + $targetParent = dirname($target); if ($targetParent === '.') { $targetParent = ''; } + return ($sourceParent === $targetParent || $this->checkPermissions($sourceParent, Constants::PERMISSION_DELETE)) && $this->checkPermissions($source, Constants::PERMISSION_UPDATE & Constants::PERMISSION_READ) && @@ -158,6 +162,7 @@ public function fopen($path, $mode) { } else { $permissions = $this->file_exists($path) ? Constants::PERMISSION_UPDATE : Constants::PERMISSION_CREATE; } + return $this->checkPermissions($path, $permissions) ? parent::fopen($path, $mode) : false; } @@ -177,7 +182,9 @@ public function getCache($path = '', $storage = null) { if (!$storage) { $storage = $this; } + $sourceCache = parent::getCache($path, $storage); + return new ACLCacheWrapper($sourceCache, $this->aclManager, $this->inShare); } @@ -188,6 +195,7 @@ public function getMetaData($path) { $data['scan_permissions'] = isset($data['scan_permissions']) ? $data['scan_permissions'] : $data['permissions']; $data['permissions'] &= $this->getACLPermissionsForPath($path); } + return $data; } @@ -195,6 +203,7 @@ public function getScanner($path = '', $storage = null) { if (!$storage) { $storage = $this->storage; } + return parent::getScanner($path, $storage); } @@ -212,6 +221,7 @@ public function stat($path) { if (!$this->checkPermissions($path, Constants::PERMISSION_READ)) { return false; } + return parent::stat($path); } @@ -219,6 +229,7 @@ public function filetype($path) { if (!$this->checkPermissions($path, Constants::PERMISSION_READ)) { return false; } + return parent::filetype($path); } @@ -226,6 +237,7 @@ public function filesize($path): false|int|float { if (!$this->checkPermissions($path, Constants::PERMISSION_READ)) { return false; } + return parent::filesize($path); } @@ -238,6 +250,7 @@ public function filemtime($path) { if (!$this->checkPermissions($path, Constants::PERMISSION_READ)) { return false; } + return parent::filemtime($path); } @@ -245,6 +258,7 @@ public function file_get_contents($path) { if (!$this->checkPermissions($path, Constants::PERMISSION_READ)) { return false; } + return parent::file_get_contents($path); } @@ -252,6 +266,7 @@ public function getMimeType($path) { if (!$this->checkPermissions($path, Constants::PERMISSION_READ)) { return false; } + return parent::getMimeType($path); } @@ -259,6 +274,7 @@ public function hash($type, $path, $raw = false) { if (!$this->checkPermissions($path, Constants::PERMISSION_READ)) { return false; } + return parent::hash($type, $path, $raw); } @@ -266,6 +282,7 @@ public function getETag($path) { if (!$this->checkPermissions($path, Constants::PERMISSION_READ)) { return false; } + return parent::getETag($path); } @@ -273,6 +290,7 @@ public function getDirectDownload($path) { if (!$this->checkPermissions($path, Constants::PERMISSION_READ)) { return false; } + return parent::getDirectDownload($path); } diff --git a/lib/ACL/Rule.php b/lib/ACL/Rule.php index 068fd409e..2a9828bb2 100644 --- a/lib/ACL/Rule.php +++ b/lib/ACL/Rule.php @@ -81,6 +81,7 @@ public function applyPermissions(int $permissions): int { // a bitmask that has all allow bits set to 1 and all inherit and deny bits to 0 $allowMask = $this->mask & $this->permissions; + return $permissions | $allowMask; } @@ -185,6 +186,7 @@ public static function formatRulePermissions(int $mask, int $permissions): strin $result[] = $type . $name; } } + return implode(', ', $result); } diff --git a/lib/ACL/RuleManager.php b/lib/ACL/RuleManager.php index f8e53dba4..f442373e8 100644 --- a/lib/ACL/RuleManager.php +++ b/lib/ACL/RuleManager.php @@ -67,11 +67,13 @@ public function getRulesForFilesById(IUser $user, array $fileIds): array { if (!isset($result[$row['fileid']])) { $result[$row['fileid']] = []; } + $rule = $this->createRule($row); if ($rule) { $result[$row['fileid']][] = $rule; } } + return $result; } @@ -106,11 +108,11 @@ public function getRulesForFilesByPath(IUser $user, int $storageId, array $fileP $rows = array_merge($rows, $query->executeQuery()->fetchAll()); } - $result = []; foreach ($filePaths as $path) { $result[$path] = []; } + return $this->rulesByPath($rows, $result); } @@ -155,6 +157,7 @@ public function getRulesForFilesByParent(IUser $user, int $storageId, string $pa if (!isset($result[$row['path']])) { $result[$row['path']] = []; } + if ($row['mapping_type'] !== null) { $rule = $this->createRule($row); if ($rule) { @@ -162,6 +165,7 @@ public function getRulesForFilesByParent(IUser $user, int $storageId, string $pa } } } + return $result; } @@ -201,11 +205,13 @@ private function rulesByPath(array $rows, array $result = []): array { if (!isset($result[$row['path']])) { $result[$row['path']] = []; } + $rule = $this->createRule($row); if ($rule) { $result[$row['path']][] = $rule; } } + return $result; } @@ -267,6 +273,7 @@ private function hasRule(IUserMapping $mapping, int $fileId): bool { ->where($query->expr()->eq('fileid', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))) ->andWhere($query->expr()->eq('mapping_type', $query->createNamedParameter($mapping->getType()))) ->andWhere($query->expr()->eq('mapping_id', $query->createNamedParameter($mapping->getId()))); + return (bool)$query->executeQuery()->fetch(); } diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 89e6d64bc..27d6a7a50 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -85,6 +85,7 @@ public function register(IRegistrationContext $context): void { $context->registerService('GroupAppFolder', function (ContainerInterface $c): Folder { /** @var IRootFolder $rootFolder */ $rootFolder = $c->get(IRootFolder::class); + return new LazyFolder($rootFolder, function () use ($rootFolder) { try { return $rootFolder->get('__groupfolders'); @@ -136,6 +137,7 @@ public function register(IRegistrationContext $context): void { if ($hasVersionApp) { $trashBackend->setVersionsBackend($c->get(VersionsBackend::class)); } + return $trashBackend; }); @@ -214,6 +216,7 @@ public function register(IRegistrationContext $context): void { $rootFolderProvider = function () use ($c): \OCP\Files\IRootFolder { return $c->get(IRootFolder::class); }; + return new ACLManagerFactory( $c->get(RuleManager::class), $c->get(TrashManager::class), diff --git a/lib/AppInfo/Capabilities.php b/lib/AppInfo/Capabilities.php index 3c1b942f4..fdf6b428b 100644 --- a/lib/AppInfo/Capabilities.php +++ b/lib/AppInfo/Capabilities.php @@ -29,6 +29,7 @@ public function getCapabilities(): array { if (!$user) { return []; } + return [ Application::APP_ID => [ 'appVersion' => $this->appManager->getAppVersion(Application::APP_ID), diff --git a/lib/AuthorizedAdminSettingMiddleware.php b/lib/AuthorizedAdminSettingMiddleware.php index abff09e6a..b5c2d54a5 100644 --- a/lib/AuthorizedAdminSettingMiddleware.php +++ b/lib/AuthorizedAdminSettingMiddleware.php @@ -24,7 +24,7 @@ class AuthorizedAdminSettingMiddleware extends Middleware { public function __construct( DelegationService $delegatedService, IControllerMethodReflector $reflector, - IRequest $request + IRequest $request, ) { $this->delegatedService = $delegatedService; $this->reflector = $reflector; @@ -63,6 +63,7 @@ public function afterException($controller, $methodName, \Exception $exception): $response = new TemplateResponse('core', '403', ['message' => $exception->getMessage()], 'guest'); $response->setStatus((int)$exception->getCode()); } + return $response; } } diff --git a/lib/BackgroundJob/ExpireGroupTrash.php b/lib/BackgroundJob/ExpireGroupTrash.php index 433f3fd60..1532f4f69 100644 --- a/lib/BackgroundJob/ExpireGroupTrash.php +++ b/lib/BackgroundJob/ExpireGroupTrash.php @@ -23,7 +23,7 @@ public function __construct( TrashBackend $trashBackend, Expiration $expiration, IConfig $config, - ITimeFactory $timeFactory + ITimeFactory $timeFactory, ) { parent::__construct($timeFactory); // Run once per hour @@ -39,6 +39,7 @@ protected function run($argument) { if ($backgroundJob === 'no') { return; } + $this->trashBackend->expire($this->expiration); } } diff --git a/lib/CacheListener.php b/lib/CacheListener.php index 4c88a2d5f..c35136a3e 100644 --- a/lib/CacheListener.php +++ b/lib/CacheListener.php @@ -14,7 +14,9 @@ use OCP\Files\Cache\ICacheEvent; class CacheListener { - public function __construct(private IEventDispatcher $eventDispatcher) { + public function __construct( + private IEventDispatcher $eventDispatcher, + ) { } public function listen(): void { diff --git a/lib/Command/ACL.php b/lib/Command/ACL.php index a36b23545..567e4f034 100644 --- a/lib/Command/ACL.php +++ b/lib/Command/ACL.php @@ -34,7 +34,7 @@ public function __construct( RuleManager $ruleManager, MountProvider $mountProvider, ACLManagerFactory $aclManagerFactory, - IUserManager $userManager + IUserManager $userManager, ) { parent::__construct($folderManager, $rootFolder, $mountProvider); $this->ruleManager = $ruleManager; @@ -64,6 +64,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { if ($folder === null) { return -1; } + if ($input->getOption('enable')) { $this->folderManager->setFolderACL($folder['id'], true); } elseif ($input->getOption('disable')) { @@ -76,12 +77,14 @@ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('User not found: ' . $mappingId . ''); return -1; } + $jailPath = $this->mountProvider->getJailPath((int)$folder['id']); $path = $input->getArgument('path'); $aclManager = $this->aclManagerFactory->getACLManager($user); $permissions = $aclManager->getACLPermissionsForPath($jailPath . rtrim('/' . $path, '/')); $permissionString = Rule::formatRulePermissions(Constants::PERMISSION_ALL, $permissions); $output->writeln($permissionString); + return 0; } else { $output->writeln('--user and options needs to be set for permissions testing'); @@ -146,13 +149,16 @@ protected function execute(InputInterface $input, OutputInterface $output) { 0, 0 )); + return 0; } + foreach ($permissionStrings as $permission) { if ($permission[0] !== '+' && $permission[0] !== '-') { $output->writeln('incorrect format for permissions "' . $permission . '"'); return -3; } + $name = substr($permission, 1); if (!isset(Rule::PERMISSIONS_MAP[$name])) { $output->writeln('incorrect format for permissions2 "' . $permission . '"'); @@ -169,6 +175,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { $permissions )); } + return 0; } @@ -203,6 +210,7 @@ private function printPermissions(InputInterface $input, OutputInterface $output return $rule->formatPermissions(); }, $rulesForPath); $formattedPath = substr($path, $jailPathLength); + return [ 'path' => $formattedPath ?: '/', 'mappings' => implode("\n", $mappings), @@ -232,6 +240,7 @@ private function parsePermissions(array $permissions): array { $result |= $permissionValue; } } + return [$mask, $result]; } } diff --git a/lib/Command/Create.php b/lib/Command/Create.php index 414c93a46..3ce3bd897 100644 --- a/lib/Command/Create.php +++ b/lib/Command/Create.php @@ -33,6 +33,7 @@ protected function configure() { protected function execute(InputInterface $input, OutputInterface $output) { $id = $this->folderManager->createFolder($input->getArgument('name')); $output->writeln((string)$id); + return 0; } } diff --git a/lib/Command/Delete.php b/lib/Command/Delete.php index 2a9026bde..35031d00c 100644 --- a/lib/Command/Delete.php +++ b/lib/Command/Delete.php @@ -29,6 +29,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { if ($folder === null) { return -1; } + $helper = $this->getHelper('question'); $question = new ConfirmationQuestion('Are you sure you want to delete the group folder ' . $folder['mount_point'] . ' and all files within, this cannot be undone (y/N).', false); if ($input->getOption('force') || $helper->ask($input, $output, $question)) { @@ -36,6 +37,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { $this->folderManager->removeFolder($folder['id']); $folderMount->delete(); } + return 0; } } diff --git a/lib/Command/ExpireGroup/ExpireGroupTrash.php b/lib/Command/ExpireGroup/ExpireGroupTrash.php index cc1c6dfb3..f77a64373 100644 --- a/lib/Command/ExpireGroup/ExpireGroupTrash.php +++ b/lib/Command/ExpireGroup/ExpireGroupTrash.php @@ -19,7 +19,7 @@ class ExpireGroupTrash extends ExpireGroupBase { public function __construct( TrashBackend $trashBackend, - Expiration $expiration + Expiration $expiration, ) { parent::__construct(); $this->trashBackend = $trashBackend; @@ -36,6 +36,7 @@ protected function configure(): void { protected function execute(InputInterface $input, OutputInterface $output): int { [$count, $size] = $this->trashBackend->expire($this->expiration); $output->writeln("Removed $count expired trashbin items"); + return 0; } } diff --git a/lib/Command/ExpireGroup/ExpireGroupVersions.php b/lib/Command/ExpireGroup/ExpireGroupVersions.php index e8404c7ca..012920a90 100644 --- a/lib/Command/ExpireGroup/ExpireGroupVersions.php +++ b/lib/Command/ExpireGroup/ExpireGroupVersions.php @@ -20,7 +20,7 @@ class ExpireGroupVersions extends ExpireGroupBase { protected GroupVersionsExpireManager $expireManager; public function __construct( - GroupVersionsExpireManager $expireManager + GroupVersionsExpireManager $expireManager, ) { parent::__construct(); $this->expireManager = $expireManager; @@ -48,6 +48,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int }); $this->expireManager->expireAll(); + return 0; } } diff --git a/lib/Command/ExpireGroup/ExpireGroupVersionsTrash.php b/lib/Command/ExpireGroup/ExpireGroupVersionsTrash.php index 776dc27f0..9ac17b789 100644 --- a/lib/Command/ExpireGroup/ExpireGroupVersionsTrash.php +++ b/lib/Command/ExpireGroup/ExpireGroupVersionsTrash.php @@ -21,7 +21,7 @@ class ExpireGroupVersionsTrash extends ExpireGroupVersions { public function __construct( GroupVersionsExpireManager $expireManager, TrashBackend $trashBackend, - Expiration $expiration + Expiration $expiration, ) { parent::__construct($expireManager); $this->trashBackend = $trashBackend; diff --git a/lib/Command/FolderCommand.php b/lib/Command/FolderCommand.php index c3158445b..c402041fe 100644 --- a/lib/Command/FolderCommand.php +++ b/lib/Command/FolderCommand.php @@ -38,13 +38,16 @@ protected function getFolder(InputInterface $input, OutputInterface $output): ?a if ((string)$folderId !== $input->getArgument('folder_id')) { // Protect against removing folderId === 0 when typing a string (e.g. folder name instead of folder id) $output->writeln('Folder id argument is not an integer. Got ' . $input->getArgument('folder_id') . ''); + return null; } + $folder = $this->folderManager->getFolder($folderId, $this->rootFolder->getMountPoint()->getNumericStorageId()); if ($folder === null) { $output->writeln('Folder not found: ' . $folderId . ''); return null; } + return $folder; } } diff --git a/lib/Command/Group.php b/lib/Command/Group.php index f8f5198ae..2fe06b46d 100644 --- a/lib/Command/Group.php +++ b/lib/Command/Group.php @@ -62,13 +62,19 @@ protected function execute(InputInterface $input, OutputInterface $output) { if (!isset($folder['groups'][$groupString])) { $this->folderManager->addApplicableGroup($folder['id'], $groupString); } + $this->folderManager->setGroupPermissions($folder['id'], $groupString, $permissions); + return 0; } + $output->writeln('Unable to parse permissions input: ' . implode(' ', $permissionsString) . ''); + return -1; } + $output->writeln('group/team not found: ' . $groupString . ''); + return -1; } @@ -82,6 +88,7 @@ private function getNewPermissions(array $input): int { return 0; } } + return $permissions; } } diff --git a/lib/Command/ListCommand.php b/lib/Command/ListCommand.php index cbe083292..6825a4d27 100644 --- a/lib/Command/ListCommand.php +++ b/lib/Command/ListCommand.php @@ -64,10 +64,12 @@ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln("user $userId not found"); return 1; } + $folders = $this->folderManager->getAllFoldersForUserWithSize($rootStorageId, $user); } else { $folders = $this->folderManager->getAllFoldersWithSize($rootStorageId); } + usort($folders, function ($a, $b) { return $a['id'] - $b['id']; }); @@ -79,6 +81,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { } else { $output->writeln('No folders configured'); } + return 0; } @@ -89,6 +92,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { return $group['permissions']; }, $folder['groups']); } + $this->writeArrayInOutputFormat($input, $output, $folders); } else { $table = new Table($output); @@ -99,6 +103,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { $groupStrings = array_map(function (string $groupId, array $entry) use ($groupNames): string { [$permissions, $displayName] = [$entry['permissions'], $entry['displayName']]; $groupName = array_key_exists($groupId, $groupNames) && ($groupNames[$groupId] !== $groupId) ? $groupNames[$groupId] . ' (' . $groupId . ')' : $displayName; + return $groupName . ': ' . $this->permissionsToString($permissions); }, array_keys($folder['groups']), array_values($folder['groups'])); $folder['groups'] = implode("\n", $groupStrings); @@ -107,10 +112,12 @@ protected function execute(InputInterface $input, OutputInterface $output) { return $manage['id'] . ' (' . $manage['type'] . ')'; }, $folder['manage']); $folder['manage'] = implode("\n", $manageStrings); + return $folder; }, $folders)); $table->render(); } + return 0; } @@ -118,6 +125,7 @@ private function permissionsToString(int $permissions): string { if ($permissions === 0) { return 'none'; } + return implode(', ', array_filter(self::PERMISSION_NAMES, function (int $possiblePermission) use ($permissions) { return $possiblePermission & $permissions; }, ARRAY_FILTER_USE_KEY)); diff --git a/lib/Command/Quota.php b/lib/Command/Quota.php index 9dcffa3a9..ccef5db2b 100644 --- a/lib/Command/Quota.php +++ b/lib/Command/Quota.php @@ -28,13 +28,16 @@ protected function execute(InputInterface $input, OutputInterface $output) { if ($folder === null) { return -1; } + $quotaString = strtolower($input->getArgument('quota')); $quota = ($quotaString === 'unlimited') ? FileInfo::SPACE_UNLIMITED : \OCP\Util::computerFileSize($quotaString); if ($quota) { $this->folderManager->setFolderQuota($folder['id'], (int)$quota); return 0; } + $output->writeln('Unable to parse quota input: ' . $quotaString . ''); + return -1; } } diff --git a/lib/Command/Rename.php b/lib/Command/Rename.php index a2e10a5df..a14560c28 100644 --- a/lib/Command/Rename.php +++ b/lib/Command/Rename.php @@ -27,7 +27,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($folder === null) { return -1; } + $this->folderManager->renameFolder($folder['id'], $input->getArgument('name')); + return 0; } } diff --git a/lib/Command/Scan.php b/lib/Command/Scan.php index 9c17321bf..b97595172 100644 --- a/lib/Command/Scan.php +++ b/lib/Command/Scan.php @@ -66,6 +66,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { if ($folder === null) { return -1; } + $folders = [$folder['id'] => $folder]; } @@ -75,6 +76,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { } else { $inputPath = ''; } + $recursive = !$input->getOption('shallow'); $duration = 0; @@ -126,6 +128,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { ]; $this->showSummary($headers, $stats, $output, $duration); + return 0; } diff --git a/lib/Command/Trashbin/Cleanup.php b/lib/Command/Trashbin/Cleanup.php index 7abccee08..29cc8694d 100644 --- a/lib/Command/Trashbin/Cleanup.php +++ b/lib/Command/Trashbin/Cleanup.php @@ -44,6 +44,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln('files_trashbin is disabled: group folders trashbin is not available'); return -1; } + $helper = $this->getHelper('question'); $folders = $this->folderManager->getAllFolders(); @@ -58,11 +59,13 @@ protected function execute(InputInterface $input, OutputInterface $output) { } $this->trashBackend->cleanTrashFolder($folder['id']); + return 0; } } $output->writeln('Folder not found: ' . $folderId . ''); + return -1; } else { $question = new ConfirmationQuestion('Are you sure you want to empty the trashbin of your group folders, this can not be undone (y/N).', false); diff --git a/lib/Controller/FolderController.php b/lib/Controller/FolderController.php index fc9057a3b..b048ea700 100644 --- a/lib/Controller/FolderController.php +++ b/lib/Controller/FolderController.php @@ -86,6 +86,7 @@ private function formatFolder(array $folder): array { $folder['groups'] = array_map(function (array $group) { return $group['permissions']; }, $folder['groups']); + return $folder; } @@ -98,13 +99,16 @@ public function getFolders(bool $applicable = false): DataResponse { if ($isAdmin && !$applicable) { return new DataResponse($folders); } + if ($this->delegationService->hasOnlyApiAccess()) { $folders = $this->foldersFilter->getForApiUser($folders); } + if ($applicable || !$this->delegationService->hasApiAccess()) { $folders = array_map($this->filterNonAdminFolder(...), $folders); $folders = array_filter($folders); } + return new DataResponse($folders); } @@ -124,6 +128,7 @@ public function getFolder(int $id): DataResponse { return new DataResponse([], Http::STATUS_NOT_FOUND); } } + return new DataResponse($this->formatFolder($folder)); } @@ -132,10 +137,12 @@ private function checkFolderExists(int $id): ?DataResponse { if ($storageId === null) { return new DataResponse([], Http::STATUS_NOT_FOUND); } + $folder = $this->manager->getFolder($id, $storageId); if ($folder === null) { return new DataResponse([], Http::STATUS_NOT_FOUND); } + return null; } @@ -155,6 +162,7 @@ public function addFolder(string $mountpoint): DataResponse { if ($folder === null) { throw new OCSNotFoundException(); } + return new DataResponse($folder); } @@ -168,9 +176,11 @@ public function removeFolder(int $id): DataResponse { if ($response) { return $response; } + $folder = $this->mountProvider->getFolder($id); $folder->delete(); $this->manager->removeFolder($id); + return new DataResponse(['success' => true]); } @@ -194,7 +204,9 @@ public function addGroup(int $id, string $group): DataResponse { if ($response) { return $response; } + $this->manager->addApplicableGroup($id, $group); + return new DataResponse(['success' => true]); } @@ -208,7 +220,9 @@ public function removeGroup(int $id, string $group): DataResponse { if ($response) { return $response; } + $this->manager->removeApplicableGroup($id, $group); + return new DataResponse(['success' => true]); } @@ -222,7 +236,9 @@ public function setPermissions(int $id, string $group, int $permissions): DataRe if ($response) { return $response; } + $this->manager->setGroupPermissions($id, $group, $permissions); + return new DataResponse(['success' => true]); } @@ -237,7 +253,9 @@ public function setManageACL(int $id, string $mappingType, string $mappingId, bo if ($response) { return $response; } + $this->manager->setManageACL($id, $mappingType, $mappingId, $manageAcl); + return new DataResponse(['success' => true]); } @@ -251,7 +269,9 @@ public function setQuota(int $id, int $quota): DataResponse { if ($response) { return $response; } + $this->manager->setFolderQuota($id, $quota); + return new DataResponse(['success' => true]); } @@ -265,7 +285,9 @@ public function setACL(int $id, bool $acl): DataResponse { if ($response) { return $response; } + $this->manager->setFolderACL($id, $acl); + return new DataResponse(['success' => true]); } @@ -279,7 +301,9 @@ public function renameFolder(int $id, string $mountpoint): DataResponse { if ($response) { return $response; } + $this->manager->renameFolder($id, trim($mountpoint)); + return new DataResponse(['success' => true]); } @@ -301,7 +325,9 @@ private function buildOCSResponseXML(string $format, DataResponse $data): V1Resp // folder list $folderData = array_map($this->folderDataForXML(...), $folderData); } + $data->setData($folderData); + return new V1Response($data, $format); } @@ -317,6 +343,7 @@ private function folderDataForXML(array $data): array { '@type' => $group['type'], ]; } + return $data; } @@ -330,6 +357,7 @@ public function aclMappingSearch(int $id, ?int $fileId, string $search = ''): Da $groups = $this->manager->searchGroups($id, $search); $users = $this->manager->searchUsers($id, $search); } + return new DataResponse([ 'users' => $users, 'groups' => $groups, diff --git a/lib/DAV/ACLPlugin.php b/lib/DAV/ACLPlugin.php index aec03aedd..66c5beeda 100644 --- a/lib/DAV/ACLPlugin.php +++ b/lib/DAV/ACLPlugin.php @@ -49,6 +49,7 @@ private function isAdmin(string $path): bool { // Happens when sharing with a remote instance return false; } + return $this->folderManager->canManageACL($folderId, $this->user); } @@ -75,6 +76,7 @@ private function getParents(string $path): array { if ($path === '.' || $path === '/') { $path = ''; } + $paths[] = $path; } @@ -99,6 +101,7 @@ public function propFind(PropFind $propFind, INode $node): void { } else { $rules = $this->ruleManager->getRulesForFilesByPath($this->user, $mount->getNumericStorageId(), [$path]); } + return array_pop($rules); }); @@ -124,12 +127,15 @@ public function propFind(PropFind $propFind, INode $node): void { if (!isset($mappings[$mappingKey])) { $mappings[$mappingKey] = $rule->getUserMapping(); } + if (!isset($inheritedPermissionsByMapping[$mappingKey])) { $inheritedPermissionsByMapping[$mappingKey] = Constants::PERMISSION_ALL; } + if (!isset($inheritedMaskByMapping[$mappingKey])) { $inheritedMaskByMapping[$mappingKey] = 0; } + $inheritedPermissionsByMapping[$mappingKey] = $rule->applyPermissions($inheritedPermissionsByMapping[$mappingKey]); $inheritedMaskByMapping[$mappingKey] |= $rule->getMask(); } @@ -164,6 +170,7 @@ public function propPatch(string $path, PropPatch $propPatch): void { if (!$node instanceof Node) { return; } + $fileInfo = $node->getFileInfo(); $mount = $fileInfo->getMountPoint(); if (!$mount instanceof GroupMountPoint || !$this->isAdmin($fileInfo->getPath())) { @@ -176,11 +183,13 @@ public function propPatch(string $path, PropPatch $propPatch): void { if (!$node instanceof Node) { return false; } + $fileInfo = $node->getFileInfo(); $mount = $fileInfo->getMountPoint(); if (!$mount instanceof GroupMountPoint) { return false; } + $path = trim($mount->getSourcePath() . '/' . $fileInfo->getInternalPath(), '/'); // populate fileid in rules diff --git a/lib/DAV/GroupFoldersHome.php b/lib/DAV/GroupFoldersHome.php index 7634187a1..e6d4fad5f 100644 --- a/lib/DAV/GroupFoldersHome.php +++ b/lib/DAV/GroupFoldersHome.php @@ -67,6 +67,7 @@ private function getFolder(string $name): ?array { return $folder; } } + return null; } @@ -77,6 +78,7 @@ private function getFolder(string $name): ?array { private function getDirectoryForFolder(array $folder): GroupFolderNode { $userHome = '/' . $this->user->getUID() . '/files'; $node = $this->rootFolder->get($userHome . '/' . $folder['mount_point']); + return new GroupFolderNode(Filesystem::getView(), $node, $folder['folder_id']); } diff --git a/lib/DAV/RootCollection.php b/lib/DAV/RootCollection.php index 5f52e246e..947e5308f 100644 --- a/lib/DAV/RootCollection.php +++ b/lib/DAV/RootCollection.php @@ -39,6 +39,7 @@ public function getChildForPrincipal(array $principalInfo): GroupFoldersHome { if (is_null($user) || $name !== $user->getUID()) { throw new \Sabre\DAV\Exception\Forbidden(); } + return new GroupFoldersHome($principalInfo, $this->folderManager, $this->rootFolder, $user); } diff --git a/lib/Folder/FolderManager.php b/lib/Folder/FolderManager.php index 019184de6..87cad8283 100644 --- a/lib/Folder/FolderManager.php +++ b/lib/Folder/FolderManager.php @@ -234,16 +234,19 @@ private function getManageAcl(array $mappings): array { if ($user === null) { return null; } + return [ 'type' => 'user', 'id' => (string)$user->getUID(), 'displayname' => (string)$user->getDisplayName() ]; } + $group = Server::get(IGroupManager::class)->get($entry['mapping_id']); if ($group === null) { return []; } + return [ 'type' => 'group', 'id' => $group->getGID(), @@ -276,6 +279,7 @@ public function getFolder(int $id, int $rootStorageId): ?array { } $folderMappings = $this->getFolderMappings($id); + return [ 'id' => $id, 'mount_point' => (string)$row['mount_point'], @@ -310,6 +314,7 @@ public function getFolderByPath(string $path): int { $node = Server::get(IRootFolder::class)->get($path); /** @var GroupMountPoint $mountPoint */ $mountPoint = $node->getMountPoint(); + return $mountPoint->getFolderId(); } @@ -354,7 +359,7 @@ private function getAllApplicable(): array { private function generateApplicableMapEntry( array $row, ?CirclesQueryHelper $queryHelper = null, - ?string &$entityId = null + ?string &$entityId = null, ): array { if (!$row['circle_id']) { $entityId = $row['group_id']; @@ -372,6 +377,7 @@ private function generateApplicableMapEntry( } catch (CircleNotFoundException $e) { $circle = null; } + $displayName = $circle?->getDisplayName() ?? $row['circle_id']; return [ @@ -390,6 +396,7 @@ private function getGroups(int $id): array { $groups = array_map(function ($gid) { return $this->groupManager->get($gid); }, array_keys($groups)); + return array_map(function ($group) { return [ 'gid' => $group->getGID(), @@ -440,6 +447,7 @@ public function canManageACL(int $folderId, IUser $user): bool { return true; } } + return false; } @@ -451,6 +459,7 @@ public function searchGroups(int $id, string $search = ''): array { if ($search === '') { return $groups; } + return array_filter($groups, function ($group) use ($search) { return (stripos($group['gid'], $search) !== false) || (stripos($group['displayname'], $search) !== false); }); @@ -476,6 +485,7 @@ public function searchUsers(int $id, string $search = '', int $limit = 10, int $ } } } + return array_values($users); } @@ -519,6 +529,7 @@ public function getFoldersForGroup(string $groupId, int $rootStorageId = 0): arr $this->joinQueryWithFileCache($query, $rootStorageId); $result = $query->executeQuery()->fetchAll(); + return array_values(array_map(function ($folder): array { return [ 'folder_id' => (int)$folder['folder_id'], @@ -765,6 +776,7 @@ public function setManageACL(int $folderId, string $type, string $id, bool $mana ->andWhere($query->expr()->eq('mapping_type', $query->createNamedParameter($type))) ->andWhere($query->expr()->eq('mapping_id', $query->createNamedParameter($id))); } + $query->executeStatement(); $action = $manageAcl ? 'given' : 'revoked'; diff --git a/lib/Listeners/NodeRenamedListener.php b/lib/Listeners/NodeRenamedListener.php index 60822f9a9..86354b934 100644 --- a/lib/Listeners/NodeRenamedListener.php +++ b/lib/Listeners/NodeRenamedListener.php @@ -42,6 +42,7 @@ public function handle(Event $event): void { if ($sourcePath !== '') { $sourcePath .= '/'; } + $sourcePath .= $source->getName(); $targetPath = $target->getInternalPath(); $this->trashManager->updateTrashedChildren($sourceStorage->getFolderId(), $targetStorage->getFolderId(), $sourcePath, $targetPath); diff --git a/lib/Migration/Version1000000Date20210216085047.php b/lib/Migration/Version1000000Date20210216085047.php index 00d473071..a707512ac 100644 --- a/lib/Migration/Version1000000Date20210216085047.php +++ b/lib/Migration/Version1000000Date20210216085047.php @@ -40,6 +40,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt if ($table->hasIndex('groups_folder_trash_folder')) { $table->dropIndex('groups_folder_trash_folder'); } + if ($table->hasIndex('groups_folder_name')) { $table->dropIndex('groups_folder_name'); } diff --git a/lib/Migration/Version102020Date20180806161449.php b/lib/Migration/Version102020Date20180806161449.php index 9aef4de68..52a870806 100644 --- a/lib/Migration/Version102020Date20180806161449.php +++ b/lib/Migration/Version102020Date20180806161449.php @@ -66,6 +66,7 @@ public function changeSchema(IOutput $output, \Closure $schemaClosure, array $op $table->addIndex(['group_id'], 'group_folder_value'); $table->addUniqueIndex(['folder_id', 'group_id'], 'groups_folder_group'); } + return $schema; } } diff --git a/lib/Mount/CacheRootPermissionsMask.php b/lib/Mount/CacheRootPermissionsMask.php index e260f8902..09738959f 100644 --- a/lib/Mount/CacheRootPermissionsMask.php +++ b/lib/Mount/CacheRootPermissionsMask.php @@ -26,6 +26,7 @@ protected function formatCacheEntry($entry) { $entry['scan_permissions'] = $entry['permissions']; $entry['permissions'] &= $this->mask; } + return $entry; } } diff --git a/lib/Mount/GroupFolderEncryptionJail.php b/lib/Mount/GroupFolderEncryptionJail.php index 7f9ce9e1a..93ce0e4e9 100644 --- a/lib/Mount/GroupFolderEncryptionJail.php +++ b/lib/Mount/GroupFolderEncryptionJail.php @@ -20,10 +20,12 @@ public function getCache($path = '', $storage = null) { if (!$storage) { $storage = $this->getWrapperStorage(); } + // By default the Jail reuses the inner cache, but when encryption is // enabled the storage needs to be passed to the cache so it takes into // account the outer Encryption wrapper. $sourceCache = $this->getWrapperStorage()->getCache($this->getUnjailedPath($path), $storage); + return new CacheJail($sourceCache, $this->rootPath); } } diff --git a/lib/Mount/GroupFolderStorage.php b/lib/Mount/GroupFolderStorage.php index 7bc54835e..707bcd215 100644 --- a/lib/Mount/GroupFolderStorage.php +++ b/lib/Mount/GroupFolderStorage.php @@ -43,6 +43,7 @@ public function getOwner($path): string|false { if ($user !== null) { return $user->getUID(); } + return $this->mountOwner !== null ? $this->mountOwner->getUID() : false; } @@ -50,11 +51,13 @@ public function getCache($path = '', $storage = null) { if ($this->cache) { return $this->cache; } + if (!$storage) { $storage = $this; } $this->cache = new RootEntryCache(parent::getCache($path, $storage), $this->rootEntry); + return $this->cache; } @@ -63,11 +66,13 @@ public function getScanner($path = '', $storage = null) { if (!$storage) { $storage = $this; } + if ($storage->instanceOfStorage(ObjectStoreStorage::class)) { $storage->scanner = new ObjectStoreScanner($storage); } elseif (!isset($storage->scanner)) { $storage->scanner = new Scanner($storage); } + return $storage->scanner; } } diff --git a/lib/Mount/MountProvider.php b/lib/Mount/MountProvider.php index dff103d83..55e7c6fac 100644 --- a/lib/Mount/MountProvider.php +++ b/lib/Mount/MountProvider.php @@ -72,7 +72,7 @@ public function __construct( IDBConnection $connection, ICache $cache, bool $allowRootShare, - bool $enableEncryption + bool $enableEncryption, ) { $this->groupProvider = $groupProvider; $this->folderManager = $folderManager; @@ -99,6 +99,7 @@ private function getRootStorageId(): int { $this->rootStorageId = $id; } } + return $this->rootStorageId; } @@ -175,6 +176,7 @@ private function getCurrentUID(): ?string { } $user = $this->userSession->getUser(); + return $user ? $user->getUID() : null; } @@ -188,7 +190,7 @@ public function getMount( bool $acl = false, ?IUser $user = null, ?ACLManager $aclManager = null, - array $rootRules = [] + array $rootRules = [], ): ?IMountPoint { if (!$cacheEntry) { // trigger folder creation @@ -196,6 +198,7 @@ public function getMount( if ($folder === null) { return null; } + $cacheEntry = $this->getRootFolder()->getStorage()->getCache()->get($folder->getId()); } @@ -245,6 +248,7 @@ public function getMount( 'mountOwner' => $user, ]); } + $maskedStore = new PermissionsMask([ 'storage' => $quotaStorage, 'mask' => $permissions @@ -275,6 +279,7 @@ private function getRootFolder(): Folder { $rootProvider = $this->rootProvider; $this->root = $rootProvider(); } + return $this->root; } diff --git a/lib/Mount/RootEntryCache.php b/lib/Mount/RootEntryCache.php index 67bd06844..b97940055 100644 --- a/lib/Mount/RootEntryCache.php +++ b/lib/Mount/RootEntryCache.php @@ -24,6 +24,7 @@ public function get($file) { if ($file === '' && $this->rootEntry) { return $this->rootEntry; } + return parent::get($file); } @@ -31,6 +32,7 @@ public function getId($file) { if ($file === '' && $this->rootEntry) { return $this->rootEntry->getId(); } + return parent::getId($file); } diff --git a/lib/Mount/RootPermissionsMask.php b/lib/Mount/RootPermissionsMask.php index 3f1b01089..f340ebc0c 100644 --- a/lib/Mount/RootPermissionsMask.php +++ b/lib/Mount/RootPermissionsMask.php @@ -82,6 +82,7 @@ public function getMetaData($path) { $data['scan_permissions'] = $data['scan_permissions'] ?? $data['permissions']; $data['permissions'] &= $this->mask; } + return $data; } @@ -89,7 +90,9 @@ public function getCache($path = '', $storage = null) { if (!$storage) { $storage = $this; } + $sourceCache = parent::getCache($path, $storage); + return new CacheRootPermissionsMask($sourceCache, $this->mask); } } diff --git a/lib/Service/DelegationService.php b/lib/Service/DelegationService.php index ac3d6fca4..cf562834c 100644 --- a/lib/Service/DelegationService.php +++ b/lib/Service/DelegationService.php @@ -32,7 +32,7 @@ class DelegationService { public function __construct( AuthorizedGroupMapper $groupAuthorizationMapper, IGroupManager $groupManager, - IUserSession $userSession + IUserSession $userSession, ) { $this->groupAuthorizationMapper = $groupAuthorizationMapper; $this->groupManager = $groupManager; @@ -62,6 +62,7 @@ public function hasApiAccess(): bool { if ($this->isAdminNextcloud()) { return true; } + return $this->getAccessLevel([ self::CLASS_API_ACCESS, self::CLASS_NAME_ADMIN_DELEGATION, @@ -86,6 +87,7 @@ private function getAccessLevel(array $settingClasses): bool { break; } } + return $authorized; } } diff --git a/lib/Service/FoldersFilter.php b/lib/Service/FoldersFilter.php index dfcf50a78..67b60f508 100644 --- a/lib/Service/FoldersFilter.php +++ b/lib/Service/FoldersFilter.php @@ -35,6 +35,7 @@ public function getForApiUser(array $folders): array { return true; } } + return false; }); diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php index 5b80c1438..213352be2 100644 --- a/lib/Settings/Admin.php +++ b/lib/Settings/Admin.php @@ -19,7 +19,7 @@ public function __construct( private IInitialState $initialState, private ApplicationService $applicationService, private DelegationService $delegationService, - private IAppManager $appManager + private IAppManager $appManager, ) { } diff --git a/lib/Settings/Section.php b/lib/Settings/Section.php index 126a6aa66..a64a52198 100644 --- a/lib/Settings/Section.php +++ b/lib/Settings/Section.php @@ -14,7 +14,7 @@ class Section implements IIconSection { public function __construct( private IL10N $l, - private IURLGenerator $url + private IURLGenerator $url, ) { } diff --git a/lib/Trash/GroupTrashItem.php b/lib/Trash/GroupTrashItem.php index 7371f0487..a026d27d7 100644 --- a/lib/Trash/GroupTrashItem.php +++ b/lib/Trash/GroupTrashItem.php @@ -49,6 +49,7 @@ public function getStorage() { /** @var Jail $groupFolderStorage */ return $groupFolderStorage->getUnjailedStorage(); } + return $groupFolderStorage; } @@ -60,6 +61,7 @@ public function getMtime() { public function getInternalPath() { // trashbin expects the path without the deletion timestamp $path = parent::getInternalPath(); + return rtrim($path, '.d' . $this->getDeletedTime()); } } diff --git a/lib/Trash/TrashBackend.php b/lib/Trash/TrashBackend.php index 3a4053f60..750f7661d 100644 --- a/lib/Trash/TrashBackend.php +++ b/lib/Trash/TrashBackend.php @@ -64,17 +64,21 @@ public function listTrashFolder(ITrashItem $folder): array { if (!$folder instanceof GroupTrashItem) { return []; } + $user = $folder->getUser(); $folderNode = $this->getNodeForTrashItem($user, $folder); if (!$folderNode instanceof Folder) { return []; } + $content = $folderNode->getDirectoryListing(); $this->aclManagerFactory->getACLManager($user)->preloadRulesForFolder($folder->getPath()); + return array_values(array_filter(array_map(function (Node $node) use ($folder, $user) { if (!$this->userHasAccessToPath($user, $folder->getPath() . '/' . $node->getName())) { return null; } + return new GroupTrashItem( $this, $folder->getOriginalLocation() . '/' . $node->getName(), @@ -96,15 +100,18 @@ public function restoreItem(ITrashItem $item) { if (!($item instanceof GroupTrashItem)) { throw new \LogicException('Trying to restore normal trash item in group folder trash backend'); } + $user = $item->getUser(); [, $folderId] = explode('/', $item->getTrashPath()); $node = $this->getNodeForTrashItem($user, $item); if ($node === null) { throw new NotFoundException(); } + if (!$this->userHasAccessToPath($item->getUser(), $item->getPath(), Constants::PERMISSION_UPDATE)) { throw new NotPermittedException(); } + $folderPermissions = $this->folderManager->getFolderPermissionsForUser($item->getUser(), (int)$folderId); if (($folderPermissions & Constants::PERMISSION_UPDATE) !== Constants::PERMISSION_UPDATE) { throw new NotPermittedException(); @@ -118,6 +125,7 @@ public function restoreItem(ITrashItem $item) { if ($parent === '.') { $parent = ''; } + if ($parent !== '' && !$targetFolder->nodeExists($parent)) { $originalLocation = basename($originalLocation); } @@ -171,15 +179,18 @@ public function removeItem(ITrashItem $item) { if (!($item instanceof GroupTrashItem)) { throw new \LogicException('Trying to remove normal trash item in group folder trash backend'); } + $user = $item->getUser(); [, $folderId] = explode('/', $item->getTrashPath()); $node = $this->getNodeForTrashItem($user, $item); if ($node === null) { throw new NotFoundException(); } + if ($node->getStorage()->unlink($node->getInternalPath()) === false) { throw new \Exception('Failed to remove item from trashbin'); } + if (!$this->userHasAccessToPath($item->getUser(), $item->getPath(), Constants::PERMISSION_DELETE)) { throw new NotPermittedException(); } @@ -210,6 +221,7 @@ public function moveToTrash(IStorage $storage, string $internalPath): bool { } else { throw new \Exception('Failed to move groupfolder item to trash'); } + return true; } else { return false; @@ -225,6 +237,7 @@ private function unwrapJails(IStorage $storage, string $internalPath): array { $unJailedInternalPath = $unJailedStorage->getUnjailedPath($unJailedInternalPath); } } + return [$unJailedStorage, $unJailedInternalPath]; } @@ -233,16 +246,18 @@ private function userHasAccessToFolder(IUser $user, int $folderId): bool { $folderIds = array_map(function (array $folder): int { return $folder['folder_id']; }, $folders); + return in_array($folderId, $folderIds); } private function userHasAccessToPath( IUser $user, string $path, - int $permission = Constants::PERMISSION_READ + int $permission = Constants::PERMISSION_READ, ): bool { $activePermissions = $this->aclManagerFactory->getACLManager($user) ->getACLPermissionsForPath($path); + return (bool)($activePermissions & $permission); } @@ -257,12 +272,14 @@ private function getNodeForTrashItem(IUser $user, ITrashItem $trashItem): ?Node if (!$this->userHasAccessToPath($user, $trashItem->getPath())) { return null; } + return $node; } catch (NotFoundException $e) { return null; } } } + return null; } @@ -270,6 +287,7 @@ private function getTrashRoot(): Folder { try { /** @var Folder $folder */ $folder = $this->appFolder->get('trash'); + return $folder; } catch (NotFoundException $e) { return $this->appFolder->newFolder('trash'); @@ -280,10 +298,12 @@ private function getTrashFolder(int $folderId): Folder { try { /** @var Folder $folder */ $folder = $this->appFolder->get('trash/' . $folderId); + return $folder; } catch (NotFoundException $e) { /** @var Folder $trashRoot */ $trashRoot = $this->appFolder->nodeExists('trash') ? $this->appFolder->get('trash') : $this->appFolder->newFolder('trash'); + return $trashRoot->newFolder((string)$folderId); } } @@ -305,6 +325,7 @@ private function getTrashForFolders(IUser $user, array $folders): array { $indexedRows[$key] = $row; $trashItemsByOriginalLocation[$row['original_location']] = $row; } + $items = []; foreach ($folders as $folder) { $folderId = $folder['folder_id']; @@ -329,9 +350,11 @@ private function getTrashForFolders(IUser $user, array $folders): array { if ($originalLocation === '' && !$userCanManageAcl) { continue; } + if (!$this->userHasAccessToPath($user, $item->getPath())) { continue; } + // if a parent of the original location has also been deleted, we also need to check it based on the now-deleted parent path foreach ($this->getParentOriginalPaths($originalLocation, $trashItemsByOriginalLocation) as $parentOriginalPath) { $parentTrashItem = $trashItemsByOriginalLocation[$parentOriginalPath]; @@ -357,6 +380,7 @@ private function getTrashForFolders(IUser $user, array $folders): array { ); } } + return $items; } @@ -371,6 +395,7 @@ private function getParentOriginalPaths(string $path, array $trashItemsByOrigina $parentPaths[] = $path; } } + return $parentPaths; } @@ -383,6 +408,7 @@ public function getTrashNodeById(IUser $user, int $fileId): ?Node { if (!$path) { return null; } + $absolutePath = $this->appFolder->getMountPoint()->getMountPoint() . $path; $relativePath = $trashFolder->getRelativePath($absolutePath); [, $folderId, $nameAndTime] = explode('/', $relativePath); @@ -431,13 +457,16 @@ public function expire(Expiration $expiration): array { $this->trashManager->removeItem($folderId, $groupTrashItem['name'], $groupTrashItem['deleted_time']); continue; } + $sizeInTrash += $node->getSize(); } + foreach ($trashItems as $groupTrashItem) { $nodeName = $groupTrashItem['name'] . '.d' . $groupTrashItem['deleted_time']; if (!isset($nodes[$nodeName])) { continue; } + $node = $nodes[$nodeName]; if ($expiration->isExpired($groupTrashItem['deleted_time'], $folder['quota'] > 0 && $folder['quota'] < ($folder['size'] + $sizeInTrash))) { @@ -446,6 +475,7 @@ public function expire(Expiration $expiration): array { $this->logger->error('Failed to remove item from trashbin: ' . $node->getPath()); continue; } + // only count up after checking if removal is possible $count += 1; $size += $node->getSize(); diff --git a/lib/Trash/TrashManager.php b/lib/Trash/TrashManager.php index b44834387..8aa57018b 100644 --- a/lib/Trash/TrashManager.php +++ b/lib/Trash/TrashManager.php @@ -26,6 +26,7 @@ public function listTrashForFolders(array $folderIds): array { ->from('group_folders_trash') ->orderBy('deleted_time') ->where($query->expr()->in('folder_id', $query->createNamedParameter($folderIds, IQueryBuilder::PARAM_INT_ARRAY))); + return $query->executeQuery()->fetchAll(); } @@ -48,6 +49,7 @@ public function getTrashItemByFileId(int $fileId): ?array { $query->select(['trash_id', 'name', 'deleted_time', 'original_location', 'folder_id', 'deleted_by']) ->from('group_folders_trash') ->where($query->expr()->eq('file_id', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))); + return $query->executeQuery()->fetch() ?: null; } @@ -58,6 +60,7 @@ public function getTrashItemByFileName(int $folderId, string $name, int $deleted ->where($query->expr()->eq('folder_id', $query->createNamedParameter($folderId, IQueryBuilder::PARAM_INT))) ->andWhere($query->expr()->eq('name', $query->createNamedParameter($name))) ->andWhere($query->expr()->eq('deleted_time', $query->createNamedParameter($deletedTime, IQueryBuilder::PARAM_INT))); + return $query->executeQuery()->fetch() ?: null; } diff --git a/lib/Versions/ExpireManager.php b/lib/Versions/ExpireManager.php index eba57447b..74d90056c 100644 --- a/lib/Versions/ExpireManager.php +++ b/lib/Versions/ExpireManager.php @@ -49,6 +49,7 @@ protected function getAutoExpireList(int $time, array $versions): array { if (!$versions) { return []; } + $toDelete = []; // versions we want to delete // ensure the versions are sorted newest first @@ -76,6 +77,7 @@ protected function getAutoExpireList(int $time, array $versions): array { $nextVersion = $version->getTimestamp() - $step; $prevTimestamp = $version->getTimestamp(); } + $newInterval = false; // version checked so we can move to the next one } else { // time to move on to the next interval $interval++; @@ -87,6 +89,7 @@ protected function getAutoExpireList(int $time, array $versions): array { } else { $nextInterval = $time - self::MAX_VERSIONS_PER_INTERVAL[$interval]['intervalEndsAfter']; } + $newInterval = true; // we changed the interval -> check same version with new interval } } diff --git a/lib/Versions/GroupVersionsExpireManager.php b/lib/Versions/GroupVersionsExpireManager.php index b65747951..11f749cc6 100644 --- a/lib/Versions/GroupVersionsExpireManager.php +++ b/lib/Versions/GroupVersionsExpireManager.php @@ -29,7 +29,7 @@ public function __construct( ExpireManager $expireManager, VersionsBackend $versionsBackend, ITimeFactory $timeFactory, - IEventDispatcher $dispatcher + IEventDispatcher $dispatcher, ) { $this->folderManager = $folderManager; $this->expireManager = $expireManager; @@ -70,6 +70,7 @@ public function expireFolder(array $folder): void { $view->unlink('/' . $fileId); continue; } + $versions = $this->versionsBackend->getVersionsForFile($dummyUser, $file); $expireVersions = $this->expireManager->getExpiredVersion($versions, $this->timeFactory->getTime(), false); foreach ($expireVersions as $version) { diff --git a/lib/Versions/VersionsBackend.php b/lib/Versions/VersionsBackend.php index 555eb33e2..b54c436af 100644 --- a/lib/Versions/VersionsBackend.php +++ b/lib/Versions/VersionsBackend.php @@ -72,6 +72,7 @@ public function getVersionFolderForFile(FileInfo $file): Folder { try { /** @var Folder $versionsFolder */ $versionsFolder = $groupfoldersVersionsFolder->get((string)$file->getId()); + return $versionsFolder; } catch (NotFoundException $e) { // The folder for the file's versions might not exists if no versions has been create yet. @@ -119,6 +120,7 @@ public function getVersionsForFile(IUser $user, FileInfo $file): array { } else { $versionEntity->setTimestamp($mtime); } + $versionEntity->setSize($version->getSize()); // Use the main file mimetype for this initialization as the original mimetype is unknown. $versionEntity->setMimetype($this->mimeTypeLoader->getId($file->getMimetype())); @@ -159,6 +161,7 @@ function (GroupVersionEntity $versionEntity) use ($versionsFolder, $mountPoint, // The reality is that the disk version might have been lost during a move operation between storages, // and its not possible to recover it, so removing the entity makes sense. $this->groupVersionsMapper->delete($versionEntity); + return null; } } @@ -238,6 +241,7 @@ public function getVersionFile(IUser $user, FileInfo $sourceFile, $revision): Fi $versionsFolder = $this->getVersionFolderForFile($sourceFile); $file = $versionsFolder->get((string)$revision); assert($file instanceof File); + return $file; } @@ -252,6 +256,7 @@ public function getAllVersionedFiles(array $folder) { $this->logger->error('Tried to get all the versioned files from a non existing mountpoint'); return []; } + try { $contents = $versionsFolder->getDirectoryListing(); } catch (NotFoundException $e) { @@ -269,6 +274,7 @@ public function getAllVersionedFiles(array $folder) { return null; } }, $fileIds); + return array_combine($fileIds, $files); } @@ -285,10 +291,12 @@ private function getVersionsFolder(int $folderId): Folder { try { /** @var Folder $folder */ $folder = $this->appFolder->get('versions/' . $folderId); + return $folder; } catch (NotFoundException $e) { /** @var Folder $trashRoot */ $trashRoot = $this->appFolder->nodeExists('versions') ? $this->appFolder->get('versions') : $this->appFolder->newFolder('versions'); + return $trashRoot->newFolder((string)$folderId); } } @@ -398,6 +406,7 @@ public function importVersionsForFile(IUser $user, Node $source, Node $target, a if ($version instanceof IMetadataVersion) { $versionEntity->setDecodedMetadata($version->getMetadata()); } + $this->groupVersionsMapper->insert($versionEntity); } } diff --git a/tests/ACL/ACLManagerTest.php b/tests/ACL/ACLManagerTest.php index 21d3c1a81..349c9987a 100644 --- a/tests/ACL/ACLManagerTest.php +++ b/tests/ACL/ACLManagerTest.php @@ -57,6 +57,7 @@ private function createMapping(string $id): IUserMapping { $mapping->method('getType')->willReturn('dummy'); $mapping->method('getId')->willReturn($id); $mapping->method('getDisplayName')->willReturn("display name for $id"); + return $mapping; } diff --git a/tests/ACL/ACLScannerTest.php b/tests/ACL/ACLScannerTest.php index 9c5bb17d3..dba331836 100644 --- a/tests/ACL/ACLScannerTest.php +++ b/tests/ACL/ACLScannerTest.php @@ -25,6 +25,7 @@ private function getAclManager(array $rules): ACLManager { ->willReturnCallback(function ($path) use ($rules) { return $rules[$path] ?? Constants::PERMISSION_ALL; }); + return $manager; } diff --git a/tests/ACL/RuleManagerTest.php b/tests/ACL/RuleManagerTest.php index e0ea9e728..36a9b43ae 100644 --- a/tests/ACL/RuleManagerTest.php +++ b/tests/ACL/RuleManagerTest.php @@ -175,6 +175,7 @@ public function testGetByPathMore() { $paths[] = $path; $storage->touch($path); } + $storage->getScanner()->scan(''); $cache = $storage->getCache(); $id1 = (int)$cache->getId('foo'); diff --git a/tests/Folder/FolderManagerTest.php b/tests/Folder/FolderManagerTest.php index 19b2afd4c..89ca8fc1b 100644 --- a/tests/Folder/FolderManagerTest.php +++ b/tests/Folder/FolderManagerTest.php @@ -72,13 +72,16 @@ private function assertHasFolders($folders) { if (!isset($folder['size'])) { $folder['size'] = 0; } + if (!isset($folder['quota'])) { $folder['quota'] = -3; } + if (!isset($folder['acl'])) { $folder['acl'] = false; } } + foreach ($existingFolders as &$existingFolder) { unset($existingFolder['id']); } diff --git a/vendor-bin/cs-fixer/composer.json b/vendor-bin/cs-fixer/composer.json index dc131e721..de3cf862f 100644 --- a/vendor-bin/cs-fixer/composer.json +++ b/vendor-bin/cs-fixer/composer.json @@ -1,6 +1,6 @@ { "require-dev": { - "nextcloud/coding-standard": "^1.2" + "nextcloud/coding-standard": "^1.3" }, "config": { "platform": { diff --git a/vendor-bin/cs-fixer/composer.lock b/vendor-bin/cs-fixer/composer.lock index b7fda8118..cd782e189 100644 --- a/vendor-bin/cs-fixer/composer.lock +++ b/vendor-bin/cs-fixer/composer.lock @@ -4,24 +4,139 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "59bdbac023efd7059e30cfd98dc00b94", + "content-hash": "a96fb1e4ff8e96b0abbdeff1a02b5808", "packages": [], "packages-dev": [ + { + "name": "erickskrauch/php-cs-fixer-custom-fixers", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/erickskrauch/php-cs-fixer-custom-fixers.git", + "reference": "36fb7f8204c1e17d9b8a24910e2147d0a3973b9c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erickskrauch/php-cs-fixer-custom-fixers/zipball/36fb7f8204c1e17d9b8a24910e2147d0a3973b9c", + "reference": "36fb7f8204c1e17d9b8a24910e2147d0a3973b9c", + "shasum": "" + }, + "require": { + "friendsofphp/php-cs-fixer": "^3", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "ely/php-code-style": "^1", + "ergebnis/composer-normalize": "^2.28", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", + "phpspec/prophecy": "^1.15", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan": "^1.11.x-dev", + "phpstan/phpstan-phpunit": "^1.3", + "phpstan/phpstan-strict-rules": "^1.5", + "phpunit/phpunit": "^9.5", + "phpunitgoodpractices/polyfill": "^1.5", + "phpunitgoodpractices/traits": "^1.9.1", + "symfony/phpunit-bridge": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "ErickSkrauch\\PhpCsFixer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "ErickSkrauch", + "email": "erickskrauch@ely.by" + } + ], + "description": "A set of custom fixers for PHP-CS-Fixer", + "homepage": "https://github.com/erickskrauch/php-cs-fixer-custom-fixers", + "keywords": [ + "Code style", + "dev", + "php-cs-fixer" + ], + "support": { + "issues": "https://github.com/erickskrauch/php-cs-fixer-custom-fixers/issues", + "source": "https://github.com/erickskrauch/php-cs-fixer-custom-fixers/tree/1.3.0" + }, + "time": "2024-06-21T20:19:52+00:00" + }, + { + "name": "kubawerlos/php-cs-fixer-custom-fixers", + "version": "v3.22.0", + "source": { + "type": "git", + "url": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers.git", + "reference": "8701394f0c7cd450ac4fa577d24589122c1d5d5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kubawerlos/php-cs-fixer-custom-fixers/zipball/8701394f0c7cd450ac4fa577d24589122c1d5d5e", + "reference": "8701394f0c7cd450ac4fa577d24589122c1d5d5e", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "ext-tokenizer": "*", + "friendsofphp/php-cs-fixer": "^3.61.1", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6.4 || ^10.5.29" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpCsFixerCustomFixers\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kuba Werłos", + "email": "werlos@gmail.com" + } + ], + "description": "A set of custom fixers for PHP CS Fixer", + "support": { + "issues": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/issues", + "source": "https://github.com/kubawerlos/php-cs-fixer-custom-fixers/tree/v3.22.0" + }, + "time": "2024-08-16T20:44:35+00:00" + }, { "name": "nextcloud/coding-standard", - "version": "v1.2.3", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/nextcloud/coding-standard.git", - "reference": "bc9c53a5306114b60c4363057aff9c2ed10a54da" + "reference": "e2e6cb1518e3d56ebfb2365bb9fa91ecb50a374c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/bc9c53a5306114b60c4363057aff9c2ed10a54da", - "reference": "bc9c53a5306114b60c4363057aff9c2ed10a54da", + "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/e2e6cb1518e3d56ebfb2365bb9fa91ecb50a374c", + "reference": "e2e6cb1518e3d56ebfb2365bb9fa91ecb50a374c", "shasum": "" }, "require": { + "erickskrauch/php-cs-fixer-custom-fixers": "^1.3", + "kubawerlos/php-cs-fixer-custom-fixers": "^3.22", "php": "^7.3|^8.0", "php-cs-fixer/shim": "^3.17" }, @@ -44,9 +159,9 @@ "description": "Nextcloud coding standards for the php cs fixer", "support": { "issues": "https://github.com/nextcloud/coding-standard/issues", - "source": "https://github.com/nextcloud/coding-standard/tree/v1.2.3" + "source": "https://github.com/nextcloud/coding-standard/tree/v1.3.0" }, - "time": "2024-08-23T14:32:32+00:00" + "time": "2024-09-18T15:52:45+00:00" }, { "name": "php-cs-fixer/shim",