From 98dd02b4674c095801ab32c70261597bca905814 Mon Sep 17 00:00:00 2001 From: Robin Windey Date: Sun, 6 Aug 2023 14:12:24 +0200 Subject: Let occ trashbin:restore restore also from groupfolders and add additional filters * Using the TrashManager allows access to all deleted files * Add 'scope' parameter to choose where to restore from (user or groupfolders) * Add 'restore-from' and 'restore-to' date parameters to filter files to be restored by their deletion date * Add 'dry-run' flag to be able to see which files would be restored and being able to adjust the filter parameters accordingly Signed-off-by: GitHub --- .../files_trashbin/lib/Command/RestoreAllFiles.php | 202 ++++++++++++++++++--- 1 file changed, 173 insertions(+), 29 deletions(-) (limited to 'apps/files_trashbin/lib') diff --git a/apps/files_trashbin/lib/Command/RestoreAllFiles.php b/apps/files_trashbin/lib/Command/RestoreAllFiles.php index bff116c4ec4..98dc88db870 100644 --- a/apps/files_trashbin/lib/Command/RestoreAllFiles.php +++ b/apps/files_trashbin/lib/Command/RestoreAllFiles.php @@ -19,12 +19,12 @@ namespace OCA\Files_Trashbin\Command; use OC\Core\Command\Base; +use OCA\Files_Trashbin\Trash\ITrashItem; +use OCA\Files_Trashbin\Trash\ITrashManager; use OCP\Files\IRootFolder; use OCP\IDBConnection; use OCP\IL10N; use OCP\IUserBackend; -use OCA\Files_Trashbin\Trashbin; -use OCA\Files_Trashbin\Helper; use OCP\IUserManager; use OCP\L10N\IFactory; use Symfony\Component\Console\Exception\InvalidOptionException; @@ -35,6 +35,10 @@ use Symfony\Component\Console\Output\OutputInterface; class RestoreAllFiles extends Base { + private const SCOPE_ALL = 0; + private const SCOPE_USER = 1; + private const SCOPE_GROUPFOLDERS = 2; + /** @var IUserManager */ protected $userManager; @@ -44,6 +48,9 @@ class RestoreAllFiles extends Base { /** @var \OCP\IDBConnection */ protected $dbConnection; + /** @var ITrashManager */ + protected $trashManager; + /** @var IL10N */ protected $l10n; @@ -51,12 +58,15 @@ class RestoreAllFiles extends Base { * @param IRootFolder $rootFolder * @param IUserManager $userManager * @param IDBConnection $dbConnection + * @param ITrashManager $trashManager + * @param IFactory $l10nFactory */ - public function __construct(IRootFolder $rootFolder, IUserManager $userManager, IDBConnection $dbConnection, IFactory $l10nFactory) { + public function __construct(IRootFolder $rootFolder, IUserManager $userManager, IDBConnection $dbConnection, ITrashManager $trashManager, IFactory $l10nFactory) { parent::__construct(); $this->userManager = $userManager; $this->rootFolder = $rootFolder; $this->dbConnection = $dbConnection; + $this->trashManager = $trashManager; $this->l10n = $l10nFactory->get('files_trashbin'); } @@ -64,7 +74,7 @@ class RestoreAllFiles extends Base { parent::configure(); $this ->setName('trashbin:restore') - ->setDescription('Restore all deleted files') + ->setDescription('Restore all deleted files according to the given filters') ->addArgument( 'user_id', InputArgument::OPTIONAL | InputArgument::IS_ARRAY, @@ -75,6 +85,31 @@ class RestoreAllFiles extends Base { null, InputOption::VALUE_NONE, 'run action on all users' + ) + ->addOption( + 'scope', + 's', + InputOption::VALUE_OPTIONAL, + 'Restore files from the given scope. Possible values are "user", "groupfolders" or "all"', + 'user' + ) + ->addOption( + 'restore-from', + 'f', + InputOption::VALUE_OPTIONAL, + 'Only restore files deleted after the given timestamp' + ) + ->addOption( + 'restore-to', + 't', + InputOption::VALUE_OPTIONAL, + 'Only restore files deleted before the given timestamp' + ) + ->addOption( + 'dry-run', + 'd', + InputOption::VALUE_NONE, + 'Only show which files would be restored but do not perform any action' ); } @@ -83,11 +118,15 @@ class RestoreAllFiles extends Base { $users = $input->getArgument('user_id'); if ((!empty($users)) and ($input->getOption('all-users'))) { throw new InvalidOptionException('Either specify a user_id or --all-users'); - } elseif (!empty($users)) { + } + + [$scope, $restoreFrom, $restoreTo, $dryRun] = $this->parseArgs($input); + + if (!empty($users)) { foreach ($users as $user) { if ($this->userManager->userExists($user)) { $output->writeln("Restoring deleted files for user $user"); - $this->restoreDeletedFiles($user, $output); + $this->restoreDeletedFiles($user, $scope, $restoreFrom, $restoreTo, $dryRun, $output); } else { $output->writeln("Unknown user $user"); return 1; @@ -107,7 +146,7 @@ class RestoreAllFiles extends Base { $users = $backend->getUsers('', $limit, $offset); foreach ($users as $user) { $output->writeln("$user"); - $this->restoreDeletedFiles($user, $output); + $this->restoreDeletedFiles($user, $scope, $restoreFrom, $restoreTo, $dryRun, $output); } $offset += $limit; } while (count($users) >= $limit); @@ -122,44 +161,149 @@ class RestoreAllFiles extends Base { * Restore deleted files for the given user * * @param string $uid + * @param int $scope + * @param int|null $restoreFrom + * @param int|null $restoreTo + * @param bool $dryRun * @param OutputInterface $output */ - protected function restoreDeletedFiles(string $uid, OutputInterface $output): void { + protected function restoreDeletedFiles(string $uid, int $scope, ?int $restoreFrom, ?int $restoreTo, bool $dryRun, OutputInterface $output): void { \OC_Util::tearDownFS(); \OC_Util::setupFS($uid); \OC_User::setUserId($uid); - // Sort by most recently deleted first - // (Restoring in order of most recently deleted preserves nested file paths. - // See https://github.com/nextcloud/server/issues/31200#issuecomment-1130358549) - $filesInTrash = Helper::getTrashFiles('/', $uid, 'mtime', true); + $user = $this->userManager->get($uid); + $userTrashItems = $this->filterTrashItems( + $this->trashManager->listTrashRoot($user), + $scope, + $restoreFrom, + $restoreTo, + $output); - $trashCount = count($filesInTrash); + $trashCount = count($userTrashItems); if ($trashCount == 0) { $output->writeln("User has no deleted files in the trashbin"); return; } - $output->writeln("Preparing to restore $trashCount files..."); + $prepMsg = $dryRun ? 'Would restore' : 'Preparing to restore'; + $output->writeln("$prepMsg $trashCount files..."); $count = 0; - foreach ($filesInTrash as $trashFile) { - $filename = $trashFile->getName(); - $timestamp = $trashFile->getMtime(); - $humanTime = $this->l10n->l('datetime', $timestamp); - $output->write("File $filename originally deleted at $humanTime "); - $file = Trashbin::getTrashFilename($filename, $timestamp); - $location = Trashbin::getLocation($uid, $filename, (string) $timestamp); - if ($location === '.') { - $location = ''; + foreach($userTrashItems as $trashItem) { + $filename = $trashItem->getName(); + $humanTime = $this->l10n->l('datetime', $trashItem->getDeletedTime()); + // We use getTitle() here instead of getOriginalLocation() because + // for groupfolders this contains the groupfolder name itself as prefix + // which makes it more human readable + $location = $trashItem->getTitle(); + + if ($dryRun) { + $output->writeln("Would restore $filename originally deleted at $humanTime to /$location"); + continue; } - $output->write("restoring to /$location:"); - if (Trashbin::restore($file, $filename, $timestamp)) { - $count = $count + 1; - $output->writeln(" success"); - } else { + + $output->write("File $filename originally deleted at $humanTime restoring to /$location:"); + + try { + $trashItem->getTrashBackend()->restoreItem($trashItem); + } catch (\Throwable $e) { $output->writeln(" failed"); + $output->writeln("" . $e->getMessage() . ""); + $output->writeln("" . $e->getTraceAsString() . "", OutputInterface::VERBOSITY_VERY_VERBOSE); + continue; } + + $count = $count + 1; + $output->writeln(" success"); + } + + if (!$dryRun) { + $output->writeln("Successfully restored $count out of $trashCount files."); + } + } + + protected function parseArgs(InputInterface $input): array { + $restoreFrom = $this->parseTimestamp($input->getOption('restore-from')); + $restoreTo = $this->parseTimestamp($input->getOption('restore-to')); + + if ($restoreFrom !== null and $restoreTo !== null and $restoreFrom > $restoreTo) { + throw new InvalidOptionException('restore-from must be before restore-to'); } - $output->writeln("Successfully restored $count out of $trashCount files."); + return [ + $this->parseScope($input->getOption('scope')), + $restoreFrom, + $restoreTo, + $input->getOption('dry-run') + ]; + } + + /** + * @param string $scope + * @return int + */ + protected function parseScope(string $scope): int { + switch ($scope) { + case 'user': + return self::SCOPE_USER; + case 'groupfolders': + return self::SCOPE_GROUPFOLDERS; + case 'all': + return self::SCOPE_ALL; + default: + throw new InvalidOptionException("Invalid scope '$scope'"); + } + } + + /** + * @param string|null $timestamp + * @return int|null + */ + protected function parseTimestamp(?string $timestamp): ?int { + if ($timestamp === null) { + return null; + } + $timestamp = strtotime($timestamp); + if ($timestamp === false) { + throw new InvalidOptionException("Invalid timestamp '$timestamp'"); + } + return $timestamp; + } + + /** + * @param ITrashItem[] $trashItem + * @param int $scope + * @param int|null $restoreFrom + * @param int|null $restoreTo + * @param OutputInterface $output + * @return ITrashItem[] + */ + protected function filterTrashItems(array $trashItems, int $scope, ?int $restoreFrom, ?int $restoreTo, OutputInterface $output): array { + $filteredTrashItems = []; + foreach ($trashItems as $trashItem) { + // Check scope with exact class names + if ($scope === self::SCOPE_USER && get_class($trashItem) !== \OCA\Files_Trashbin\Trash\TrashItem::class) { + $output->writeln("Skipping " . $trashItem->getName() . " because it is not a user trash item", OutputInterface::VERBOSITY_VERBOSE); + continue; + } + if ($scope === self::SCOPE_GROUPFOLDERS && get_class($trashItem) !== \OCA\GroupFolders\Trash\GroupTrashItem::class) { + $output->writeln("Skipping " . $trashItem->getName() . " because it is not a groupfolders trash item", OutputInterface::VERBOSITY_VERBOSE); + continue; + } + + // Check left timestamp boundary + if ($restoreFrom !== null && $trashItem->getDeletedTime() <= $restoreFrom) { + $output->writeln("Skipping " . $trashItem->getName() . " because it was deleted before the restore-from timestamp", OutputInterface::VERBOSITY_VERBOSE); + continue; + } + + // Check right timestamp boundary + if ($restoreTo !== null && $trashItem->getDeletedTime() >= $restoreTo) { + $output->writeln("Skipping " . $trashItem->getName() . " because it was deleted after the restore-to timestamp", OutputInterface::VERBOSITY_VERBOSE); + continue; + } + + $filteredTrashItems[] = $trashItem; + } + return $filteredTrashItems; } } -- cgit v1.2.3 From ee66518ca25c53836a9b8a6eb3c17d46e3be8251 Mon Sep 17 00:00:00 2001 From: Robin Windey Date: Sat, 12 Aug 2023 13:06:34 +0000 Subject: Decouple from groupfolders app & remove PSALM warnings Signed-off-by: GitHub --- .../files_trashbin/lib/Command/RestoreAllFiles.php | 31 +++++++++++++--------- build/psalm-baseline.xml | 6 +++++ 2 files changed, 24 insertions(+), 13 deletions(-) (limited to 'apps/files_trashbin/lib') diff --git a/apps/files_trashbin/lib/Command/RestoreAllFiles.php b/apps/files_trashbin/lib/Command/RestoreAllFiles.php index 98dc88db870..1e852c3658e 100644 --- a/apps/files_trashbin/lib/Command/RestoreAllFiles.php +++ b/apps/files_trashbin/lib/Command/RestoreAllFiles.php @@ -124,13 +124,8 @@ class RestoreAllFiles extends Base { if (!empty($users)) { foreach ($users as $user) { - if ($this->userManager->userExists($user)) { - $output->writeln("Restoring deleted files for user $user"); - $this->restoreDeletedFiles($user, $scope, $restoreFrom, $restoreTo, $dryRun, $output); - } else { - $output->writeln("Unknown user $user"); - return 1; - } + $output->writeln("Restoring deleted files for user $user"); + $this->restoreDeletedFiles($user, $scope, $restoreFrom, $restoreTo, $dryRun, $output); } } elseif ($input->getOption('all-users')) { $output->writeln('Restoring deleted files for all users'); @@ -173,6 +168,12 @@ class RestoreAllFiles extends Base { \OC_User::setUserId($uid); $user = $this->userManager->get($uid); + + if ($user === null) { + $output->writeln("Unknown user $uid"); + return; + } + $userTrashItems = $this->filterTrashItems( $this->trashManager->listTrashRoot($user), $scope, @@ -215,7 +216,7 @@ class RestoreAllFiles extends Base { $count = $count + 1; $output->writeln(" success"); } - + if (!$dryRun) { $output->writeln("Successfully restored $count out of $trashCount files."); } @@ -270,7 +271,7 @@ class RestoreAllFiles extends Base { } /** - * @param ITrashItem[] $trashItem + * @param ITrashItem[] $trashItems * @param int $scope * @param int|null $restoreFrom * @param int|null $restoreTo @@ -280,12 +281,16 @@ class RestoreAllFiles extends Base { protected function filterTrashItems(array $trashItems, int $scope, ?int $restoreFrom, ?int $restoreTo, OutputInterface $output): array { $filteredTrashItems = []; foreach ($trashItems as $trashItem) { - // Check scope with exact class names - if ($scope === self::SCOPE_USER && get_class($trashItem) !== \OCA\Files_Trashbin\Trash\TrashItem::class) { + $trashItemClass = get_class($trashItem); + + // Check scope with exact class name for locally deleted files + if ($scope === self::SCOPE_USER && $trashItemClass !== \OCA\Files_Trashbin\Trash\TrashItem::class) { $output->writeln("Skipping " . $trashItem->getName() . " because it is not a user trash item", OutputInterface::VERBOSITY_VERBOSE); continue; } - if ($scope === self::SCOPE_GROUPFOLDERS && get_class($trashItem) !== \OCA\GroupFolders\Trash\GroupTrashItem::class) { + + // Check scope for groupfolders by string because the groupfolders app might not be installed + if ($scope === self::SCOPE_GROUPFOLDERS && $trashItemClass !== 'OCA\GroupFolders\Trash\GroupTrashItem') { $output->writeln("Skipping " . $trashItem->getName() . " because it is not a groupfolders trash item", OutputInterface::VERBOSITY_VERBOSE); continue; } @@ -301,7 +306,7 @@ class RestoreAllFiles extends Base { $output->writeln("Skipping " . $trashItem->getName() . " because it was deleted after the restore-to timestamp", OutputInterface::VERBOSITY_VERBOSE); continue; } - + $filteredTrashItems[] = $trashItem; } return $filteredTrashItems; diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 3d56f710237..bc88ef086df 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -1305,6 +1305,12 @@ + + + + + + IEventListener -- cgit v1.2.3 From 52d77eb9fe367a55dd0e8dc05abf7be6b00e298c Mon Sep 17 00:00:00 2001 From: Robin Windey Date: Sun, 13 Aug 2023 16:34:06 +0000 Subject: Make scope parsing more readable Signed-off-by: GitHub --- apps/files_trashbin/lib/Command/RestoreAllFiles.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'apps/files_trashbin/lib') diff --git a/apps/files_trashbin/lib/Command/RestoreAllFiles.php b/apps/files_trashbin/lib/Command/RestoreAllFiles.php index 1e852c3658e..172e1af385b 100644 --- a/apps/files_trashbin/lib/Command/RestoreAllFiles.php +++ b/apps/files_trashbin/lib/Command/RestoreAllFiles.php @@ -39,6 +39,12 @@ class RestoreAllFiles extends Base { private const SCOPE_USER = 1; private const SCOPE_GROUPFOLDERS = 2; + private static $SCOPE_MAP = [ + 'user' => self::SCOPE_USER, + 'groupfolders' => self::SCOPE_GROUPFOLDERS, + 'all' => self::SCOPE_ALL + ]; + /** @var IUserManager */ protected $userManager; @@ -243,16 +249,11 @@ class RestoreAllFiles extends Base { * @return int */ protected function parseScope(string $scope): int { - switch ($scope) { - case 'user': - return self::SCOPE_USER; - case 'groupfolders': - return self::SCOPE_GROUPFOLDERS; - case 'all': - return self::SCOPE_ALL; - default: - throw new InvalidOptionException("Invalid scope '$scope'"); + if (isset(self::$SCOPE_MAP[$scope])) { + return self::$SCOPE_MAP[$scope]; } + + throw new InvalidOptionException("Invalid scope '$scope'"); } /** -- cgit v1.2.3 From acf0b4ce34be0c7a9770c5032b8bd604d2dc22a6 Mon Sep 17 00:00:00 2001 From: Robin Windey Date: Mon, 14 Aug 2023 10:38:28 +0000 Subject: Code adjustments according to PR review * Delete unnecessary function docs * Rename parameters to 'since' and 'until' * Style: use '&&' instead of 'and' * Add types Signed-off-by: GitHub --- .../files_trashbin/lib/Command/RestoreAllFiles.php | 86 ++++++++-------------- build/psalm-baseline.xml | 6 -- 2 files changed, 32 insertions(+), 60 deletions(-) (limited to 'apps/files_trashbin/lib') diff --git a/apps/files_trashbin/lib/Command/RestoreAllFiles.php b/apps/files_trashbin/lib/Command/RestoreAllFiles.php index 172e1af385b..f071526680c 100644 --- a/apps/files_trashbin/lib/Command/RestoreAllFiles.php +++ b/apps/files_trashbin/lib/Command/RestoreAllFiles.php @@ -19,7 +19,6 @@ namespace OCA\Files_Trashbin\Command; use OC\Core\Command\Base; -use OCA\Files_Trashbin\Trash\ITrashItem; use OCA\Files_Trashbin\Trash\ITrashManager; use OCP\Files\IRootFolder; use OCP\IDBConnection; @@ -39,7 +38,7 @@ class RestoreAllFiles extends Base { private const SCOPE_USER = 1; private const SCOPE_GROUPFOLDERS = 2; - private static $SCOPE_MAP = [ + private static array $SCOPE_MAP = [ 'user' => self::SCOPE_USER, 'groupfolders' => self::SCOPE_GROUPFOLDERS, 'all' => self::SCOPE_ALL @@ -54,8 +53,7 @@ class RestoreAllFiles extends Base { /** @var \OCP\IDBConnection */ protected $dbConnection; - /** @var ITrashManager */ - protected $trashManager; + protected ITrashManager $trashManager; /** @var IL10N */ protected $l10n; @@ -100,14 +98,14 @@ class RestoreAllFiles extends Base { 'user' ) ->addOption( - 'restore-from', - 'f', + 'since', + null, InputOption::VALUE_OPTIONAL, 'Only restore files deleted after the given timestamp' ) ->addOption( - 'restore-to', - 't', + 'until', + null, InputOption::VALUE_OPTIONAL, 'Only restore files deleted before the given timestamp' ) @@ -122,16 +120,16 @@ class RestoreAllFiles extends Base { protected function execute(InputInterface $input, OutputInterface $output): int { /** @var string[] $users */ $users = $input->getArgument('user_id'); - if ((!empty($users)) and ($input->getOption('all-users'))) { + if ((!empty($users)) && ($input->getOption('all-users'))) { throw new InvalidOptionException('Either specify a user_id or --all-users'); } - [$scope, $restoreFrom, $restoreTo, $dryRun] = $this->parseArgs($input); + [$scope, $since, $until, $dryRun] = $this->parseArgs($input); if (!empty($users)) { foreach ($users as $user) { $output->writeln("Restoring deleted files for user $user"); - $this->restoreDeletedFiles($user, $scope, $restoreFrom, $restoreTo, $dryRun, $output); + $this->restoreDeletedFiles($user, $scope, $since, $until, $dryRun, $output); } } elseif ($input->getOption('all-users')) { $output->writeln('Restoring deleted files for all users'); @@ -147,7 +145,7 @@ class RestoreAllFiles extends Base { $users = $backend->getUsers('', $limit, $offset); foreach ($users as $user) { $output->writeln("$user"); - $this->restoreDeletedFiles($user, $scope, $restoreFrom, $restoreTo, $dryRun, $output); + $this->restoreDeletedFiles($user, $scope, $since, $until, $dryRun, $output); } $offset += $limit; } while (count($users) >= $limit); @@ -159,16 +157,9 @@ class RestoreAllFiles extends Base { } /** - * Restore deleted files for the given user - * - * @param string $uid - * @param int $scope - * @param int|null $restoreFrom - * @param int|null $restoreTo - * @param bool $dryRun - * @param OutputInterface $output + * Restore deleted files for the given user according to the given filters */ - protected function restoreDeletedFiles(string $uid, int $scope, ?int $restoreFrom, ?int $restoreTo, bool $dryRun, OutputInterface $output): void { + protected function restoreDeletedFiles(string $uid, int $scope, ?int $since, ?int $until, bool $dryRun, OutputInterface $output): void { \OC_Util::tearDownFS(); \OC_Util::setupFS($uid); \OC_User::setUserId($uid); @@ -183,13 +174,13 @@ class RestoreAllFiles extends Base { $userTrashItems = $this->filterTrashItems( $this->trashManager->listTrashRoot($user), $scope, - $restoreFrom, - $restoreTo, + $since, + $until, $output); $trashCount = count($userTrashItems); if ($trashCount == 0) { - $output->writeln("User has no deleted files in the trashbin"); + $output->writeln("User has no deleted files in the trashbin matching the given filters"); return; } $prepMsg = $dryRun ? 'Would restore' : 'Preparing to restore'; @@ -213,13 +204,12 @@ class RestoreAllFiles extends Base { try { $trashItem->getTrashBackend()->restoreItem($trashItem); } catch (\Throwable $e) { - $output->writeln(" failed"); - $output->writeln("" . $e->getMessage() . ""); - $output->writeln("" . $e->getTraceAsString() . "", OutputInterface::VERBOSITY_VERY_VERBOSE); + $output->writeln(" Failed: " . $e->getMessage() . ""); + $output->writeln(" " . $e->getTraceAsString() . "", OutputInterface::VERBOSITY_VERY_VERBOSE); continue; } - $count = $count + 1; + $count++; $output->writeln(" success"); } @@ -229,25 +219,21 @@ class RestoreAllFiles extends Base { } protected function parseArgs(InputInterface $input): array { - $restoreFrom = $this->parseTimestamp($input->getOption('restore-from')); - $restoreTo = $this->parseTimestamp($input->getOption('restore-to')); + $since = $this->parseTimestamp($input->getOption('since')); + $until = $this->parseTimestamp($input->getOption('until')); - if ($restoreFrom !== null and $restoreTo !== null and $restoreFrom > $restoreTo) { - throw new InvalidOptionException('restore-from must be before restore-to'); + if ($since !== null && $until !== null && $since > $until) { + throw new InvalidOptionException('since must be before until'); } return [ $this->parseScope($input->getOption('scope')), - $restoreFrom, - $restoreTo, + $since, + $until, $input->getOption('dry-run') ]; } - /** - * @param string $scope - * @return int - */ protected function parseScope(string $scope): int { if (isset(self::$SCOPE_MAP[$scope])) { return self::$SCOPE_MAP[$scope]; @@ -256,10 +242,6 @@ class RestoreAllFiles extends Base { throw new InvalidOptionException("Invalid scope '$scope'"); } - /** - * @param string|null $timestamp - * @return int|null - */ protected function parseTimestamp(?string $timestamp): ?int { if ($timestamp === null) { return null; @@ -271,15 +253,7 @@ class RestoreAllFiles extends Base { return $timestamp; } - /** - * @param ITrashItem[] $trashItems - * @param int $scope - * @param int|null $restoreFrom - * @param int|null $restoreTo - * @param OutputInterface $output - * @return ITrashItem[] - */ - protected function filterTrashItems(array $trashItems, int $scope, ?int $restoreFrom, ?int $restoreTo, OutputInterface $output): array { + protected function filterTrashItems(array $trashItems, int $scope, ?int $since, ?int $until, OutputInterface $output): array { $filteredTrashItems = []; foreach ($trashItems as $trashItem) { $trashItemClass = get_class($trashItem); @@ -290,20 +264,24 @@ class RestoreAllFiles extends Base { continue; } - // Check scope for groupfolders by string because the groupfolders app might not be installed + /** + * Check scope for groupfolders by string because the groupfolders app might not be installed. + * That's why PSALM doesn't know the class GroupTrashItem. + * @psalm-suppress RedundantCondition + */ if ($scope === self::SCOPE_GROUPFOLDERS && $trashItemClass !== 'OCA\GroupFolders\Trash\GroupTrashItem') { $output->writeln("Skipping " . $trashItem->getName() . " because it is not a groupfolders trash item", OutputInterface::VERBOSITY_VERBOSE); continue; } // Check left timestamp boundary - if ($restoreFrom !== null && $trashItem->getDeletedTime() <= $restoreFrom) { + if ($since !== null && $trashItem->getDeletedTime() <= $since) { $output->writeln("Skipping " . $trashItem->getName() . " because it was deleted before the restore-from timestamp", OutputInterface::VERBOSITY_VERBOSE); continue; } // Check right timestamp boundary - if ($restoreTo !== null && $trashItem->getDeletedTime() >= $restoreTo) { + if ($until !== null && $trashItem->getDeletedTime() >= $until) { $output->writeln("Skipping " . $trashItem->getName() . " because it was deleted after the restore-to timestamp", OutputInterface::VERBOSITY_VERBOSE); continue; } diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index bc88ef086df..3d56f710237 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -1305,12 +1305,6 @@ - - - - - - IEventListener -- cgit v1.2.3 From d7a73ffdf1b87d9e56e02446f3e2cd3c725d30a5 Mon Sep 17 00:00:00 2001 From: Robin Windey Date: Wed, 16 Aug 2023 08:40:21 +0000 Subject: Rename since/until in verbose message Signed-off-by: GitHub --- apps/files_trashbin/lib/Command/RestoreAllFiles.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'apps/files_trashbin/lib') diff --git a/apps/files_trashbin/lib/Command/RestoreAllFiles.php b/apps/files_trashbin/lib/Command/RestoreAllFiles.php index f071526680c..cd79f1e8def 100644 --- a/apps/files_trashbin/lib/Command/RestoreAllFiles.php +++ b/apps/files_trashbin/lib/Command/RestoreAllFiles.php @@ -276,13 +276,13 @@ class RestoreAllFiles extends Base { // Check left timestamp boundary if ($since !== null && $trashItem->getDeletedTime() <= $since) { - $output->writeln("Skipping " . $trashItem->getName() . " because it was deleted before the restore-from timestamp", OutputInterface::VERBOSITY_VERBOSE); + $output->writeln("Skipping " . $trashItem->getName() . " because it was deleted before the 'since' timestamp", OutputInterface::VERBOSITY_VERBOSE); continue; } // Check right timestamp boundary if ($until !== null && $trashItem->getDeletedTime() >= $until) { - $output->writeln("Skipping " . $trashItem->getName() . " because it was deleted after the restore-to timestamp", OutputInterface::VERBOSITY_VERBOSE); + $output->writeln("Skipping " . $trashItem->getName() . " because it was deleted after the 'until' timestamp", OutputInterface::VERBOSITY_VERBOSE); continue; } -- cgit v1.2.3