Skip to content

Commit 30aaefd

Browse files
committed
fix(Federation): Show some icon for federated users on shares
Signed-off-by: fenn-cs <fenn25.fn@gmail.com>
1 parent ad66160 commit 30aaefd

7 files changed

Lines changed: 60 additions & 15 deletions

File tree

apps/dav/lib/Connector/Sabre/FilesPlugin.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class FilesPlugin extends ServerPlugin {
8181
public const MOUNT_TYPE_PROPERTYNAME = '{http://nextcloud.org/ns}mount-type';
8282
public const MOUNT_ROOT_PROPERTYNAME = '{http://nextcloud.org/ns}is-mount-root';
8383
public const IS_ENCRYPTED_PROPERTYNAME = '{http://nextcloud.org/ns}is-encrypted';
84+
public const IS_FEDERATED_PROPERTYNAME = '{http://nextcloud.org/ns}is-federated';
8485
public const METADATA_ETAG_PROPERTYNAME = '{http://nextcloud.org/ns}metadata_etag';
8586
public const UPLOAD_TIME_PROPERTYNAME = '{http://nextcloud.org/ns}upload_time';
8687
public const CREATION_TIME_PROPERTYNAME = '{http://nextcloud.org/ns}creation_time';
@@ -149,6 +150,7 @@ public function initialize(Server $server) {
149150
$server->protectedProperties[] = self::HAS_PREVIEW_PROPERTYNAME;
150151
$server->protectedProperties[] = self::MOUNT_TYPE_PROPERTYNAME;
151152
$server->protectedProperties[] = self::IS_ENCRYPTED_PROPERTYNAME;
153+
$server->protectedProperties[] = self::IS_FEDERATED_PROPERTYNAME;
152154
$server->protectedProperties[] = self::SHARE_NOTE;
153155

154156
// normally these cannot be changed (RFC4918), but we want them modifiable through PROPPATCH
@@ -413,6 +415,10 @@ public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node)
413415
$propFind->handle(self::DISPLAYNAME_PROPERTYNAME, function () use ($node) {
414416
return $node->getName();
415417
});
418+
419+
$propFind->handle(self::IS_FEDERATED_PROPERTYNAME, function () use ($node) {
420+
return $node->getOwner()->isFederated() ? 'true' : 'false';
421+
});
416422
}
417423

418424
if ($node instanceof \OCA\DAV\Connector\Sabre\File) {

apps/files/src/init.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,6 @@ registerPreviewServiceWorker()
7070

7171
registerDavProperty('nc:hidden', { nc: 'http://nextcloud.org/ns' })
7272
registerDavProperty('nc:is-mount-root', { nc: 'http://nextcloud.org/ns' })
73+
registerDavProperty('nc:is-federated', { nc: 'http://nextcloud.org/ns' })
7374

7475
initLivePhotos()

apps/files_sharing/src/actions/sharingStatusAction.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,25 +29,13 @@ import LinkSvg from '@mdi/svg/svg/link.svg?raw'
2929
import CircleSvg from '../../../../core/img/apps/circles.svg?raw'
3030

3131
import { action as sidebarAction } from '../../../files/src/actions/sidebarAction'
32-
import { generateUrl } from '@nextcloud/router'
3332
import { getCurrentUser } from '@nextcloud/auth'
33+
import { generateAvatarSvg } from '../utils/AccountIcon.ts'
3434

3535
import './sharingStatusAction.scss'
3636

37-
const isDarkMode = window?.matchMedia?.('(prefers-color-scheme: dark)')?.matches === true
38-
|| document.querySelector('[data-themes*=dark]') !== null
39-
40-
const generateAvatarSvg = (userId: string, isGuest = false) => {
41-
const url = isDarkMode ? '/avatar/{userId}/32/dark' : '/avatar/{userId}/32'
42-
const avatarUrl = generateUrl(isGuest ? url : url + '?guestFallback=true', { userId })
43-
return `<svg width="32" height="32" viewBox="0 0 32 32"
44-
xmlns="http://www.w3.org/2000/svg" class="sharing-status__avatar">
45-
<image href="${avatarUrl}" height="32" width="32" />
46-
</svg>`
47-
}
48-
4937
const isExternal = (node: Node) => {
50-
return node.attributes.remote_id !== undefined
38+
return node.attributes?.['is-federated'] ?? false
5139
}
5240

5341
export const action = new FileAction({
@@ -110,7 +98,8 @@ export const action = new FileAction({
11098

11199
const ownerId = node?.attributes?.['owner-id']
112100
if (ownerId && (ownerId !== getCurrentUser()?.uid || isExternal(node))) {
113-
return generateAvatarSvg(ownerId, isExternal(node))
101+
const sanitizeId = (id: string) => id.replace(/[^a-zA-Z0-9._%+-@]+/g, '').replace(/\//g, '')
102+
return generateAvatarSvg(sanitizeId(ownerId), isExternal(node))
114103
}
115104

116105
return AccountPlusSvg
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*!
2+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
import { generateUrl } from '@nextcloud/router'
6+
7+
const isDarkMode = window?.matchMedia?.('(prefers-color-scheme: dark)')?.matches === true
8+
|| document.querySelector('[data-themes*=dark]') !== null
9+
10+
export const generateAvatarSvg = (userId: string, isExternalUser = false) => {
11+
console.log('User ID:', userId)
12+
const url = isDarkMode ? '/avatar/{userId}/32/dark' : '/avatar/{userId}/32'
13+
const avatarUrl = generateUrl(isExternalUser ? url + '?guestFallback=true' : url, { userId })
14+
return `<svg width="32" height="32" viewBox="0 0 32 32"
15+
xmlns="http://www.w3.org/2000/svg" class="sharing-status__avatar">
16+
<image href="${avatarUrl}" height="32" width="32" />
17+
</svg>`
18+
}

lib/private/User/LazyUser.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ private function getUser(): IUser {
5151
$this->user = $this->userManager->get($this->uid);
5252
}
5353
}
54+
55+
if ($this->user === null) {
56+
throw new \Exception('User not found');
57+
}
58+
5459
/** @var IUser */
5560
$user = $this->user;
5661
return $user;
@@ -167,4 +172,16 @@ public function getManagerUids(): array {
167172
public function setManagerUids(array $uids): void {
168173
$this->getUser()->setManagerUids($uids);
169174
}
175+
176+
public function isFederated(): bool {
177+
try {
178+
// If getUser succeeds then user is definitely not federated
179+
// This could fail for other reasons (especially a race condition where a user is deleted)
180+
// But it's what we have now
181+
$this->getUser();
182+
return false;
183+
} catch (\Exception $e) {
184+
return true;
185+
}
186+
}
170187
}

lib/private/User/User.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,4 +618,10 @@ public function triggerChange($feature, $value = null, $oldValue = null) {
618618
$this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
619619
}
620620
}
621+
622+
public function isFederated(): bool {
623+
// Federated users are instantiated via LazyUser
624+
// DAV also only uses LazyUser
625+
return false;
626+
}
621627
}

lib/public/IUser.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,4 +287,12 @@ public function getManagerUids(): array;
287287
* @since 27.0.0
288288
*/
289289
public function setManagerUids(array $uids): void;
290+
291+
/**
292+
* Check if the user is federated (from another server)
293+
*
294+
* @return bool
295+
* @since 28.0.11
296+
*/
297+
public function isFederated(): bool;
290298
}

0 commit comments

Comments
 (0)