Skip to content

Commit e1adb98

Browse files
Merge pull request #62965 from nextcloud/backport/62925/stable34
[stable34] fix(trashbin): properly show deleted by for federated shares
2 parents f1266e6 + cf0fd72 commit e1adb98

4 files changed

Lines changed: 60 additions & 1 deletion

File tree

apps/files_trashbin/lib/Trash/LegacyTrashBackend.php

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use OCA\Files_Trashbin\Helper;
1212
use OCA\Files_Trashbin\Storage;
1313
use OCA\Files_Trashbin\Trashbin;
14+
use OCP\Federation\ICloudIdManager;
1415
use OCP\Files\FileInfo;
1516
use OCP\Files\Folder;
1617
use OCP\Files\IRootFolder;
@@ -26,6 +27,7 @@ class LegacyTrashBackend implements ITrashBackend {
2627
public function __construct(
2728
private IRootFolder $rootFolder,
2829
private IUserManager $userManager,
30+
private ICloudIdManager $cloudIdManager,
2931
) {
3032
}
3133

@@ -38,7 +40,7 @@ private function mapTrashItem(FileInfo $file, IUser $user, ?ITrashItem $parent =
3840
$originalLocation = $file->getName();
3941
}
4042
/** @psalm-suppress UndefinedInterfaceMethod */
41-
$deletedBy = $this->userManager->get($file['deletedBy']) ?? $parent?->getDeletedBy();
43+
$deletedBy = $this->resolveDeletedBy($file['deletedBy']) ?? $parent?->getDeletedBy();
4244
$trashFilename = Trashbin::getTrashFilename($file->getName(), $file->getMtime());
4345
return new TrashItem(
4446
$this,
@@ -125,4 +127,29 @@ public function getTrashNodeById(IUser $user, int $fileId) {
125127
return null;
126128
}
127129
}
130+
131+
/**
132+
* Resolve the user that deleted a trash item. Files deleted by a federated share
133+
* recipient only carry the recipient's remote cloud ID, which no local IUserManager
134+
* backend can resolve, so fall back to a display-only user for the cloud ID in that
135+
* case instead of leaving the item without an "Unknown" deleted by user.
136+
*/
137+
private function resolveDeletedBy(?string $uid): ?IUser {
138+
if (!$uid) {
139+
return null;
140+
}
141+
142+
$user = $this->userManager->get($uid);
143+
if ($user !== null) {
144+
return $user;
145+
}
146+
147+
try {
148+
$cloudId = $this->cloudIdManager->resolveCloudId($uid);
149+
} catch (\InvalidArgumentException $e) {
150+
return null;
151+
}
152+
153+
return $this->userManager->getFederatedUser($cloudId);
154+
}
128155
}

lib/private/User/Manager.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use OCP\Config\IUserConfig;
1313
use OCP\DB\QueryBuilder\IQueryBuilder;
1414
use OCP\EventDispatcher\IEventDispatcher;
15+
use OCP\Federation\ICloudId;
1516
use OCP\HintException;
1617
use OCP\ICache;
1718
use OCP\ICacheFactory;
@@ -894,4 +895,9 @@ public function getAvatarUrlDark(string $userId, int $size): string {
894895

895896
return $url;
896897
}
898+
899+
#[\Override]
900+
public function getFederatedUser(ICloudId $cloudId): IUser {
901+
return new LazyUser($cloudId->getDisplayId(), $this, $cloudId->getDisplayId());
902+
}
897903
}

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 from 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 \OCP\Federation\ICloudId $federatedUserId A cloud ID of the federated user
292+
* @return IUser
293+
* @since 35.0.0
294+
*/
295+
public function getFederatedUser(\OCP\Federation\ICloudId $cloudId): IUser;
285296
}

tests/lib/User/ManagerTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use OC\User\User;
1616
use OCP\Config\IUserConfig;
1717
use OCP\EventDispatcher\IEventDispatcher;
18+
use OCP\Federation\ICloudId;
1819
use OCP\ICache;
1920
use OCP\ICacheFactory;
2021
use OCP\IConfig;
@@ -741,4 +742,18 @@ public function testGetAvatarUrlLight(): void {
741742
public function testGetAvatarUrlDark(): void {
742743
$this->assertEquals('http://localhost/index.php/avatar/userid/64/dark', $this->manager->getAvatarUrlDark('userid', 64));
743744
}
745+
746+
public function testGetFederatedUser(): void {
747+
$userId = 'test@example.com';
748+
749+
$cloudId = $this->createMock(ICloudId::class);
750+
$cloudId->expects($this->exactly(2))
751+
->method('getDisplayId')
752+
->willReturn($userId);
753+
754+
$user = $this->manager->getFederatedUser($cloudId);
755+
756+
$this->assertEquals($userId, $user->getUID());
757+
$this->assertEquals($userId, $user->getDisplayName());
758+
}
744759
}

0 commit comments

Comments
 (0)