aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Appelman <robin@icewind.nl>2025-03-11 16:31:39 +0100
committerRobin Appelman <robin@icewind.nl>2025-03-28 16:47:07 +0100
commit2e9222a29ae3430725f8f20346ec1308e0de3263 (patch)
treee25b04422f99378d026ccd312684a70b6d42e7d1
parent28a2965a31aba25035ca8350684f1c4d26c30248 (diff)
downloadnextcloud-server-2e9222a29ae3430725f8f20346ec1308e0de3263.tar.gz
nextcloud-server-2e9222a29ae3430725f8f20346ec1308e0de3263.zip
feat: add getParentId to ICacheEntry
Signed-off-by: Robin Appelman <robin@icewind.nl>
-rw-r--r--apps/files_sharing/lib/Command/ListShares.php125
-rw-r--r--lib/private/Files/Cache/CacheEntry.php4
-rw-r--r--lib/public/Files/Cache/ICacheEntry.php8
3 files changed, 137 insertions, 0 deletions
diff --git a/apps/files_sharing/lib/Command/ListShares.php b/apps/files_sharing/lib/Command/ListShares.php
new file mode 100644
index 00000000000..40a4e8ed539
--- /dev/null
+++ b/apps/files_sharing/lib/Command/ListShares.php
@@ -0,0 +1,125 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * SPDX-FileCopyrightText: 2025 Robin Appelman <robin@icewind.nl>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCA\Files_Sharing\Command;
+
+use OC\Core\Command\Base;
+use OCP\Files\Folder;
+use OCP\Files\Node;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\IDBConnection;
+use OCP\Share\IManager;
+use OCP\Share\IShare;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class ListShares extends Base {
+ /** @var array{string, Node} */
+ private $fileCache = [];
+
+ public function __construct(
+ private readonly IDBConnection $connection,
+ private readonly IManager $shareManager,
+ private readonly IRootFolder $rootFolder,
+ ) {
+ parent::__construct();
+ }
+
+ protected function configure() {
+ parent::configure();
+ $this
+ ->setName('sharing:list')
+ ->setDescription('List available shares')
+ ->addOption('owner', null, InputOption::VALUE_REQUIRED, 'only show shares owned by a specific user')
+ ->addOption('recipient', null, InputOption::VALUE_REQUIRED, 'only show shares with a specific recipient')
+ ->addOption('by', null, InputOption::VALUE_REQUIRED, 'only show shares with by as specific user')
+ ->addOption('file', null, InputOption::VALUE_REQUIRED, 'only show shares of a specific file')
+ ->addOption('parent', null, InputOption::VALUE_REQUIRED, 'only show shares of files inside a specific folder')
+ ->addOption('recursive', null, InputOption::VALUE_NONE, 'also show shares nested deep inside the specified parent folder');
+ }
+
+ public function execute(InputInterface $input, OutputInterface $output): int {
+ $shares = iterator_to_array($this->shareManager->getAllShares());
+ $shares = array_filter($shares, function (IShare $share) use ($input) {
+ return $this->shouldShowShare($input, $share);
+ });
+ $data = array_map(function (IShare $share) {
+ return [
+ 'id' => $share->getId(),
+ 'file' => $share->getNodeId(),
+ 'owner' => $share->getShareOwner(),
+ 'recipient' => $share->getSharedWith(),
+ 'by' => $share->getSharedBy(),
+ ];
+ }, $shares);
+ if ($input->getOption('output') === self::OUTPUT_FORMAT_PLAIN) {
+ $this->writeTableInOutputFormat($input, $output, $data);
+ } else {
+ $this->writeArrayInOutputFormat($input, $output, $data);
+ }
+ }
+
+ private function getFileId(string $file): int {
+ if (is_numeric($file)) {
+ return $file;
+ }
+ return $this->getFile($file)->getId();
+ }
+
+ private function getFile(string $file): Node {
+ if (isset($this->fileCache[$file])) {
+ return $this->fileCache[$file];
+ }
+
+ if (is_numeric($file)) {
+ $node = $this->rootFolder->getFirstNodeById($file);
+ if (!$node) {
+ throw new NotFoundException("File with id $file not found");
+ }
+ } else {
+ $node = $this->rootFolder->get($file);
+ }
+ $this->fileCache[$file] = $node;
+ return $node;
+ }
+
+ private function shouldShowShare(InputInterface $input, IShare $share): bool {
+ if ($input->getOption('owner') && $share->getShareOwner() !== $input->getOption('owner')) {
+ return false;
+ }
+ if ($input->getOption('recipient') && $share->getSharedWith() !== $input->getOption('recipient')) {
+ return false;
+ }
+ if ($input->getOption('by') && $share->getSharedBy() !== $input->getOption('by')) {
+ return false;
+ }
+ if ($input->getOption('file') && $share->getNodeId() !== $this->getFileId($input->getOption('file'))) {
+ return false;
+ }
+ if ($input->getOption('parent')) {
+ $parent = $this->getFile($input->getOption('parent'));
+ if (!$parent instanceof Folder) {
+ throw new \Exception("Parent {$parent->getPath()} is not a folder");
+ }
+ $recursive = $input->getOption('recursive');
+ if (!$recursive) {
+ if ($share->getNodeCacheEntry()->getParent() !== $parent->getId()) {
+ return false;
+ }
+ } else {
+ $shareNode = $share->getNode();
+ if ($parent->getRelativePath($shareNode->getPath()) === null) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/lib/private/Files/Cache/CacheEntry.php b/lib/private/Files/Cache/CacheEntry.php
index e9417c8012a..ab5bae316f4 100644
--- a/lib/private/Files/Cache/CacheEntry.php
+++ b/lib/private/Files/Cache/CacheEntry.php
@@ -110,6 +110,10 @@ class CacheEntry implements ICacheEntry {
return $this->data['upload_time'] ?? null;
}
+ public function getParentId(): int {
+ return $this->data['parent'];
+ }
+
public function getData() {
return $this->data;
}
diff --git a/lib/public/Files/Cache/ICacheEntry.php b/lib/public/Files/Cache/ICacheEntry.php
index 11d91e74105..28e673071fd 100644
--- a/lib/public/Files/Cache/ICacheEntry.php
+++ b/lib/public/Files/Cache/ICacheEntry.php
@@ -161,4 +161,12 @@ interface ICacheEntry extends ArrayAccess {
* @since 25.0.0
*/
public function getUnencryptedSize(): int;
+
+ /**
+ * Get the file id of the parent folder
+ *
+ * @return int
+ * @since 32.0.0
+ */
+ public function getParentId(): int;
}