Skip to content

Commit 20b8b8b

Browse files
committed
feat(files_sharing): add support for the references
Signed-off-by: Kostiantyn Miakshyn <molodchick@gmail.com>
1 parent 52e109d commit 20b8b8b

4 files changed

Lines changed: 155 additions & 0 deletions

File tree

apps/files_sharing/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
'OCA\\Files_Sharing\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
9393
'OCA\\Files_Sharing\\OpenMetrics\\SharesCountMetric' => $baseDir . '/../lib/OpenMetrics/SharesCountMetric.php',
9494
'OCA\\Files_Sharing\\OrphanHelper' => $baseDir . '/../lib/OrphanHelper.php',
95+
'OCA\\Files_Sharing\\Reference\\ShareReferenceProvider' => $baseDir . '/../lib/Reference/ShareReferenceProvider.php',
9596
'OCA\\Files_Sharing\\Repair\\CleanupShareTarget' => $baseDir . '/../lib/Repair/CleanupShareTarget.php',
9697
'OCA\\Files_Sharing\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php',
9798
'OCA\\Files_Sharing\\Scanner' => $baseDir . '/../lib/Scanner.php',

apps/files_sharing/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class ComposerStaticInitFiles_Sharing
107107
'OCA\\Files_Sharing\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
108108
'OCA\\Files_Sharing\\OpenMetrics\\SharesCountMetric' => __DIR__ . '/..' . '/../lib/OpenMetrics/SharesCountMetric.php',
109109
'OCA\\Files_Sharing\\OrphanHelper' => __DIR__ . '/..' . '/../lib/OrphanHelper.php',
110+
'OCA\\Files_Sharing\\Reference\\ShareReferenceProvider' => __DIR__ . '/..' . '/../lib/Reference/ShareReferenceProvider.php',
110111
'OCA\\Files_Sharing\\Repair\\CleanupShareTarget' => __DIR__ . '/..' . '/../lib/Repair/CleanupShareTarget.php',
111112
'OCA\\Files_Sharing\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php',
112113
'OCA\\Files_Sharing\\Scanner' => __DIR__ . '/..' . '/../lib/Scanner.php',

apps/files_sharing/lib/AppInfo/Application.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use OCA\Files\Event\LoadAdditionalScriptsEvent;
1313
use OCA\Files\Event\LoadSidebar;
1414
use OCA\Files_Sharing\Capabilities;
15+
use OCA\Files_Sharing\Reference\ShareReferenceProvider;
1516
use OCA\Files_Sharing\Config\ConfigLexicon;
1617
use OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent;
1718
use OCA\Files_Sharing\External\Manager;
@@ -122,6 +123,8 @@ function () use ($c) {
122123
$context->registerEventListener(UserShareAccessUpdatedEvent::class, SharesUpdatedListener::class);
123124

124125
$context->registerConfigLexicon(ConfigLexicon::class);
126+
127+
$context->registerReferenceProvider(ShareReferenceProvider::class);
125128
}
126129

