Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
11 changes: 8 additions & 3 deletions lib/Db/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace OCA\Deck\Db;

use OCP\IUser;
use OCP\IUserManager;

class User extends RelationalObject {
Expand All @@ -18,19 +19,23 @@ public function __construct($uid, IUserManager $userManager) {
});
}

public function getObjectSerialization() {
public function getObjectSerialization(): array {
return [
'uid' => $this->getObject()->getUID(),
'displayname' => $this->getDisplayName(),
'type' => Acl::PERMISSION_TYPE_USER
];
}

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();
}
}
43 changes: 43 additions & 0 deletions lib/Listeners/AclCreatedRemovedListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Deck\Listeners;

use OCA\Deck\Event\AclCreatedEvent;
use OCA\Deck\Event\AclDeletedEvent;
use OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\EventDispatcher\IEventListener;
use OCP\IGroupManager;
use OCP\IUserManager;
use OCP\Share\IShare;

class AclCreatedRemovedListener implements IEventListener {

Check failure on line 19 in lib/Listeners/AclCreatedRemovedListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

MissingTemplateParam

lib/Listeners/AclCreatedRemovedListener.php:19:44: MissingTemplateParam: OCA\Deck\Listeners\AclCreatedRemovedListener has missing template params when extending OCP\EventDispatcher\IEventListener, expecting 1 (see https://psalm.dev/182)
public function __construct(
private IGroupManager $groupManager,
private IEventDispatcher $eventDispatcher,
private IUserManager $userManager,
) {
}

public function handle(Event $event): void {
if (!$event instanceof AclDeletedEvent && !$event instanceof AclCreatedEvent) {
return;
}

$acl = $event->getAcl();
if ($acl->getType() === IShare::TYPE_GROUP) {
$group = $this->groupManager->get($acl->getParticipant());
foreach ($group->getUsers() as $user) {
$this->eventDispatcher->dispatchTyped(new UserShareAccessUpdatedEvent($user));

Check failure on line 36 in lib/Listeners/AclCreatedRemovedListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedClass

lib/Listeners/AclCreatedRemovedListener.php:36:47: UndefinedClass: Class, interface or enum named OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent does not exist (see https://psalm.dev/019)

Check failure on line 36 in lib/Listeners/AclCreatedRemovedListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

InvalidArgument

lib/Listeners/AclCreatedRemovedListener.php:36:43: InvalidArgument: Argument 1 of OCP\EventDispatcher\IEventDispatcher::dispatchTyped expects OCP\EventDispatcher\Event, but OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent provided (see https://psalm.dev/004)
}
} else {
Comment on lines +33 to +38
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to be missing circles handling?

$user = $this->userManager->get($acl->getParticipant());
$this->eventDispatcher->dispatchTyped(new UserShareAccessUpdatedEvent($user));

Check failure on line 40 in lib/Listeners/AclCreatedRemovedListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedClass

lib/Listeners/AclCreatedRemovedListener.php:40:46: UndefinedClass: Class, interface or enum named OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent does not exist (see https://psalm.dev/019)
}
}
}
18 changes: 18 additions & 0 deletions lib/Service/BoardService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -69,6 +72,7 @@
private IDBConnection $connection,
private BoardServiceValidator $boardServiceValidator,
private SessionMapper $sessionMapper,
private IUserManager $userManager,
private ?string $userId,
) {
}
Expand Down Expand Up @@ -235,6 +239,13 @@
$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);

Check failure on line 245 in lib/Service/BoardService.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedClass

lib/Service/BoardService.php:245:17: UndefinedClass: Class, interface or enum named OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent does not exist (see https://psalm.dev/019)
$this->eventDispatcher->dispatchTyped($event);

Check failure on line 246 in lib/Service/BoardService.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

InvalidArgument

lib/Service/BoardService.php:246:42: InvalidArgument: Argument 1 of OCP\EventDispatcher\IEventDispatcher::dispatchTyped expects OCP\EventDispatcher\Event, but OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent provided (see https://psalm.dev/004)
}

return $board;
}

Expand All @@ -253,6 +264,13 @@
$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);

Check failure on line 270 in lib/Service/BoardService.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedClass

lib/Service/BoardService.php:270:17: UndefinedClass: Class, interface or enum named OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent does not exist (see https://psalm.dev/019)
$this->eventDispatcher->dispatchTyped($event);

Check failure on line 271 in lib/Service/BoardService.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

InvalidArgument

lib/Service/BoardService.php:271:42: InvalidArgument: Argument 1 of OCP\EventDispatcher\IEventDispatcher::dispatchTyped expects OCP\EventDispatcher\Event, but OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent provided (see https://psalm.dev/004)
}

return $board;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Service/PermissionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@
* 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
Expand Down Expand Up @@ -276,7 +276,7 @@
}
}
$this->users[(string)$boardId] = $users;
return $this->users[(string)$boardId];

Check failure on line 279 in lib/Service/PermissionService.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

InvalidReturnStatement

lib/Service/PermissionService.php:279:10: InvalidReturnStatement: The inferred type 'array<array-key, OCA\Deck\Db\User|array<array-key, OCA\Deck\Db\User|array<string, OCA\Deck\Db\User>>>|mixed' does not match the declared return type 'array<array-key, OCA\Deck\Db\User>' for OCA\Deck\Service\PermissionService::findUsers (see https://psalm.dev/128)
}

public function canCreate() {
Expand Down
19 changes: 18 additions & 1 deletion lib/Sharing/DeckShareProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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}';

Expand Down Expand Up @@ -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 [];
}
}
10 changes: 10 additions & 0 deletions tests/unit/Service/BoardServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -50,6 +51,7 @@
use OCP\IDBConnection;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;

Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -135,6 +141,7 @@ public function setUp(): void {
$this->connection,
$this->boardServiceValidator,
$this->sessionMapper,
$this->userManager,
$this->userId
);

Expand Down Expand Up @@ -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));
}

Expand Down
Loading