From 3c9cfe713a570f08aba6628cbe49ab307cc6e74d Mon Sep 17 00:00:00 2001 From: yemkareems Date: Mon, 8 Jul 2024 10:24:28 +0530 Subject: [PATCH 01/13] feat: add occ command files:list Signed-off-by: yemkareems --- apps/files/appinfo/info.xml | 1 + .../composer/composer/autoload_classmap.php | 1 + .../composer/composer/autoload_static.php | 7 +- apps/files/lib/Command/ListFiles.php | 312 ++++++++++++++++++ 4 files changed, 318 insertions(+), 3 deletions(-) create mode 100644 apps/files/lib/Command/ListFiles.php diff --git a/apps/files/appinfo/info.xml b/apps/files/appinfo/info.xml index f3da2057f6523..41904932bcb26 100644 --- a/apps/files/appinfo/info.xml +++ b/apps/files/appinfo/info.xml @@ -49,6 +49,7 @@ OCA\Files\Command\Object\Delete OCA\Files\Command\Object\Get OCA\Files\Command\Object\Put + OCA\Files\Command\ListFiles diff --git a/apps/files/composer/composer/autoload_classmap.php b/apps/files/composer/composer/autoload_classmap.php index 68cdabb3dcdab..e3ddd7f4a6c79 100644 --- a/apps/files/composer/composer/autoload_classmap.php +++ b/apps/files/composer/composer/autoload_classmap.php @@ -39,6 +39,7 @@ 'OCA\\Files\\Command\\Put' => $baseDir . '/../lib/Command/Put.php', 'OCA\\Files\\Command\\RepairTree' => $baseDir . '/../lib/Command/RepairTree.php', 'OCA\\Files\\Command\\Scan' => $baseDir . '/../lib/Command/Scan.php', + 'OCA\\Files\\Command\\ListFiles' => $baseDir . '/../lib/Command/ListFiles.php', 'OCA\\Files\\Command\\ScanAppData' => $baseDir . '/../lib/Command/ScanAppData.php', 'OCA\\Files\\Command\\TransferOwnership' => $baseDir . '/../lib/Command/TransferOwnership.php', 'OCA\\Files\\Controller\\ApiController' => $baseDir . '/../lib/Controller/ApiController.php', diff --git a/apps/files/composer/composer/autoload_static.php b/apps/files/composer/composer/autoload_static.php index ca88e773e4aa5..64cc2c5b7e15e 100644 --- a/apps/files/composer/composer/autoload_static.php +++ b/apps/files/composer/composer/autoload_static.php @@ -7,14 +7,14 @@ class ComposerStaticInitFiles { public static $prefixLengthsPsr4 = array ( - 'O' => + 'O' => array ( 'OCA\\Files\\' => 10, ), ); public static $prefixDirsPsr4 = array ( - 'OCA\\Files\\' => + 'OCA\\Files\\' => array ( 0 => __DIR__ . '/..' . '/../lib', ), @@ -54,7 +54,8 @@ class ComposerStaticInitFiles 'OCA\\Files\\Command\\Put' => __DIR__ . '/..' . '/../lib/Command/Put.php', 'OCA\\Files\\Command\\RepairTree' => __DIR__ . '/..' . '/../lib/Command/RepairTree.php', 'OCA\\Files\\Command\\Scan' => __DIR__ . '/..' . '/../lib/Command/Scan.php', - 'OCA\\Files\\Command\\ScanAppData' => __DIR__ . '/..' . '/../lib/Command/ScanAppData.php', + 'OCA\\Files\\Command\\ListFiles' => __DIR__ . '/..' . '/../lib/Command/ListFiles.php', + 'OCA\\Files\\Command\\ScanAppData' => __DIR__ . '/..' . '/../lib/Command/ScanAppData.php', 'OCA\\Files\\Command\\TransferOwnership' => __DIR__ . '/..' . '/../lib/Command/TransferOwnership.php', 'OCA\\Files\\Controller\\ApiController' => __DIR__ . '/..' . '/../lib/Controller/ApiController.php', 'OCA\\Files\\Controller\\DirectEditingController' => __DIR__ . '/..' . '/../lib/Controller/DirectEditingController.php', diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php new file mode 100644 index 0000000000000..8e0dbfde52e31 --- /dev/null +++ b/apps/files/lib/Command/ListFiles.php @@ -0,0 +1,312 @@ + + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\Files\Command; + +use OC\Core\Command\Base; +use OC\Core\Command\InterruptedException; +use OC\FilesMetadata\FilesMetadataManager; +use OC\ForbiddenException; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\File; +use OCP\Files\FileInfo; +use OCP\Files\Folder; +use OCP\Files\IRootFolder; +use OCP\Files\NotFoundException; +use OCP\IUserManager; +use Psr\Log\LoggerInterface; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class ListFiles extends Base { + protected array $fileInfo = []; + protected array $dirInfo = []; + public function __construct( + private IUserManager $userManager, + private IRootFolder $rootFolder, + private FilesMetadataManager $filesMetadataManager, + private IEventDispatcher $eventDispatcher, + private LoggerInterface $logger + ) { + parent::__construct(); + } + + protected function configure(): void { + parent::configure(); + + $this->setName("files:list") + ->setDescription("List filesystem in the path mentioned in path argument") + ->addArgument( + "path", + InputArgument::REQUIRED, + 'List all the files and folder mentioned in this path, eg occ files:list path="/alice/files/Music", the path being a required argument to determine the user' + ) + ->addOption("type", "", InputArgument::OPTIONAL, "Filter by type like application, image, video etc") + ->addOption( + "minSize", + '0', + InputArgument::OPTIONAL, + "Filter by min size" + ) + ->addOption( + "maxSize", + '0', + InputArgument::OPTIONAL, + "Filter by max size" + ) + ->addOption( + "sort", + "name", + InputArgument::OPTIONAL, + "Sort by name, path, size, owner, type, perm, created-at" + ) + ->addOption("order", "ASC", InputArgument::OPTIONAL, "Order is either ASC or DESC"); + } + + private function getNodeInfo(File|Folder $node): array { + $nodeInfo = [ + "name" => $node->getName(), + "size" => $node->getSize() . " bytes", + "perm" => $node->getPermissions(), + "owner" => $node->getOwner()->getDisplayName(), + "created-at" => $node->getCreationTime(), + "type" => $node->getMimePart(), + ]; + if($node->getMimetype() == FileInfo::MIMETYPE_FOLDER) { + $nodeInfo['type'] = 'directory'; + } + + return $nodeInfo; + } + + protected function listFiles( + string $user, + string $path, + OutputInterface $output, + ?string $type = "", + ?int $minSize = 0, + ?int $maxSize = 0 + ): void { + try { + /** @var Folder $userFolder **/ + $userFolder = $this->rootFolder->get($path); + + $files = $userFolder->getDirectoryListing(); + foreach ($files as $file) { + $includeType = $includeMin = $includeMax = true; + $nodeInfo = $this->getNodeInfo($file); + if ($type != "" && $type != $nodeInfo['type']) { + $includeType = false; + } + if ($minSize > 0) { + $includeMin = $file->getSize() >= $minSize; + } + if ($maxSize > 0) { + $includeMax = $file->getSize() <= $maxSize; + } + if ($file instanceof File) { + if ($includeType && $includeMin && $includeMax) { + $this->fileInfo[] = $nodeInfo; + } + } elseif ($file instanceof Folder) { + if ($includeType && $includeMin && $includeMax) { + $this->dirInfo[] = $nodeInfo; + } + } + } + } catch (ForbiddenException $e) { + $output->writeln( + "Home storage for user $user not writable or 'files' subdirectory missing" + ); + $output->writeln(" " . $e->getMessage()); + $output->writeln( + 'Make sure you\'re running the list 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 (NotFoundException $e) { + $output->writeln( + "Path not found: " . $e->getMessage() . "" + ); + } catch (\Exception $e) { + $output->writeln( + "Exception during list: " . $e->getMessage() . "" + ); + $output->writeln("" . $e->getTraceAsString() . ""); + } + } + + protected function execute( + InputInterface $input, + OutputInterface $output + ): int { + $inputPath = $input->getArgument("path"); + if ($inputPath) { + $inputPath = ltrim($inputPath, "path="); + [, $user] = explode("/", rtrim($inputPath, "/").'/', 4); + } + + $this->initTools($output); + + if (is_object($user)) { + $user = $user->getUID(); + } + $path = $inputPath ?: "/" . $user; + + if ($this->userManager->userExists($user)) { + $output->writeln( + "Starting list for user ($user)" + ); + $this->listFiles( + $user, + $path, + $output, + $input->getOption("type"), + $input->getOption("minSize"), + $input->getOption("maxSize") + ); + } else { + $output->writeln( + "Unknown user $user" + ); + $output->writeln("", OutputInterface::VERBOSITY_VERBOSE); + return self::FAILURE; + } + + + $this->presentStats($input, $output); + return self::SUCCESS; + } + + /** + * Initialises some useful tools for the Command + */ + protected function initTools(OutputInterface $output): void { + // Convert PHP errors to exceptions + set_error_handler( + fn ( + int $severity, + string $message, + string $file, + int $line + ): bool => $this->exceptionErrorHandler( + $output, + $severity, + $message, + $file, + $line + ), + E_ALL + ); + } + + /** + * Processes PHP errors in order to be able to show them in the output + * + * @see https://www.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 + */ + public function exceptionErrorHandler( + OutputInterface $output, + int $severity, + string $message, + string $file, + int $line + ): bool { + if ($severity === E_DEPRECATED || $severity === E_USER_DEPRECATED) { + // Do not show deprecation warnings + return false; + } + $e = new \ErrorException($message, 0, $severity, $file, $line); + $output->writeln( + "Error during list: " . $e->getMessage() . "" + ); + $output->writeln( + "" . $e->getTraceAsString() . "", + OutputInterface::VERBOSITY_VERY_VERBOSE + ); + return true; + } + + protected function presentStats( + InputInterface $input, + OutputInterface $output + ): void { + $headers = [ + "Permission", + "Size", + "Owner", + "Created at", + "Filename", + "Type", + ]; + $rows = []; + $fileInfo = $this->fileInfo[0] ?? []; + $sortKey = array_key_exists($input->getOption("sort"), $fileInfo) + ? $input->getOption("sort") + : "name"; + $order = $input->getOption("order") == "ASC" ? SORT_ASC : SORT_DESC; + $fileArr = array_column($this->fileInfo, $sortKey); + $dirArr = array_column($this->dirInfo, $sortKey); + array_multisort( + $fileArr, + $order, + $this->fileInfo + ); + array_multisort( + $dirArr, + $order, + $this->dirInfo + ); + + foreach ($this->fileInfo as $k => $item) { + $rows[$k] = [ + $item["perm"], + $item["size"], + $item["owner"], + $item["created-at"], + $item["name"], + $item["type"], + ]; + } + foreach ($this->dirInfo as $k => $item) { + $rows[] = [ + $item["perm"], + $item["size"], + $item["owner"], + $item["created-at"], + $item["name"], + $item["type"], + ]; + } + + $table = new Table($output); + $table->setHeaders($headers)->setRows($rows); + $table->render(); + } +} From a851f27597528099e7ab9ba9a0c89e79145014c0 Mon Sep 17 00:00:00 2001 From: yemkareems Date: Mon, 8 Jul 2024 10:42:25 +0530 Subject: [PATCH 02/13] fix: FileCopyrightText changed Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index 8e0dbfde52e31..5e63eeaf077f7 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -1,23 +1,8 @@ - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * + * SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCA\Files\Command; @@ -88,7 +73,7 @@ private function getNodeInfo(File|Folder $node): array { "name" => $node->getName(), "size" => $node->getSize() . " bytes", "perm" => $node->getPermissions(), - "owner" => $node->getOwner()->getDisplayName(), + "owner" => $node->getOwner()?->getDisplayName(), "created-at" => $node->getCreationTime(), "type" => $node->getMimePart(), ]; From 5d3075a2883c405a5f7138197a77a6ac7357c0dc Mon Sep 17 00:00:00 2001 From: yemkareems Date: Mon, 8 Jul 2024 11:10:22 +0530 Subject: [PATCH 03/13] fix: ran build/autoloaderchecker.sh and commit the results Signed-off-by: yemkareems --- apps/files/composer/composer/autoload_classmap.php | 2 +- apps/files/composer/composer/autoload_static.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/files/composer/composer/autoload_classmap.php b/apps/files/composer/composer/autoload_classmap.php index e3ddd7f4a6c79..7a02936897769 100644 --- a/apps/files/composer/composer/autoload_classmap.php +++ b/apps/files/composer/composer/autoload_classmap.php @@ -31,6 +31,7 @@ 'OCA\\Files\\Command\\Delete' => $baseDir . '/../lib/Command/Delete.php', 'OCA\\Files\\Command\\DeleteOrphanedFiles' => $baseDir . '/../lib/Command/DeleteOrphanedFiles.php', 'OCA\\Files\\Command\\Get' => $baseDir . '/../lib/Command/Get.php', + 'OCA\\Files\\Command\\ListFiles' => $baseDir . '/../lib/Command/ListFiles.php', 'OCA\\Files\\Command\\Move' => $baseDir . '/../lib/Command/Move.php', 'OCA\\Files\\Command\\Object\\Delete' => $baseDir . '/../lib/Command/Object/Delete.php', 'OCA\\Files\\Command\\Object\\Get' => $baseDir . '/../lib/Command/Object/Get.php', @@ -39,7 +40,6 @@ 'OCA\\Files\\Command\\Put' => $baseDir . '/../lib/Command/Put.php', 'OCA\\Files\\Command\\RepairTree' => $baseDir . '/../lib/Command/RepairTree.php', 'OCA\\Files\\Command\\Scan' => $baseDir . '/../lib/Command/Scan.php', - 'OCA\\Files\\Command\\ListFiles' => $baseDir . '/../lib/Command/ListFiles.php', 'OCA\\Files\\Command\\ScanAppData' => $baseDir . '/../lib/Command/ScanAppData.php', 'OCA\\Files\\Command\\TransferOwnership' => $baseDir . '/../lib/Command/TransferOwnership.php', 'OCA\\Files\\Controller\\ApiController' => $baseDir . '/../lib/Controller/ApiController.php', diff --git a/apps/files/composer/composer/autoload_static.php b/apps/files/composer/composer/autoload_static.php index 64cc2c5b7e15e..53fc7185c9fc5 100644 --- a/apps/files/composer/composer/autoload_static.php +++ b/apps/files/composer/composer/autoload_static.php @@ -7,14 +7,14 @@ class ComposerStaticInitFiles { public static $prefixLengthsPsr4 = array ( - 'O' => + 'O' => array ( 'OCA\\Files\\' => 10, ), ); public static $prefixDirsPsr4 = array ( - 'OCA\\Files\\' => + 'OCA\\Files\\' => array ( 0 => __DIR__ . '/..' . '/../lib', ), @@ -46,6 +46,7 @@ class ComposerStaticInitFiles 'OCA\\Files\\Command\\Delete' => __DIR__ . '/..' . '/../lib/Command/Delete.php', 'OCA\\Files\\Command\\DeleteOrphanedFiles' => __DIR__ . '/..' . '/../lib/Command/DeleteOrphanedFiles.php', 'OCA\\Files\\Command\\Get' => __DIR__ . '/..' . '/../lib/Command/Get.php', + 'OCA\\Files\\Command\\ListFiles' => __DIR__ . '/..' . '/../lib/Command/ListFiles.php', 'OCA\\Files\\Command\\Move' => __DIR__ . '/..' . '/../lib/Command/Move.php', 'OCA\\Files\\Command\\Object\\Delete' => __DIR__ . '/..' . '/../lib/Command/Object/Delete.php', 'OCA\\Files\\Command\\Object\\Get' => __DIR__ . '/..' . '/../lib/Command/Object/Get.php', @@ -54,8 +55,7 @@ class ComposerStaticInitFiles 'OCA\\Files\\Command\\Put' => __DIR__ . '/..' . '/../lib/Command/Put.php', 'OCA\\Files\\Command\\RepairTree' => __DIR__ . '/..' . '/../lib/Command/RepairTree.php', 'OCA\\Files\\Command\\Scan' => __DIR__ . '/..' . '/../lib/Command/Scan.php', - 'OCA\\Files\\Command\\ListFiles' => __DIR__ . '/..' . '/../lib/Command/ListFiles.php', - 'OCA\\Files\\Command\\ScanAppData' => __DIR__ . '/..' . '/../lib/Command/ScanAppData.php', + 'OCA\\Files\\Command\\ScanAppData' => __DIR__ . '/..' . '/../lib/Command/ScanAppData.php', 'OCA\\Files\\Command\\TransferOwnership' => __DIR__ . '/..' . '/../lib/Command/TransferOwnership.php', 'OCA\\Files\\Controller\\ApiController' => __DIR__ . '/..' . '/../lib/Controller/ApiController.php', 'OCA\\Files\\Controller\\DirectEditingController' => __DIR__ . '/..' . '/../lib/Controller/DirectEditingController.php', From 8fc516c39a8559a0ad77bc2fc461684b8e3810b9 Mon Sep 17 00:00:00 2001 From: yemkareems Date: Mon, 8 Jul 2024 16:35:49 +0530 Subject: [PATCH 04/13] fix: getNodeInfo type corrected, type check made strict, min/max type converted, user check removed Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index 5e63eeaf077f7..4edc930d8cf0e 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -1,4 +1,5 @@ addOption("type", "", InputArgument::OPTIONAL, "Filter by type like application, image, video etc") ->addOption( "minSize", - '0', + 0, InputArgument::OPTIONAL, "Filter by min size" ) ->addOption( "maxSize", - '0', + 0, InputArgument::OPTIONAL, "Filter by max size" ) @@ -68,7 +70,7 @@ protected function configure(): void { ->addOption("order", "ASC", InputArgument::OPTIONAL, "Order is either ASC or DESC"); } - private function getNodeInfo(File|Folder $node): array { + private function getNodeInfo(Node $node): array { $nodeInfo = [ "name" => $node->getName(), "size" => $node->getSize() . " bytes", @@ -98,9 +100,11 @@ protected function listFiles( $files = $userFolder->getDirectoryListing(); foreach ($files as $file) { + /** @var Node $fileNode */ + $fileNode = $file; $includeType = $includeMin = $includeMax = true; - $nodeInfo = $this->getNodeInfo($file); - if ($type != "" && $type != $nodeInfo['type']) { + $nodeInfo = $this->getNodeInfo($fileNode); + if ($type !== "" && $type !== $nodeInfo['type']) { $includeType = false; } if ($minSize > 0) { @@ -147,6 +151,7 @@ protected function execute( OutputInterface $output ): int { $inputPath = $input->getArgument("path"); + $user = ''; if ($inputPath) { $inputPath = ltrim($inputPath, "path="); [, $user] = explode("/", rtrim($inputPath, "/").'/', 4); @@ -154,9 +159,6 @@ protected function execute( $this->initTools($output); - if (is_object($user)) { - $user = $user->getUID(); - } $path = $inputPath ?: "/" . $user; if ($this->userManager->userExists($user)) { @@ -168,8 +170,8 @@ protected function execute( $path, $output, $input->getOption("type"), - $input->getOption("minSize"), - $input->getOption("maxSize") + (int) $input->getOption("minSize"), + (int) $input->getOption("maxSize") ); } else { $output->writeln( From deb1f22c23b15565d9d3c2e87dba08d789ad7fab Mon Sep 17 00:00:00 2001 From: yemkareems Date: Mon, 8 Jul 2024 16:50:49 +0530 Subject: [PATCH 05/13] fix: addOption type corrected Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index 4edc930d8cf0e..b62e30f89a770 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -51,13 +51,13 @@ protected function configure(): void { ->addOption("type", "", InputArgument::OPTIONAL, "Filter by type like application, image, video etc") ->addOption( "minSize", - 0, + "0", InputArgument::OPTIONAL, "Filter by min size" ) ->addOption( "maxSize", - 0, + "0", InputArgument::OPTIONAL, "Filter by max size" ) From 66fa88fad2cf41f55243a4ecf664d2cccd576c5b Mon Sep 17 00:00:00 2001 From: yemkareems Date: Mon, 8 Jul 2024 17:04:28 +0530 Subject: [PATCH 06/13] fix: cs fix ran Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index b62e30f89a770..b0c7c50ddde5f 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -1,4 +1,5 @@ Date: Tue, 9 Jul 2024 14:31:47 +0530 Subject: [PATCH 07/13] fix: humanFileSize added for size, type strict check removed as it is breaking the listing, inputPath check removed as path is mandatory, sorting done only when sort param is there, writeTableInOutputFormat done Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 72 ++++++++++++---------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index b0c7c50ddde5f..4420ca1de9251 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -74,7 +74,7 @@ protected function configure(): void { private function getNodeInfo(Node $node): array { $nodeInfo = [ "name" => $node->getName(), - "size" => $node->getSize() . " bytes", + "size" => \OCP\Util::humanFileSize($node->getSize()), "perm" => $node->getPermissions(), "owner" => $node->getOwner()?->getDisplayName(), "created-at" => $node->getCreationTime(), @@ -105,7 +105,7 @@ protected function listFiles( $fileNode = $file; $includeType = $includeMin = $includeMax = true; $nodeInfo = $this->getNodeInfo($fileNode); - if ($type !== "" && $type !== $nodeInfo['type']) { + if ($type != "" && $type !== $nodeInfo['type']) { $includeType = false; } if ($minSize > 0) { @@ -152,11 +152,8 @@ protected function execute( OutputInterface $output ): int { $inputPath = $input->getArgument("path"); - $user = ''; - if ($inputPath) { - $inputPath = ltrim($inputPath, "path="); - [, $user] = explode("/", rtrim($inputPath, "/").'/', 4); - } + $inputPath = ltrim($inputPath, "path="); + [, $user] = explode("/", rtrim($inputPath, "/").'/', 4); $this->initTools($output); @@ -245,56 +242,47 @@ protected function presentStats( InputInterface $input, OutputInterface $output ): void { - $headers = [ - "Permission", - "Size", - "Owner", - "Created at", - "Filename", - "Type", - ]; $rows = []; $fileInfo = $this->fileInfo[0] ?? []; $sortKey = array_key_exists($input->getOption("sort"), $fileInfo) ? $input->getOption("sort") - : "name"; + : ""; $order = $input->getOption("order") == "ASC" ? SORT_ASC : SORT_DESC; $fileArr = array_column($this->fileInfo, $sortKey); $dirArr = array_column($this->dirInfo, $sortKey); - array_multisort( - $fileArr, - $order, - $this->fileInfo - ); - array_multisort( - $dirArr, - $order, - $this->dirInfo - ); - + if($sortKey != '') { + array_multisort( + $fileArr, + $order, + $this->fileInfo + ); + array_multisort( + $dirArr, + $order, + $this->dirInfo + ); + } foreach ($this->fileInfo as $k => $item) { $rows[$k] = [ - $item["perm"], - $item["size"], - $item["owner"], - $item["created-at"], - $item["name"], - $item["type"], + "Permission" => $item["perm"], + "Size" => $item["size"], + "Owner" => $item["owner"], + "Created at" => $item["created-at"], + "Filename" => $item["name"], + "Type" => $item["type"], ]; } foreach ($this->dirInfo as $k => $item) { $rows[] = [ - $item["perm"], - $item["size"], - $item["owner"], - $item["created-at"], - $item["name"], - $item["type"], + "Permission" => $item["perm"], + "Size" => $item["size"], + "Owner" => $item["owner"], + "Created at" => $item["created-at"], + "Filename" => $item["name"], + "Type" => $item["type"], ]; } - $table = new Table($output); - $table->setHeaders($headers)->setRows($rows); - $table->render(); + $this->writeTableInOutputFormat($input, $output, $rows); } } From 31e05a558269ca96ab362f9ffd2b5ecc5d2a3501 Mon Sep 17 00:00:00 2001 From: yemkareems Date: Tue, 9 Jul 2024 16:13:53 +0530 Subject: [PATCH 08/13] fix: cs fix ran for ListFiles Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index 4420ca1de9251..0bfb1e7355058 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -21,7 +21,6 @@ use OCP\Files\NotFoundException; use OCP\IUserManager; use Psr\Log\LoggerInterface; -use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; From b516475d15231d7491d3c4a3cb320866d8c0274c Mon Sep 17 00:00:00 2001 From: yemkareems Date: Tue, 9 Jul 2024 18:07:55 +0530 Subject: [PATCH 09/13] fix: issues with sorting fixed Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index 0bfb1e7355058..3ebc2a5a526a4 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -74,6 +74,7 @@ private function getNodeInfo(Node $node): array { $nodeInfo = [ "name" => $node->getName(), "size" => \OCP\Util::humanFileSize($node->getSize()), + "realSize" => $node->getSize(), "perm" => $node->getPermissions(), "owner" => $node->getOwner()?->getDisplayName(), "created-at" => $node->getCreationTime(), @@ -246,6 +247,9 @@ protected function presentStats( $sortKey = array_key_exists($input->getOption("sort"), $fileInfo) ? $input->getOption("sort") : ""; + if($sortKey == 'size') { + $sortKey = 'realSize'; + } $order = $input->getOption("order") == "ASC" ? SORT_ASC : SORT_DESC; $fileArr = array_column($this->fileInfo, $sortKey); $dirArr = array_column($this->dirInfo, $sortKey); @@ -253,11 +257,13 @@ protected function presentStats( array_multisort( $fileArr, $order, + SORT_NATURAL | SORT_FLAG_CASE, $this->fileInfo ); array_multisort( $dirArr, $order, + SORT_NATURAL | SORT_FLAG_CASE, $this->dirInfo ); } From 0caad523c5fad8dfd0df1f656786313b5397ed1b Mon Sep 17 00:00:00 2001 From: yemkareems Date: Mon, 29 Jul 2024 11:23:08 +0530 Subject: [PATCH 10/13] fix: make user mandatory argument and use getUserFolder to get users directory. Add path to get the list based on the path or else list the user folder. Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index 3ebc2a5a526a4..695aec36cac81 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -44,10 +44,11 @@ protected function configure(): void { $this->setName("files:list") ->setDescription("List filesystem in the path mentioned in path argument") ->addArgument( - "path", + "user", InputArgument::REQUIRED, - 'List all the files and folder mentioned in this path, eg occ files:list path="/alice/files/Music", the path being a required argument to determine the user' + 'List the files and folder belonging to the user, eg occ files:list user="admin", the user being a required argument' ) + ->addOption("path", "", InputArgument::OPTIONAL, "List files inside a particular path of the user, if not mentioned list from user's root directory") ->addOption("type", "", InputArgument::OPTIONAL, "Filter by type like application, image, video etc") ->addOption( "minSize", @@ -89,17 +90,18 @@ private function getNodeInfo(Node $node): array { protected function listFiles( string $user, - string $path, OutputInterface $output, + ?string $path = "", ?string $type = "", ?int $minSize = 0, ?int $maxSize = 0 ): void { try { /** @var Folder $userFolder **/ - $userFolder = $this->rootFolder->get($path); + $userFolder = $this->rootFolder->getUserFolder($user); + $pathList = $userFolder->get('/'.$path); - $files = $userFolder->getDirectoryListing(); + $files = $pathList->getDirectoryListing(); foreach ($files as $file) { /** @var Node $fileNode */ $fileNode = $file; @@ -151,13 +153,12 @@ protected function execute( InputInterface $input, OutputInterface $output ): int { - $inputPath = $input->getArgument("path"); - $inputPath = ltrim($inputPath, "path="); - [, $user] = explode("/", rtrim($inputPath, "/").'/', 4); + $user = $input->getArgument("user"); + $user = ltrim($user, "user="); + $path = $input->getOption("path"); $this->initTools($output); - $path = $inputPath ?: "/" . $user; if ($this->userManager->userExists($user)) { $output->writeln( @@ -165,8 +166,8 @@ protected function execute( ); $this->listFiles( $user, - $path, $output, + $path, $input->getOption("type"), (int) $input->getOption("minSize"), (int) $input->getOption("maxSize") From 860fb314eb9494971ea0a48e5b43d1c9f225bc28 Mon Sep 17 00:00:00 2001 From: yemkareems Date: Mon, 29 Jul 2024 12:29:39 +0530 Subject: [PATCH 11/13] fix: psalm ci fix Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index 695aec36cac81..778042663cb98 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -99,6 +99,7 @@ protected function listFiles( try { /** @var Folder $userFolder **/ $userFolder = $this->rootFolder->getUserFolder($user); + /** @var Folder $pathList **/ $pathList = $userFolder->get('/'.$path); $files = $pathList->getDirectoryListing(); @@ -155,7 +156,6 @@ protected function execute( ): int { $user = $input->getArgument("user"); $user = ltrim($user, "user="); - $path = $input->getOption("path"); $this->initTools($output); @@ -167,7 +167,7 @@ protected function execute( $this->listFiles( $user, $output, - $path, + $input->getOption("path"), $input->getOption("type"), (int) $input->getOption("minSize"), (int) $input->getOption("maxSize") From 49cac414c01e497f9006ab525dbc53562ddea029 Mon Sep 17 00:00:00 2001 From: yemkareems Date: Mon, 29 Jul 2024 13:26:10 +0530 Subject: [PATCH 12/13] fix: psalm ci fix Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index 778042663cb98..e36aae402796d 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -97,10 +97,9 @@ protected function listFiles( ?int $maxSize = 0 ): void { try { - /** @var Folder $userFolder **/ $userFolder = $this->rootFolder->getUserFolder($user); /** @var Folder $pathList **/ - $pathList = $userFolder->get('/'.$path); + $pathList = $userFolder->get('/' . $path); $files = $pathList->getDirectoryListing(); foreach ($files as $file) { @@ -167,7 +166,7 @@ protected function execute( $this->listFiles( $user, $output, - $input->getOption("path"), + (string) $input->getOption("path"), $input->getOption("type"), (int) $input->getOption("minSize"), (int) $input->getOption("maxSize") From 2dd5854d0958203f660328fdb3c2a6b3f9c362e0 Mon Sep 17 00:00:00 2001 From: yemkareems Date: Mon, 29 Jul 2024 18:16:00 +0530 Subject: [PATCH 13/13] fix: user_id made required argument and documentation updated accordingly Signed-off-by: yemkareems --- apps/files/lib/Command/ListFiles.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/apps/files/lib/Command/ListFiles.php b/apps/files/lib/Command/ListFiles.php index e36aae402796d..1a96d7a63226b 100644 --- a/apps/files/lib/Command/ListFiles.php +++ b/apps/files/lib/Command/ListFiles.php @@ -42,11 +42,11 @@ protected function configure(): void { parent::configure(); $this->setName("files:list") - ->setDescription("List filesystem in the path mentioned in path argument") + ->setDescription("List files of the user and filter by path, type, size optionally") ->addArgument( - "user", + "user_id", InputArgument::REQUIRED, - 'List the files and folder belonging to the user, eg occ files:list user="admin", the user being a required argument' + 'List the files and folder belonging to the user, eg occ files:list admin, the user_id being a required argument' ) ->addOption("path", "", InputArgument::OPTIONAL, "List files inside a particular path of the user, if not mentioned list from user's root directory") ->addOption("type", "", InputArgument::OPTIONAL, "Filter by type like application, image, video etc") @@ -153,12 +153,9 @@ protected function execute( InputInterface $input, OutputInterface $output ): int { - $user = $input->getArgument("user"); - $user = ltrim($user, "user="); - + $user = $input->getArgument("user_id"); $this->initTools($output); - if ($this->userManager->userExists($user)) { $output->writeln( "Starting list for user ($user)" @@ -166,7 +163,7 @@ protected function execute( $this->listFiles( $user, $output, - (string) $input->getOption("path"), + (string) $input->getOption("path") ? $input->getOption("path") : '', $input->getOption("type"), (int) $input->getOption("minSize"), (int) $input->getOption("maxSize") @@ -179,7 +176,6 @@ protected function execute( return self::FAILURE; } - $this->presentStats($input, $output); return self::SUCCESS; }