From 3e8f7e9debfb60dd4ede4e2ab593d05d02b5a20b Mon Sep 17 00:00:00 2001 From: Julius Knorr Date: Tue, 30 Dec 2025 10:35:52 +0100 Subject: [PATCH 1/3] chore: Expose IUser object of internal DTO Signed-off-by: Julius Knorr --- lib/Db/User.php | 11 ++++++++--- lib/Service/PermissionService.php | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/Db/User.php b/lib/Db/User.php index 7c50aa9b1..3902b177e 100644 --- a/lib/Db/User.php +++ b/lib/Db/User.php @@ -7,6 +7,7 @@ namespace OCA\Deck\Db; +use OCP\IUser; use OCP\IUserManager; class User extends RelationalObject { @@ -18,7 +19,7 @@ public function __construct($uid, IUserManager $userManager) { }); } - public function getObjectSerialization() { + public function getObjectSerialization(): array { return [ 'uid' => $this->getObject()->getUID(), 'displayname' => $this->getDisplayName(), @@ -26,11 +27,15 @@ public function getObjectSerialization() { ]; } - public function getUID() { + public function getUID(): string { return $this->getPrimaryKey(); } - public function getDisplayName() { + public function getDisplayName(): ?string { return $this->userManager->getDisplayName($this->getPrimaryKey()); } + + public function getUserObject(): IUser { + return $this->getObject(); + } } diff --git a/lib/Service/PermissionService.php b/lib/Service/PermissionService.php index 1c5ef10b0..2f28c07a5 100644 --- a/lib/Service/PermissionService.php +++ b/lib/Service/PermissionService.php @@ -207,7 +207,7 @@ public function userCan(array $acls, $permission, $userId = null) { * Required to allow assigning them to cards * * @param $boardId - * @return array + * @return User[] */ public function findUsers($boardId, $refresh = false) { // cache users of a board so we don't query them for every cards From 709e23bca1d2d7a3e1e6313195215effd610fb46 Mon Sep 17 00:00:00 2001 From: Julius Knorr Date: Tue, 30 Dec 2025 10:37:34 +0100 Subject: [PATCH 2/3] chore: Implement getUsersForShare on share provider Signed-off-by: Julius Knorr --- lib/Sharing/DeckShareProvider.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/Sharing/DeckShareProvider.php b/lib/Sharing/DeckShareProvider.php index dab4a4934..388195ba4 100644 --- a/lib/Sharing/DeckShareProvider.php +++ b/lib/Sharing/DeckShareProvider.php @@ -34,6 +34,7 @@ use OCP\Share\IManager; use OCP\Share\IPartialShareProvider; use OCP\Share\IShare; +use OCP\Share\IShareProviderGetUsers; /** Taken from the talk shareapicontroller helper */ interface IShareProviderBackend { @@ -43,7 +44,7 @@ public function formatShare(IShare $share): array; public function canAccessShare(IShare $share, string $user): bool; } -class DeckShareProvider implements \OCP\Share\IShareProvider, IPartialShareProvider { +class DeckShareProvider implements \OCP\Share\IShareProvider, IPartialShareProvider, IShareProviderGetUsers { public const DECK_FOLDER = '/Deck'; public const DECK_FOLDER_PLACEHOLDER = '/{DECK_PLACEHOLDER}'; @@ -1108,4 +1109,20 @@ public function getOrphanedAttachmentShares(): array { return $shares; } + + public function getUsersForShare(IShare $share): iterable { + if ($share->getShareType() === IShare::TYPE_DECK) { + $cardId = (int)$share->getSharedWith(); + $boardId = $this->cardMapper->findBoardId($cardId); + if ($boardId === null) { + return []; + } + + foreach ($this->permissionService->findUsers($boardId) as $user) { + yield $user->getUserObject(); + } + } + + return []; + } } From dfe25f2f4a87ee1e66bae84b3af0ae06c7c71c00 Mon Sep 17 00:00:00 2001 From: grnd-alt Date: Thu, 15 Jan 2026 12:43:56 +0100 Subject: [PATCH 3/3] feat: dispatch UserShareAccessUpdatedEvent on ACL add/remove Signed-off-by: grnd-alt --- lib/AppInfo/Application.php | 5 +++ lib/Listeners/AclCreatedRemovedListener.php | 43 +++++++++++++++++++++ lib/Service/BoardService.php | 18 +++++++++ tests/unit/Service/BoardServiceTest.php | 10 +++++ 4 files changed, 76 insertions(+) create mode 100644 lib/Listeners/AclCreatedRemovedListener.php diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 5b0c7bb36..71c732522 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -27,6 +27,7 @@ use OCA\Deck\Event\CardUpdatedEvent; use OCA\Deck\Event\SessionClosedEvent; use OCA\Deck\Event\SessionCreatedEvent; +use OCA\Deck\Listeners\AclCreatedRemovedListener; use OCA\Deck\Listeners\BeforeTemplateRenderedListener; use OCA\Deck\Listeners\CommentEventListener; use OCA\Deck\Listeners\FullTextSearchEventListener; @@ -134,6 +135,10 @@ public function register(IRegistrationContext $context): void { $context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class); + // Event listening to emit UserShareAccessUpdatedEvent for files_sharing + $context->registerEventListener(AclCreatedEvent::class, AclCreatedRemovedListener::class); + $context->registerEventListener(AclDeletedEvent::class, AclCreatedRemovedListener::class); + // Event listening for full text search indexing $context->registerEventListener(CardCreatedEvent::class, FullTextSearchEventListener::class); $context->registerEventListener(CardUpdatedEvent::class, FullTextSearchEventListener::class); diff --git a/lib/Listeners/AclCreatedRemovedListener.php b/lib/Listeners/AclCreatedRemovedListener.php new file mode 100644 index 000000000..9893a3ecb --- /dev/null +++ b/lib/Listeners/AclCreatedRemovedListener.php @@ -0,0 +1,43 @@ +getAcl(); + if ($acl->getType() === IShare::TYPE_GROUP) { + $group = $this->groupManager->get($acl->getParticipant()); + foreach ($group->getUsers() as $user) { + $this->eventDispatcher->dispatchTyped(new UserShareAccessUpdatedEvent($user)); + } + } else { + $user = $this->userManager->get($acl->getParticipant()); + $this->eventDispatcher->dispatchTyped(new UserShareAccessUpdatedEvent($user)); + } + } +} diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index d2189fd94..b1e1200ac 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -7,6 +7,7 @@ namespace OCA\Deck\Service; +use OC\User\LazyUser; use OCA\Deck\Activity\ActivityManager; use OCA\Deck\Activity\ChangeSet; use OCA\Deck\AppInfo\Application; @@ -34,6 +35,7 @@ use OCA\Deck\NoPermissionException; use OCA\Deck\Notification\NotificationHelper; use OCA\Deck\Validators\BoardServiceValidator; +use OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\DB\Exception as DbException; @@ -42,6 +44,7 @@ use OCP\IDBConnection; use OCP\IL10N; use OCP\IURLGenerator; +use OCP\IUserManager; use OCP\Server; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; @@ -69,6 +72,7 @@ public function __construct( private IDBConnection $connection, private BoardServiceValidator $boardServiceValidator, private SessionMapper $sessionMapper, + private IUserManager $userManager, private ?string $userId, ) { } @@ -235,6 +239,13 @@ public function delete(int $id): Board { $this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $board, ActivityManager::SUBJECT_BOARD_DELETE); $this->changeHelper->boardChanged($board->getId()); + $acls = $this->aclMapper->findAll($id); + foreach ($acls as $acl) { + $user = new LazyUser($acl->getParticipant(), $this->userManager); + $event = new UserShareAccessUpdatedEvent($user); + $this->eventDispatcher->dispatchTyped($event); + } + return $board; } @@ -253,6 +264,13 @@ public function deleteUndo(int $id): Board { $this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_BOARD, $board, ActivityManager::SUBJECT_BOARD_RESTORE); $this->changeHelper->boardChanged($board->getId()); + $acls = $this->aclMapper->findAll($id); + foreach ($acls as $acl) { + $user = new LazyUser($acl->getParticipant(), $this->userManager); + $event = new UserShareAccessUpdatedEvent($user); + $this->eventDispatcher->dispatchTyped($event); + } + return $board; } diff --git a/tests/unit/Service/BoardServiceTest.php b/tests/unit/Service/BoardServiceTest.php index 5ce29df8c..b2ce00ce4 100644 --- a/tests/unit/Service/BoardServiceTest.php +++ b/tests/unit/Service/BoardServiceTest.php @@ -40,6 +40,7 @@ use OCA\Deck\Db\Session; use OCA\Deck\Db\SessionMapper; use OCA\Deck\Db\StackMapper; +use OCA\Deck\Db\User; use OCA\Deck\Event\AclCreatedEvent; use OCA\Deck\Event\AclDeletedEvent; use OCA\Deck\NoPermissionException; @@ -50,6 +51,7 @@ use OCP\IDBConnection; use OCP\IURLGenerator; use OCP\IUser; +use OCP\IUserManager; use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; @@ -95,6 +97,9 @@ class BoardServiceTest extends TestCase { /** @var SessionMapper */ private $sessionMapper; + /** @var IUserManager */ + private $userManager; + public function setUp(): void { parent::setUp(); $this->l10n = $this->createMock(L10N::class); @@ -115,6 +120,7 @@ public function setUp(): void { $this->connection = $this->createMock(IDBConnection::class); $this->boardServiceValidator = $this->createMock(BoardServiceValidator::class); $this->sessionMapper = $this->createMock(SessionMapper::class); + $this->userManager = $this->createMock(IUserManager::class); $this->service = new BoardService( $this->boardMapper, @@ -135,6 +141,7 @@ public function setUp(): void { $this->connection, $this->boardServiceValidator, $this->sessionMapper, + $this->userManager, $this->userId ); @@ -262,6 +269,9 @@ public function testDelete() { $this->boardMapper->expects($this->once()) ->method('update') ->willReturn($boardDeleted); + $this->aclMapper->expects($this->once()) + ->method('findAll') + ->willReturn([]); $this->assertEquals($boardDeleted, $this->service->delete(123)); }