Skip to content

Commit f15ed55

Browse files
committed
[wip] add command for getting user file information
Signed-off-by: Robin Appelman <robin@icewind.nl>
1 parent 579d37a commit f15ed55

4 files changed

Lines changed: 324 additions & 102 deletions

File tree

core/Command/Info/File.php

Lines changed: 6 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,9 @@
55
namespace OC\Core\Command\Info;
66

77
use OC\Files\ObjectStore\ObjectStoreStorage;
8-
use OCA\Circles\MountManager\CircleMount;
98
use OCA\Files_External\Config\ExternalMountPoint;
10-
use OCA\Files_Sharing\SharedMount;
119
use OCA\GroupFolders\Mount\GroupMountPoint;
12-
use OCP\Constants;
1310
use OCP\Files\Config\IUserMountCache;
14-
use OCP\Files\FileInfo;
1511
use OCP\Files\Folder;
1612
use OCP\Files\IHomeStorage;
1713
use OCP\Files\IRootFolder;
@@ -20,7 +16,6 @@
2016
use OCP\Files\NotFoundException;
2117
use OCP\IL10N;
2218
use OCP\L10N\IFactory;
23-
use OCP\Share\IShare;
2419
use OCP\Util;
2520
use Symfony\Component\Console\Command\Command;
2621
use Symfony\Component\Console\Input\InputArgument;
@@ -32,11 +27,13 @@ class File extends Command {
3227
private IRootFolder $rootFolder;
3328
private IUserMountCache $userMountCache;
3429
private IL10N $l10n;
30+
private FileUtils $fileUtils;
3531

36-
public function __construct(IRootFolder $rootFolder, IUserMountCache $userMountCache, IFactory $l10nFactory) {
32+
public function __construct(IRootFolder $rootFolder, IUserMountCache $userMountCache, IFactory $l10nFactory, FileUtils $fileUtils) {
3733
$this->rootFolder = $rootFolder;
3834
$this->userMountCache = $userMountCache;
3935
$this->l10n = $l10nFactory->get("files");
36+
$this->fileUtils = $fileUtils;
4037
parent::__construct();
4138
}
4239

@@ -83,16 +80,16 @@ public function execute(InputInterface $input, OutputInterface $output): int {
8380
}
8481
$this->outputStorageDetails($node->getMountPoint(), $node, $output);
8582

86-
$filesPerUser = $this->getFilesByUser($node);
83+
$filesPerUser = $this->fileUtils->getFilesByUser($node);
8784
$output->writeln("");
8885
$output->writeln("The following users have access to the file");
8986
$output->writeln("");
9087
foreach ($filesPerUser as $user => $files) {
9188
$output->writeln("$user:");
9289
foreach ($files as $userFile) {
93-
$output->writeln(" " . $userFile->getPath() . ": " . $this->formatPermissions($userFile->getType(), $userFile->getPermissions()));
90+
$output->writeln(" " . $userFile->getPath() . ": " . $this->fileUtils->formatPermissions($userFile->getType(), $userFile->getPermissions()));
9491
$mount = $userFile->getMountPoint();
95-
$output->writeln(" " . $this->formatMountType($mount));
92+
$output->writeln(" " . $this->fileUtils->formatMountType($mount));
9693
}
9794
}
9895

@@ -121,99 +118,6 @@ private function getNode(string $fileInput): ?Node {
121118
}
122119
}
123120

124-
/**
125-
* @param FileInfo $file
126-
* @return array<string, Node[]>
127-
* @throws \OCP\Files\NotPermittedException
128-
* @throws \OC\User\NoUserException
129-
*/
130-
private function getFilesByUser(FileInfo $file): array {
131-
$id = $file->getId();
132-
if (!$id) {
133-
return [];
134-
}
135-
136-
$mounts = $this->userMountCache->getMountsForFileId($id);
137-
$result = [];
138-
foreach ($mounts as $mount) {
139-
if (isset($result[$mount->getUser()->getUID()])) {
140-
continue;
141-
}
142-
143-
$userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID());
144-
$result[$mount->getUser()->getUID()] = $userFolder->getById($id);
145-
}
146-
147-
return $result;
148-
}
149-
150-
private function formatPermissions(string $type, int $permissions): string {
151-
if ($permissions == Constants::PERMISSION_ALL || ($type === 'file' && $permissions == (Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE))) {
152-
return "full permissions";
153-
}
154-
155-
$perms = [];
156-
$allPerms = [Constants::PERMISSION_READ => "read", Constants::PERMISSION_UPDATE => "update", Constants::PERMISSION_CREATE => "create", Constants::PERMISSION_DELETE => "delete", Constants::PERMISSION_SHARE => "share"];
157-
foreach ($allPerms as $perm => $name) {
158-
if (($permissions & $perm) === $perm) {
159-
$perms[] = $name;
160-
}
161-
}
162-
163-
return implode(", ", $perms);
164-
}
165-
166-
/**
167-
* @psalm-suppress UndefinedClass
168-
* @psalm-suppress UndefinedInterfaceMethod
169-
*/
170-
private function formatMountType(IMountPoint $mountPoint): string {
171-
$storage = $mountPoint->getStorage();
172-
if ($storage && $storage->instanceOfStorage(IHomeStorage::class)) {
173-
return "home storage";
174-
} elseif ($mountPoint instanceof SharedMount) {
175-
$share = $mountPoint->getShare();
176-
$shares = $mountPoint->getGroupedShares();
177-
$sharedBy = array_map(function (IShare $share) {
178-
$shareType = $this->formatShareType($share);
179-
if ($shareType) {
180-
return $share->getSharedBy() . " (via " . $shareType . " " . $share->getSharedWith() . ")";
181-
} else {
182-
return $share->getSharedBy();
183-
}
184-
}, $shares);
185-
$description = "shared by " . implode(', ', $sharedBy);
186-
if ($share->getSharedBy() !== $share->getShareOwner()) {
187-
$description .= " owned by " . $share->getShareOwner();
188-
}
189-
return $description;
190-
} elseif ($mountPoint instanceof GroupMountPoint) {
191-
return "groupfolder " . $mountPoint->getFolderId();
192-
} elseif ($mountPoint instanceof ExternalMountPoint) {
193-
return "external storage " . $mountPoint->getStorageConfig()->getId();
194-
} elseif ($mountPoint instanceof CircleMount) {
195-
return "circle";
196-
}
197-
return get_class($mountPoint);
198-
}
199-
200-
private function formatShareType(IShare $share): ?string {
201-
switch ($share->getShareType()) {
202-
case IShare::TYPE_GROUP:
203-
return "group";
204-
case IShare::TYPE_CIRCLE:
205-
return "circle";
206-
case IShare::TYPE_DECK:
207-
return "deck";
208-
case IShare::TYPE_ROOM:
209-
return "room";
210-
case IShare::TYPE_USER:
211-
return null;
212-
default:
213-
return "Unknown (".$share->getShareType().")";
214-
}
215-
}
216-
217121
/**
218122
* @psalm-suppress UndefinedClass
219123
* @psalm-suppress UndefinedInterfaceMethod

core/Command/Info/FileUtils.php

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* @copyright Copyright (c) 2023 Robin Appelman <robin@icewind.nl>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
namespace OC\Core\Command\Info;
25+
26+
27+
use OC\Files\SetupManager;
28+
use OCA\Circles\MountManager\CircleMount;
29+
use OCA\Files_External\Config\ExternalMountPoint;
30+
use OCA\Files_Sharing\SharedMount;
31+
use OCA\GroupFolders\Mount\GroupMountPoint;
32+
use OCP\Constants;
33+
use OCP\Files\Config\IUserMountCache;
34+
use OCP\Files\FileInfo;
35+
use OCP\Files\IHomeStorage;
36+
use OCP\Files\IRootFolder;
37+
use OCP\Files\Mount\IMountManager;
38+
use OCP\Files\Mount\IMountPoint;
39+
use OCP\Files\Node;
40+
use OCP\IUser;
41+
use OCP\Share\IShare;
42+
use OCP\Util;
43+
use Symfony\Component\Console\Output\OutputInterface;
44+
use OCP\Files\Folder;
45+
46+
class FileUtils {
47+
private IRootFolder $rootFolder;
48+
private IUserMountCache $userMountCache;
49+
private IMountManager $mountManager;
50+
private SetupManager $setupManager;
51+
52+
public function __construct(
53+
IRootFolder $rootFolder,
54+
IUserMountCache $userMountCache,
55+
IMountManager $mountManager,
56+
SetupManager $setupManager
57+
) {
58+
$this->rootFolder = $rootFolder;
59+
$this->userMountCache = $userMountCache;
60+
$this->mountManager = $mountManager;
61+
$this->setupManager = $setupManager;
62+
}
63+
64+
/**
65+
* @param FileInfo $file
66+
* @return array<string, Node[]>
67+
* @throws \OCP\Files\NotPermittedException
68+
* @throws \OC\User\NoUserException
69+
*/
70+
public function getFilesByUser(FileInfo $file): array {
71+
$id = $file->getId();
72+
if (!$id) {
73+
return [];
74+
}
75+
76+
$mounts = $this->userMountCache->getMountsForFileId($id);
77+
$result = [];
78+
foreach ($mounts as $mount) {
79+
if (isset($result[$mount->getUser()->getUID()])) {
80+
continue;
81+
}
82+
83+
$userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID());
84+
$result[$mount->getUser()->getUID()] = $userFolder->getById($id);
85+
}
86+
87+
return $result;
88+
}
89+
90+
public function formatPermissions(string $type, int $permissions): string {
91+
if ($permissions == Constants::PERMISSION_ALL || ($type === 'file' && $permissions == (Constants::PERMISSION_ALL - Constants::PERMISSION_CREATE))) {
92+
return "full permissions";
93+
}
94+
95+
$perms = [];
96+
$allPerms = [Constants::PERMISSION_READ => "read", Constants::PERMISSION_UPDATE => "update", Constants::PERMISSION_CREATE => "create", Constants::PERMISSION_DELETE => "delete", Constants::PERMISSION_SHARE => "share"];
97+
foreach ($allPerms as $perm => $name) {
98+
if (($permissions & $perm) === $perm) {
99+
$perms[] = $name;
100+
}
101+
}
102+
103+
return implode(", ", $perms);
104+
}
105+
106+
/**
107+
* @psalm-suppress UndefinedClass
108+
* @psalm-suppress UndefinedInterfaceMethod
109+
*/
110+
public function formatMountType(IMountPoint $mountPoint): string {
111+
$storage = $mountPoint->getStorage();
112+
if ($storage && $storage->instanceOfStorage(IHomeStorage::class)) {
113+
return "home storage";
114+
} elseif ($mountPoint instanceof SharedMount) {
115+
$share = $mountPoint->getShare();
116+
$shares = $mountPoint->getGroupedShares();
117+
$sharedBy = array_map(function (IShare $share) {
118+
$shareType = $this->formatShareType($share);
119+
if ($shareType) {
120+
return $share->getSharedBy() . " (via " . $shareType . " " . $share->getSharedWith() . ")";
121+
} else {
122+
return $share->getSharedBy();
123+
}
124+
}, $shares);
125+
$description = "shared by " . implode(', ', $sharedBy);
126+
if ($share->getSharedBy() !== $share->getShareOwner()) {
127+
$description .= " owned by " . $share->getShareOwner();
128+
}
129+
return $description;
130+
} elseif ($mountPoint instanceof GroupMountPoint) {
131+
return "groupfolder " . $mountPoint->getFolderId();
132+
} elseif ($mountPoint instanceof ExternalMountPoint) {
133+
return "external storage " . $mountPoint->getStorageConfig()->getId();
134+
} elseif ($mountPoint instanceof CircleMount) {
135+
return "circle";
136+
}
137+
return get_class($mountPoint);
138+
}
139+
140+
public function formatShareType(IShare $share): ?string {
141+
switch ($share->getShareType()) {
142+
case IShare::TYPE_GROUP:
143+
return "group";
144+
case IShare::TYPE_CIRCLE:
145+
return "circle";
146+
case IShare::TYPE_DECK:
147+
return "deck";
148+
case IShare::TYPE_ROOM:
149+
return "room";
150+
case IShare::TYPE_USER:
151+
return null;
152+
default:
153+
return "Unknown (" . $share->getShareType() . ")";
154+
}
155+
}
156+
157+
/**
158+
* @param IUser $user
159+
* @return IMountPoint[]
160+
*/
161+
public function getMountsForUser(IUser $user): array {
162+
$this->setupManager->setupForUser($user);
163+
$prefix = "/" . $user->getUID();
164+
return array_filter($this->mountManager->getAll(), function (IMountPoint $mount) use ($prefix) {
165+
return str_starts_with($mount->getMountPoint(), $prefix);
166+
});
167+
}
168+
169+
/**
170+
* Print out the largest count($sizeLimits) files in the directory tree
171+
*
172+
* @param OutputInterface $output
173+
* @param Folder $node
174+
* @param string $prefix
175+
* @param array $sizeLimits largest items that are still in the queue to be printed, ordered ascending
176+
* @return void
177+
*/
178+
public function outputLargeFilesTree(
179+
OutputInterface $output,
180+
Folder $node,
181+
string $prefix,
182+
array &$sizeLimits
183+
): int {
184+
$count = 0;
185+
$children = $node->getDirectoryListing();
186+
usort($children, function (Node $a, Node $b) {
187+
return $b->getSize() <=> $a->getSize();
188+
});
189+
foreach ($children as $i => $child) {
190+
if (count($sizeLimits) === 0 || $child->getSize() < $sizeLimits[0]) {
191+
return $count;
192+
}
193+
array_shift($sizeLimits);
194+
$count += 1;
195+
196+
// var_dump(implode(", ", $sizeLimits));
197+
/** @var Node $child */
198+
$output->writeln("$prefix- " . $child->getName() . ": " . Util::humanFileSize($child->getSize()));
199+
if ($child instanceof Folder) {
200+
$recurseSizeLimits = $sizeLimits;
201+
for ($j = 0; $j < count($recurseSizeLimits); $j++) {
202+
$nextChildSize = (int)$children[$i + $j]?->getSize();
203+
if ($nextChildSize > $recurseSizeLimits[0]) {
204+
array_shift($recurseSizeLimits);
205+
$recurseSizeLimits[] = $nextChildSize;
206+
}
207+
}
208+
sort($recurseSizeLimits);
209+
$recurseCount = $this->outputLargeFilesTree($output, $child, $prefix . " ", $recurseSizeLimits);
210+
$sizeLimits = array_slice($sizeLimits, $recurseCount);
211+
$count += $recurseCount;
212+
}
213+
}
214+
}
215+
}

0 commit comments

Comments
 (0)