From 6b01382b085ef3f2195120f4c13744720a8f43c2 Mon Sep 17 00:00:00 2001 From: Florent Poinsaut Date: Tue, 11 Oct 2022 11:27:13 +0000 Subject: [PATCH] Add CSV output format Signed-off-by: Florent Poinsaut --- README.md | 18 +- composer.json | 3 +- composer.lock | 571 ++++++++++++++++++++++--------------- lib/Command/ListShares.php | 28 +- lib/Service/SharesList.php | 47 +++ 5 files changed, 407 insertions(+), 260 deletions(-) diff --git a/README.md b/README.md index c958e7a..a053978 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,18 @@ This app allows generating reports of shares on the system. - ## Usage -#### Command: -``` -./occ sharing:list [-u|--user [USER]] [-p|--path [PATH]] [-t|--token [TOKEN]] [-f|--filter [FILTER]] +### Command + +```sh +./occ sharing:list [-u|--user [USER]] [-p|--path [PATH]] [-t|--token [TOKEN]] [-f|--filter [FILTER]] [-o|--output FORMAT] ``` Without options, the command yields the unfiltered list of all shares.\ With options, the list is narrowed down using the filters set. -#### Options: +### Options * `-u [USER]` or `--user [USER]`\ List only shares of the given user. @@ -24,13 +24,14 @@ With options, the list is narrowed down using the filters set. * `-f [FILTER]` or `--filter [FILTER]`\ List only shares where the TYPE matches the argument.\ Possible values for the filter argument: {owner, initiator, recipient} - +* `-o FORMAT` or `--output FORMAT`\ + Set the output format (json or csv, default is json). ## Examples To better illustrate how the app work see the examples below: -### Example 1 +### Example 1 Listing all shares user0 is a participant in (be it owner, initiator or recipient): @@ -115,7 +116,8 @@ Listing all shares user0 is a participant in (be it owner, initiator or recipien ] ``` -### Example 3: +### Example 3 + List all info about all shares `./occ sharing:list` diff --git a/composer.json b/composer.json index 456c72c..45376fd 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,8 @@ "description": "3rdparty components for sharelisting", "license": "MIT", "require": { - "nikic/iter": "^2.2" + "nikic/iter": "^2.2", + "symfony/serializer": "^5.4" }, "require-dev": { "phpunit/phpunit": "^9", diff --git a/composer.lock b/composer.lock index 247c055..c9c367d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e962911f90e4296ff4f9b36c97b0f673", + "content-hash": "280059a3e5c545fce72e8e3f92894660", "packages": [ { "name": "nikic/iter", @@ -55,6 +55,341 @@ "source": "https://github.com/nikic/iter/tree/v2.2.0" }, "time": "2021-08-02T15:04:32+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "30885182c981ab175d4d034db0f6f469898070ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-10-20T20:35:02+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-03-04T08:16:47+00:00" + }, + { + "name": "symfony/serializer", + "version": "v5.4.12", + "source": { + "type": "git", + "url": "https://github.com/symfony/serializer.git", + "reference": "776fa3010f62b97a7119757a66596a654cd244d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/serializer/zipball/776fa3010f62b97a7119757a66596a654cd244d4", + "reference": "776fa3010f62b97a7119757a66596a654cd244d4", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "doctrine/annotations": "<1.12", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/dependency-injection": "<4.4", + "symfony/property-access": "<5.4", + "symfony/property-info": "<5.3.13", + "symfony/uid": "<5.3", + "symfony/yaml": "<4.4" + }, + "require-dev": { + "doctrine/annotations": "^1.12", + "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/filesystem": "^4.4|^5.0|^6.0", + "symfony/form": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/mime": "^4.4|^5.0|^6.0", + "symfony/property-access": "^5.4|^6.0", + "symfony/property-info": "^5.3.13|^6.0", + "symfony/uid": "^5.3|^6.0", + "symfony/validator": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0", + "symfony/var-exporter": "^4.4|^5.0|^6.0", + "symfony/yaml": "^4.4|^5.0|^6.0" + }, + "suggest": { + "psr/cache-implementation": "For using the metadata cache.", + "symfony/config": "For using the XML mapping loader.", + "symfony/mime": "For using a MIME type guesser within the DataUriNormalizer.", + "symfony/property-access": "For using the ObjectNormalizer.", + "symfony/property-info": "To deserialize relations.", + "symfony/var-exporter": "For using the metadata compiler.", + "symfony/yaml": "For using the default YAML mapping loader." + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Serializer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/serializer/tree/v5.4.12" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-08-26T10:32:10+00:00" } ], "packages-dev": [ @@ -3334,73 +3669,6 @@ ], "time": "2022-04-12T16:02:29+00:00" }, - { - "name": "symfony/deprecation-contracts", - "version": "v2.5.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-01-02T09:53:40+00:00" - }, { "name": "symfony/event-dispatcher", "version": "v5.4.3", @@ -3761,88 +4029,6 @@ ], "time": "2022-01-02T09:53:40+00:00" }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.25.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-10-20T20:35:02+00:00" - }, { "name": "symfony/polyfill-intl-grapheme", "version": "v1.25.0", @@ -4170,89 +4356,6 @@ ], "time": "2021-06-05T21:20:04+00:00" }, - { - "name": "symfony/polyfill-php80", - "version": "v1.25.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-03-04T08:16:47+00:00" - }, { "name": "symfony/polyfill-php81", "version": "v1.25.0", @@ -4746,5 +4849,5 @@ "platform-overrides": { "php": "7.4" }, - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } diff --git a/lib/Command/ListShares.php b/lib/Command/ListShares.php index a3a5970..52ac7dd 100644 --- a/lib/Command/ListShares.php +++ b/lib/Command/ListShares.php @@ -3,6 +3,7 @@ declare(strict_types=1); /** * @copyright Copyright (c) 2018 Roeland Jago Douma * + * @author Florent Poinsaut * @author Roeland Jago Douma * @author John Molakvoæ * @@ -88,29 +89,22 @@ class ListShares extends Base { 'f', InputOption::VALUE_OPTIONAL, 'Filter shares, possible values: owner, initiator, recipient, token, has-expiration, no-expiration' + ) + ->addOption( + 'output', + 'o', + InputOption::VALUE_OPTIONAL, + 'Output format (json or csv, default is json)', + 'json' ); - parent::configure(); } protected function execute(InputInterface $input, OutputInterface $output): int { $user = $input->getOption('user'); $path = $input->getOption('path'); $token = $input->getOption('token'); - $filter = $input->getOption('filter'); - - if ($filter === 'owner') { - $filter = SharesList::FILTER_OWNER; - } elseif ($filter === 'initiator') { - $filter = SharesList::FILTER_INITIATOR; - } else if ($filter === 'recipient') { - $filter = SharesList::FILTER_RECIPIENT; - } else if ($filter === 'has-expiration') { - $filter = SharesList::FILTER_HAS_EXPIRATION; - } else if ($filter === 'no-expiration') { - $filter = SharesList::FILTER_NO_EXPIRATION; - } else { - $filter = SharesList::FILTER_NONE; - } + $filter = $this->sharesList->filterStringToInt($input->getOption('filter')); + $outputOpt = $input->getOption('output'); if ($user === null && $token === null) { $shares = []; @@ -124,7 +118,7 @@ class ListShares extends Base { $shares = iter\toArray($this->sharesList->getFormattedShares($user, $filter, $path, $token)); } - $output->writeln(json_encode($shares, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); + $output->writeln($this->sharesList->getSerializedShares($shares, $outputOpt)); return 0; } } diff --git a/lib/Service/SharesList.php b/lib/Service/SharesList.php index d8de0c4..d7f8412 100644 --- a/lib/Service/SharesList.php +++ b/lib/Service/SharesList.php @@ -3,6 +3,7 @@ declare(strict_types=1); /** * @copyright Copyright (c) 2018 Roeland Jago Douma * + * @author Florent Poinsaut * @author Roeland Jago Douma * @author John Molakvoæ * @@ -34,6 +35,9 @@ use OCP\IUserManager; use OCP\Share; use OCP\Share\IManager as ShareManager; use OCP\Share\IShare; +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Encoder\CsvEncoder; +use Symfony\Component\Serializer\Serializer; class SharesList { @@ -281,4 +285,47 @@ class SharesList { return $data; } + + public function filterStringToInt(?string $filterString): int { + switch ($filterString) { + case 'owner': + $filter = SharesList::FILTER_OWNER; + break; + case 'initiator': + $filter = SharesList::FILTER_INITIATOR; + break; + case 'recipient': + $filter = SharesList::FILTER_RECIPIENT; + break; + case 'has-expiration': + $filter = SharesList::FILTER_HAS_EXPIRATION; + break; + case 'no-expiration': + $filter = SharesList::FILTER_NO_EXPIRATION; + break; + default: + $filter = SharesList::FILTER_NONE; + break; + } + + return $filter; + } + + public function getSerializedShares(array $shares, ?string $format = 'json'): string + { + switch ($format) { + case 'csv': + $encoders = [new CsvEncoder()]; + $context = []; + break; + default: + $encoders = [new JsonEncoder()]; + $format = 'json'; + $context = ['json_encode_options' => JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE]; + break; + } + + $serializer = new Serializer([], $encoders); + return $serializer->serialize($shares, $format, $context); + } }