Skip to content

Commit 116ea33

Browse files
committed
fix(trashbin): properly show deleted by for federated shares
Signed-off-by: Kent Delante <kent@delante.me> Assisted-by: ClaudeCode:claude-sonnet-5 When a remote user deletes a file in a federated share, the deleted by column in trashbin shows "Unknown" instead of the remote user. This fixes it so that it properly shows the remote user under the deleted by column.
1 parent 09c1a0b commit 116ea33

3 files changed

Lines changed: 51 additions & 1 deletion

File tree

‎apps/files_trashbin/lib/Trash/LegacyTrashBackend.php‎

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use OCA\Files_Trashbin\Helper;
1313
use OCA\Files_Trashbin\Storage;
1414
use OCA\Files_Trashbin\Trashbin;
15+
use OCP\Federation\ICloudIdManager;
1516
use OCP\Files\FileInfo;
1617
use OCP\Files\Folder;
1718
use OCP\Files\IRootFolder;
@@ -28,6 +29,7 @@ class LegacyTrashBackend implements ITrashBackend {
2829
public function __construct(
2930
private readonly IRootFolder $rootFolder,
3031
private readonly IUserManager $userManager,
32+
private readonly ICloudIdManager $cloudIdManager,
3133
) {
3234
}
3335

@@ -40,7 +42,7 @@ private function mapTrashItem(FileInfo $file, IUser $user, ?ITrashItem $parent =
4042
$originalLocation = $file->getName();
4143
}
4244
/** @psalm-suppress UndefinedInterfaceMethod */
43-
$deletedBy = $this->userManager->get($file['deletedBy']) ?? $parent?->getDeletedBy();
45+
$deletedBy = $this->resolveDeletedBy($file['deletedBy']) ?? $parent?->getDeletedBy();
4446
$trashFilename = Trashbin::getTrashFilename($file->getName(), $file->getMtime());
4547
return new TrashItem(
4648
$this,
@@ -127,4 +129,27 @@ public function getTrashNodeById(IUser $user, int $fileId): ?Node {
127129
return null;
128130
}
129131
}
132+
133+
/**
134+
* Resolve the user that deleted a trash item. Files deleted by a federated share
135+
* recipient only carry the recipient's remote cloud ID, which no local IUserManager
136+
* backend can resolve, so fall back to a display-only user for the cloud ID in that
137+
* case instead of leaving the item without an "Unknown" deleted by user.
138+
*/
139+
private function resolveDeletedBy(?string $uid): ?IUser {
140+
if (!$uid) {
141+
return null;
142+
}
143+
144+
$user = $this->userManager->get($uid);
145+
if ($user !== null) {
146+
return $user;
147+
}
148+
149+
if ($this->cloudIdManager->isValidCloudId($uid)) {
150+
return $this->userManager->getDisplayUser($uid);
151+
}
152+
153+
return null;
154+
}
130155
}

‎lib/private/User/Manager.php‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use OCP\Config\IUserConfig;
1414
use OCP\DB\QueryBuilder\IQueryBuilder;
1515
use OCP\EventDispatcher\IEventDispatcher;
16+
use OCP\Federation\ICloudIdManager;
1617
use OCP\HintException;
1718
use OCP\ICache;
1819
use OCP\ICacheFactory;
@@ -82,6 +83,7 @@ public function __construct(
8283
ICacheFactory $cacheFactory,
8384
private IEventDispatcher $eventDispatcher,
8485
private LoggerInterface $logger,
86+
private ICloudIdManager $cloudIdManager,
8587
) {
8688
$this->cache = new WithLocalCache($cacheFactory->createDistributed('user_backend_map'));
8789
$this->listen('\OC\User', 'postDelete', function (IUser $user): void {
@@ -883,4 +885,16 @@ public function getAvatarUrlLight(string $userId, int $size): string {
883885
public function getAvatarUrlDark(string $userId, int $size): string {
884886
return ($this->urlGenerator ??= Server::get(IURLGenerator::class))->linkToRouteAbsolute('core.avatar.getAvatarDark', ['userId' => $userId, 'size' => $size]);
885887
}
888+
889+
#[\Override]
890+
public function getDisplayUser(string $federatedUserId): ?IUser {
891+
try {
892+
$cloudId = $this->cloudIdManager->resolveCloudId($federatedUserId);
893+
} catch (\InvalidArgumentException $e) {
894+
$this->logger->debug($federatedUserId . ' is not a valid cloud id', ['exception' => $e]);
895+
return null;
896+
}
897+
898+
return new LazyUser($federatedUserId, $this, $cloudId->getDisplayId());
899+
}
886900
}

‎lib/public/IUserManager.php‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,4 +282,15 @@ public function getAvatarUrlLight(string $userId, int $size): string;
282282
* @since 34.0.0
283283
*/
284284
public function getAvatarUrlDark(string $userId, int $size): string;
285+
286+
/**
287+
* Get a read-only user for a cloud ID, for showing the display name of a remote
288+
* federation user (e.g. the "deleted by" user of a federated share) that has no
289+
* local account.
290+
*
291+
* @param $federatedUserId A cloud ID in the form of user@example.com
292+
* @return ?IUser
293+
* @since 35.0.0
294+
*/
295+
public function getDisplayUser(string $federatedUserId): ?IUser;
285296
}

0 commit comments

Comments
 (0)