Skip to content

Commit 797c686

Browse files
authored
Merge pull request #7499 from nextcloud/chore/share-provide-get-users
chore/share provide get users
2 parents d8a73ec + 75172a4 commit 797c686

11 files changed

Lines changed: 150 additions & 19 deletions

File tree

lib/Activity/Filter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public function getIcon(): string {
6161
* @return string[] An array of allowed apps from which activities should be displayed
6262
* @since 11.0.0
6363
*/
64-
public function filterTypes(array $types): array {
64+
public function filterTypes($types): array {
6565
return array_merge($types, ['deck_comment']);
6666
}
6767

lib/AppInfo/Application.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use OCA\Deck\Event\CardUpdatedEvent;
2828
use OCA\Deck\Event\SessionClosedEvent;
2929
use OCA\Deck\Event\SessionCreatedEvent;
30+
use OCA\Deck\Listeners\AclCreatedRemovedListener;
3031
use OCA\Deck\Listeners\BeforeTemplateRenderedListener;
3132
use OCA\Deck\Listeners\CommentEventListener;
3233
use OCA\Deck\Listeners\FullTextSearchEventListener;
@@ -134,6 +135,10 @@ public function register(IRegistrationContext $context): void {
134135

135136
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
136137

138+
// Event listening to emit UserShareAccessUpdatedEvent for files_sharing
139+
$context->registerEventListener(AclCreatedEvent::class, AclCreatedRemovedListener::class);
140+
$context->registerEventListener(AclDeletedEvent::class, AclCreatedRemovedListener::class);
141+
137142
// Event listening for full text search indexing
138143
$context->registerEventListener(CardCreatedEvent::class, FullTextSearchEventListener::class);
139144
$context->registerEventListener(CardUpdatedEvent::class, FullTextSearchEventListener::class);

lib/Db/User.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace OCA\Deck\Db;
99

10+
use OCP\IUser;
1011
use OCP\IUserManager;
1112

1213
class User extends RelationalObject {
@@ -18,19 +19,23 @@ public function __construct($uid, IUserManager $userManager) {
1819
});
1920
}
2021

21-
public function getObjectSerialization() {
22+
public function getObjectSerialization(): array {
2223
return [
2324
'uid' => $this->getObject()->getUID(),
2425
'displayname' => $this->getDisplayName(),
2526
'type' => Acl::PERMISSION_TYPE_USER
2627
];
2728
}
2829

29-
public function getUID() {
30+
public function getUID(): string {
3031
return $this->getPrimaryKey();
3132
}
3233

33-
public function getDisplayName() {
34+
public function getDisplayName(): ?string {
3435
return $this->userManager->getDisplayName($this->getPrimaryKey());
3536
}
37+
38+
public function getUserObject(): IUser {
39+
return $this->getObject();
40+
}
3641
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/**
4+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-License-Identifier: AGPL-3.0-or-later
6+
*/
7+
namespace OCA\Deck\Listeners;
8+
9+
use OCA\Circles\Model\Member;
10+
use OCA\Deck\Event\AclCreatedEvent;
11+
use OCA\Deck\Event\AclDeletedEvent;
12+
use OCA\Deck\Service\CirclesService;
13+
use OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent;
14+
use OCP\EventDispatcher\Event;
15+
use OCP\EventDispatcher\IEventDispatcher;
16+
use OCP\EventDispatcher\IEventListener;
17+
use OCP\IGroupManager;
18+
use OCP\IUserManager;
19+
use OCP\Share\IShare;
20+
21+
/** @template-implements IEventListener<Event|AclDeletedEvent|AclCreatedEvent> */
22+
class AclCreatedRemovedListener implements IEventListener {
23+
public function __construct(
24+
private CirclesService $circlesService,
25+
private IGroupManager $groupManager,
26+
private IEventDispatcher $eventDispatcher,
27+
private IUserManager $userManager,
28+
) {
29+
}
30+
31+
public function handle(Event $event): void {
32+
if (!$event instanceof AclDeletedEvent && !$event instanceof AclCreatedEvent) {
33+
return;
34+
}
35+
36+
if (!class_exists(UserShareAccessUpdatedEvent::class)) {
37+
return;
38+
}
39+
40+
$acl = $event->getAcl();
41+
switch ($acl->getType()) {
42+
case IShare::TYPE_GROUP:
43+
$group = $this->groupManager->get($acl->getParticipant());
44+
foreach ($group->getUsers() as $user) {
45+
$this->eventDispatcher->dispatchTyped(new UserShareAccessUpdatedEvent($user));
46+
}
47+
break;
48+
case IShare::TYPE_CIRCLE:
49+
if (!$this->circlesService->isCirclesEnabled()) {
50+
return;
51+
}
52+
$circle = $this->circlesService->getCircle($acl->getParticipant());
53+
$members = array_filter($circle->getInheritedMembers(), static function (Member $member) {
54+
return $member->getUserType() === Member::TYPE_USER;
55+
});
56+
foreach ($members as $member) {
57+
$user = $this->userManager->get($member->getUserId());
58+
$this->eventDispatcher->dispatchTyped(new UserShareAccessUpdatedEvent($user));
59+
}
60+
break;
61+
default:
62+
$user = $this->userManager->get($acl->getParticipant());
63+
$this->eventDispatcher->dispatchTyped(new UserShareAccessUpdatedEvent($user));
64+
break;
65+
}
66+
}
67+
}

lib/Notification/NotificationHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public function sendCardDuedate(Card $card): void {
107107
$notification = $this->notificationManager->createNotification();
108108
$notification
109109
->setApp('deck')
110-
->setUser((string)$user->getUID())
110+
->setUser($user->getUID())
111111
->setObject('card', (string)$card->getId())
112112
->setSubject('card-overdue', [
113113
$card->getTitle(), $board->getTitle()

lib/Service/BoardService.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace OCA\Deck\Service;
99

10+
use OC\User\LazyUser;
1011
use OCA\Deck\Activity\ActivityManager;
1112
use OCA\Deck\Activity\ChangeSet;
1213
use OCA\Deck\AppInfo\Application;
@@ -34,6 +35,7 @@
3435
use OCA\Deck\NoPermissionException;
3536
use OCA\Deck\Notification\NotificationHelper;
3637
use OCA\Deck\Validators\BoardServiceValidator;
38+
use OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent;
3739
use OCP\AppFramework\Db\DoesNotExistException;
3840
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
3941
use OCP\DB\Exception as DbException;
@@ -42,6 +44,7 @@
4244
use OCP\IDBConnection;
4345
use OCP\IL10N;
4446
use OCP\IURLGenerator;
47+
use OCP\IUserManager;
4548
use OCP\Server;
4649
use Psr\Container\ContainerExceptionInterface;
4750
use Psr\Container\NotFoundExceptionInterface;
@@ -69,6 +72,7 @@ public function __construct(
6972
private IDBConnection $connection,
7073
private BoardServiceValidator $boardServiceValidator,
7174
private SessionMapper $sessionMapper,
75+
private IUserManager $userManager,
7276
private ?string $userId,
7377
) {
7478
}
@@ -235,6 +239,15 @@ public function delete(int $id): Board {
235239
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $board, ActivityManager::SUBJECT_BOARD_DELETE);
236240
$this->changeHelper->boardChanged($board->getId());
237241

242+
if (class_exists(UserShareAccessUpdatedEvent::class)) {
243+
$acls = $this->aclMapper->findAll($id);
244+
foreach ($acls as $acl) {
245+
$user = new LazyUser($acl->getParticipant(), $this->userManager);
246+
$event = new UserShareAccessUpdatedEvent($user);
247+
$this->eventDispatcher->dispatchTyped($event);
248+
}
249+
}
250+
238251
return $board;
239252
}
240253

@@ -253,6 +266,15 @@ public function deleteUndo(int $id): Board {
253266
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $board, ActivityManager::SUBJECT_BOARD_RESTORE);
254267
$this->changeHelper->boardChanged($board->getId());
255268

269+
if (class_exists(UserShareAccessUpdatedEvent::class)) {
270+
$acls = $this->aclMapper->findAll($id);
271+
foreach ($acls as $acl) {
272+
$user = new LazyUser($acl->getParticipant(), $this->userManager);
273+
$event = new UserShareAccessUpdatedEvent($user);
274+
$this->eventDispatcher->dispatchTyped($event);
275+
}
276+
}
277+
256278
return $board;
257279
}
258280

lib/Service/PermissionService.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
use Psr\Log\LoggerInterface;
2727

2828
class PermissionService {
29-
private array $users = [];
29+
30+
/** @var array<string, array<string, User>> */
31+
private $users = [];
3032

3133
private CappedMemoryCache $boardCache;
3234
/** @var CappedMemoryCache<array<Acl::PERMISSION_*, bool>> */
@@ -207,8 +209,9 @@ public function userCan(array $acls, $permission, $userId = null) {
207209
* Required to allow assigning them to cards
208210
*
209211
* @param $boardId
210-
* @return array
211-
*/
212+
* @param $refresh
213+
* @return array<string, User>
214+
* */
212215
public function findUsers($boardId, $refresh = false) {
213216
// cache users of a board so we don't query them for every cards
214217
if (array_key_exists((string)$boardId, $this->users) && !$refresh) {
@@ -222,12 +225,12 @@ public function findUsers($boardId, $refresh = false) {
222225
} catch (MultipleObjectsReturnedException $e) {
223226
return [];
224227
}
225-
228+
/** @var array<string, User> */
226229
$users = [];
227230
if (!$this->userManager->userExists($board->getOwner())) {
228231
$this->logger->info('No owner found for board ' . $board->getId());
229232
} else {
230-
$users[$board->getOwner()] = new User($board->getOwner(), $this->userManager);
233+
$users[(string)$board->getOwner()] = new User($board->getOwner(), $this->userManager);
231234
}
232235
$acls = $this->aclMapper->findAll($boardId);
233236
/** @var Acl $acl */
@@ -237,7 +240,7 @@ public function findUsers($boardId, $refresh = false) {
237240
$this->logger->info('No user found for acl rule ' . $acl->getId());
238241
continue;
239242
}
240-
$users[$acl->getParticipant()] = new User($acl->getParticipant(), $this->userManager);
243+
$users[(string)$acl->getParticipant()] = new User($acl->getParticipant(), $this->userManager);
241244
}
242245
if ($acl->getType() === Acl::PERMISSION_TYPE_GROUP) {
243246
$group = $this->groupManager->get($acl->getParticipant());
@@ -246,7 +249,7 @@ public function findUsers($boardId, $refresh = false) {
246249
continue;
247250
}
248251
foreach ($group->getUsers() as $user) {
249-
$users[$user->getUID()] = new User($user->getUID(), $this->userManager);
252+
$users[(string)$user->getUID()] = new User($user->getUID(), $this->userManager);
250253
}
251254
}
252255

@@ -267,7 +270,7 @@ public function findUsers($boardId, $refresh = false) {
267270
if ($user === null) {
268271
$this->logger->info('No user found for circle member ' . $member->getUserId());
269272
} else {
270-
$users[$member->getUserId()] = new User($member->getUserId(), $this->userManager);
273+
$users[(string)$member->getUserId()] = new User($member->getUserId(), $this->userManager);
271274
}
272275
}
273276
} catch (\Exception $e) {

lib/Sharing/DeckShareProvider.php

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
use OCP\Share\IManager;
3535
use OCP\Share\IPartialShareProvider;
3636
use OCP\Share\IShare;
37+
use OCP\Share\IShareProviderGetUsers;
3738

3839
/** Taken from the talk shareapicontroller helper */
3940
interface IShareProviderBackend {
@@ -43,7 +44,7 @@ public function formatShare(IShare $share): array;
4344
public function canAccessShare(IShare $share, string $user): bool;
4445
}
4546

46-
class DeckShareProvider implements \OCP\Share\IShareProvider, IPartialShareProvider {
47+
class DeckShareProvider implements \OCP\Share\IShareProvider, IPartialShareProvider, IShareProviderGetUsers {
4748
public const DECK_FOLDER = '/Deck';
4849
public const DECK_FOLDER_PLACEHOLDER = '/{DECK_PLACEHOLDER}';
4950

@@ -1108,4 +1109,20 @@ public function getOrphanedAttachmentShares(): array {
11081109

11091110
return $shares;
11101111
}
1112+
1113+
public function getUsersForShare(IShare $share): iterable {
1114+
if ($share->getShareType() === IShare::TYPE_DECK) {
1115+
$cardId = (int)$share->getSharedWith();
1116+
$boardId = $this->cardMapper->findBoardId($cardId);
1117+
if ($boardId === null) {
1118+
return [];
1119+
}
1120+
1121+
foreach ($this->permissionService->findUsers($boardId) as $user) {
1122+
yield $user->getUserObject();
1123+
}
1124+
}
1125+
1126+
return [];
1127+
}
11111128
}

tests/psalm-baseline.xml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<files psalm-version="6.5.0@38fc8444edf0cebc9205296ee6e30e906ade783b">
3-
<file src="lib/Activity/Filter.php">
4-
<MethodSignatureMismatch>
5-
<code><![CDATA[$types]]></code>
6-
</MethodSignatureMismatch>
7-
</file>
83
<file src="lib/Controller/BoardApiController.php">
94
<UndefinedFunction>
105
<code><![CDATA[parseDate($modified)]]></code>

tests/stub.phpstub

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ namespace OCA\Circles\Model {
4444
public const APP_DEFAULT = 11000;
4545

4646
public function getLevel(): int {}
47+
public function getUserType(): int{}
4748
}
4849

4950
class Circle {
@@ -85,6 +86,12 @@ namespace OCA\Circles {
8586
}
8687
}
8788

89+
namespace OCA\Files_Sharing\Event{
90+
class UserShareAccessUpdatedEvent extends \OCP\EventDispatcher\Event{
91+
public function __construct($user){}
92+
}
93+
}
94+
8895
namespace {
8996

9097
use OCP\IServerContainer;

0 commit comments

Comments
 (0)