127130
public function boot(IBootContext $context): void {
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
9+
namespace OCA\Files_Sharing\Reference;
10+
11+
use OCP\Collaboration\Reference\ADiscoverableReferenceProvider;
12+
use OCP\Collaboration\Reference\IReference;
13+
use OCP\Collaboration\Reference\Reference;
14+
use OCP\Files\IMimeTypeDetector;
15+
use OCP\Files\InvalidPathException;
16+
use OCP\Files\NotFoundException;
17+
use OCP\Files\NotPermittedException;
18+
use OCP\IL10N;
19+
use OCP\IPreview;
20+
use OCP\IURLGenerator;
21+
use OCP\Share\Exceptions\ShareNotFound;
22+
use OCP\Share\IManager as ShareManager;
23+
24+
class ShareReferenceProvider extends ADiscoverableReferenceProvider {
25+
26+
public function __construct(
27+
private IL10N $l10n,
28+
private IURLGenerator $urlGenerator,
29+
private ShareManager $shareManager,
30+
private IMimeTypeDetector $mimeTypeDetector,
31+
private IPreview $previewManager,
32+
) {
33+
}
34+
35+
public function matchReference(string $referenceText): bool {
36+
return $this->getShareToken($referenceText) !== null;
37+
}
38+
39+
public function resolveReference(string $referenceText): ?IReference {
40+
if ($this->matchReference($referenceText)) {
41+
$reference = new Reference($referenceText);
42+
try {
43+
$this->fetchReference($reference);
44+
} catch (NotFoundException $e) {
45+
$reference->setRichObject('file', null);
46+
$reference->setAccessible(false);
47+
}
48+
return $reference;
49+
}
50+
51+
return null;
52+
}
53+
54+
public function getCachePrefix(string $referenceId): string {
55+
$token = $this->getShareToken($referenceId);
56+
return $token !== null ? $token : '';
57+
}
58+
59+
public function getCacheKey(string $referenceId): ?string {
60+
// Cache key depends on the share token
61+
return $this->getCachePrefix($referenceId);
62+
}
63+
64+
public function getId(): string {
65+
return 'files_sharing';
66+
}
67+
68+
public function getTitle(): string {
69+
return $this->l10n->t('Shared files');
70+
}
71+
72+
public function getOrder(): int {
73+
return 5;
74+
}
75+
76+
public function getIconUrl(): string {
77+
return $this->urlGenerator->imagePath('files_sharing', 'app.svg');
78+
}
79+
80+
private function getShareToken(string $referenceText): ?string {
81+
$start = $this->urlGenerator->getAbsoluteURL('/s/');
82+
$startIndex = $this->urlGenerator->getAbsoluteURL('/index.php/s/');
83+
84+
if (mb_strpos($referenceText, $start) === 0) {
85+
return $this->extractToken($referenceText, $start);
86+
}
87+
88+
if (mb_strpos($referenceText, $startIndex) === 0) {
89+
return $this->extractToken($referenceText, $startIndex);
90+
}
91+
92+
return null;
93+
}
94+
95+
private function extractToken(string $referenceText, string $prefix): ?string {
96+
$token = mb_substr($referenceText, mb_strlen($prefix));
97+
// Token might be followed by query parameters or path
98+
$parts = parse_url($referenceText);
99+
if (isset($parts['path'])) {
100+
$token = mb_substr($parts['path'], mb_strlen(parse_url($prefix, PHP_URL_PATH)));
101+
}
102+
// Remove any trailing slash or additional path components
103+
$token = strtok($token, '/');
104+
return $token !== '' ? $token : null;
105+
}
106+
107+
/**
108+
* @throws NotFoundException
109+
*/
110+
private function fetchReference(Reference $reference): void {
111+
$token = $this->getShareToken($reference->getId());
112+
if ($token === null) {
113+
throw new NotFoundException();
114+
}
115+
116+
try {
117+
$share = $this->shareManager->getShareByToken($token);
118+
$node = $share->getNode();
119+
120+
$reference->setTitle($node->getName());
121+
$reference->setDescription($node->getMimetype());
122+
$reference->setUrl($this->urlGenerator->getAbsoluteURL('/s/' . $token));
123+
124+
if ($this->previewManager->isMimeSupported($node->getMimeType())) {
125+
$reference->setImageUrl($this->urlGenerator->linkToRouteAbsolute('core.Preview.getPreviewByFileId', [
126+
'x' => 1600,
127+
'y' => 630,
128+
'fileId' => $node->getId(),
129+
]));
130+
} else {
131+
$fileTypeIconUrl = $this->mimeTypeDetector->mimeTypeIcon($node->getMimeType());
132+
$reference->setImageUrl($fileTypeIconUrl);
133+
}
134+
135+
$reference->setRichObject('file', [
136+
'id' => $node->getId(),
137+
'name' => $node->getName(),
138+
'size' => $node->getSize(),
139+
'path' => $node->getPath(),
140+
'link' => $reference->getUrl(),
141+
'mimetype' => $node->getMimetype(),
142+
'mtime' => $node->getMTime(),
143+
'preview-available' => $this->previewManager->isAvailable($node),
144+
'share-token' => $token,
145+
]);
146+
} catch (ShareNotFound|InvalidPathException|NotFoundException|NotPermittedException $e) {
147+
throw new NotFoundException(previous: $e);
148+
}
149+
}
150+
}

0 commit comments

Comments
 (0)