Skip to content

Commit 7f71965

Browse files
authored
Merge pull request #4031 from nextcloud/enh/reference-link
implement reference provider
2 parents f3892fd + 20c3e4e commit 7f71965

5 files changed

Lines changed: 146 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ All notable changes to this project will be documented in this file.
2424
- Delete polls without the need to archive them first
2525
- Collapsible poll description
2626
- Transfer polls to another owner by the current poll owner or the administration
27+
- Added reference provider for link previews
2728

2829
## [7.4.1] - 2024-03-07
2930
### New

img/polls.svg

Lines changed: 3 additions & 3 deletions
Loading

lib/AppInfo/Application.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
use OCA\Polls\Model\Settings\SystemSettings;
5757
use OCA\Polls\Notification\Notifier;
5858
use OCA\Polls\Provider\SearchProvider;
59+
use OCA\Polls\Reference\PollReferenceProvider;
5960
use OCA\Polls\UserSession;
6061
use OCP\AppFramework\App;
6162
use OCP\AppFramework\Bootstrap\IBootContext;
@@ -127,6 +128,7 @@ public function register(IRegistrationContext $context): void {
127128

128129
$context->registerSearchProvider(SearchProvider::class);
129130
$context->registerDashboardWidget(PollWidget::class);
131+
$context->registerReferenceProvider(PollReferenceProvider::class);
130132
}
131133

132134
/**
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
/**
5+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
6+
* SPDX-License-Identifier: AGPL-3.0-or-later
7+
*/
8+
9+
namespace OCA\Polls\Reference;
10+
11+
use Exception;
12+
use OCA\Polls\AppInfo\Application;
13+
use OCA\Polls\Exceptions\ForbiddenException;
14+
use OCA\Polls\Exceptions\NotFoundException;
15+
use OCA\Polls\Service\PollService;
16+
use OCP\Collaboration\Reference\IReference;
17+
use OCP\Collaboration\Reference\IReferenceProvider;
18+
use OCP\Collaboration\Reference\Reference;
19+
use OCP\IL10N;
20+
use OCP\IURLGenerator;
21+
22+
class PollReferenceProvider implements IReferenceProvider {
23+
24+
/** @psalm-suppress PossiblyUnusedMethod */
25+
public function __construct(
26+
private PollService $pollService,
27+
private IURLGenerator $urlGenerator,
28+
private IL10N $l10n,
29+
private ?string $userId,
30+
) {
31+
}
32+
33+
/**
34+
* @inheritDoc
35+
*/
36+
public function matchReference(string $referenceText): bool {
37+
// validate url by checking if it contains a poll id; This is valid for internal polls
38+
return ($this->extractPollId($referenceText) !== 0);
39+
}
40+
41+
private function extractPollId($referenceText): int {
42+
$matchingUrls = [
43+
$this->urlGenerator->getAbsoluteURL('/apps/' . Application::APP_ID . '/vote'), // poll url base without index.php
44+
$this->urlGenerator->getAbsoluteURL('/index.php/apps/' . Application::APP_ID . '/vote'), // poll url base with index.php
45+
];
46+
47+
foreach ($matchingUrls as $url) {
48+
preg_match('/^' . preg_quote($url, '/') . '?\/([0-9]+)$/', $referenceText, $matches);
49+
if ($matches && count($matches) > 1) {
50+
return (int)$matches[1];
51+
}
52+
}
53+
return 0;
54+
}
55+
56+
57+
/**
58+
* @inheritDoc
59+
*/
60+
public function resolveReference(string $referenceText): ?IReference {
61+
if ($this->matchReference($referenceText)) {
62+
$pollId = $this->extractPollId($referenceText);
63+
64+
if ($pollId) {
65+
try {
66+
$poll = $this->pollService->get($pollId);
67+
$title = $this->l10n->t('Poll') . ': ' . $poll->getTitle();
68+
$description = $poll->getDescription();
69+
$ownerId = $poll->getUser()->getId();
70+
$ownerDisplayName = $poll->getUser()->getDisplayName();
71+
$url = $poll->getVoteUrl();
72+
73+
} catch (NotFoundException $e) {
74+
$pollId = 0;
75+
$title = $this->l10n->t('404 - Poll not found');
76+
$description = $this->l10n->t('This poll does not exist (anymore).');
77+
$ownerId = null;
78+
$ownerDisplayName = $this->l10n->t('No one.');
79+
$url = null;
80+
81+
} catch (ForbiddenException $e) {
82+
$owner = $this->pollService->getPollOwnerFromDB($pollId);
83+
$title = $this->l10n->t('Access denied');
84+
$ownerDisplayName = $owner->getDisplayName();
85+
$description = $this->l10n->t('You have no access to this poll. Contact %s if you think this is a mistake.', $ownerDisplayName);
86+
$ownerId = $owner->getId();
87+
$url = $referenceText;
88+
89+
} catch (Exception $e) {
90+
// skip the reference silently
91+
return null;
92+
}
93+
94+
$imageUrl = $this->urlGenerator->getAbsoluteURL(
95+
$this->urlGenerator->imagePath(Application::APP_ID, 'polls.svg')
96+
);
97+
98+
$reference = new Reference($referenceText);
99+
$reference->setTitle($title);
100+
$reference->setDescription($description ? $description : $this->l10n->t('No description available.'));
101+
$reference->setImageUrl($imageUrl);
102+
$reference->setRichObject(Application::APP_ID . '_poll_widget', [
103+
'id' => $pollId,
104+
'poll' => [
105+
'id' => $pollId,
106+
'title' => $title,
107+
'description' => $description ? $description : $this->l10n->t('No description available.'),
108+
'ownerDisplayName' => $ownerDisplayName,
109+
'ownerId' => $ownerId,
110+
'url' => $url,
111+
],
112+
]);
113+
return $reference;
114+
}
115+
}
116+
117+
return null;
118+
}
119+
120+
public function getCachePrefix(string $referenceId): string {
121+
$pollId = $this->extractPollId($referenceId);
122+
if ($pollId !== 0) {
123+
return (string)$pollId;
124+
}
125+
126+
return $referenceId;
127+
}
128+
129+
public function getCacheKey(string $referenceId): ?string {
130+
return $this->userId ?? '';
131+
}
132+
}

lib/Service/PollService.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,14 @@ public function get(int $pollId) {
178178
}
179179
}
180180

181+
public function getPollOwnerFromDB(int $pollId): UserBase {
182+
try {
183+
$poll = $this->pollMapper->find($pollId);
184+
return $poll->getUser();
185+
} catch (DoesNotExistException $e) {
186+
throw new NotFoundException('Poll not found');
187+
}
188+
}
181189
/**
182190
* Add poll
183191
*/

0 commit comments

Comments
 (0)