Skip to content

Commit 6dbf0d2

Browse files
feat: refresh user mounts when removed from a group or circle that has associated team folders
Signed-off-by: Cristian Scheid <cristianscheid@gmail.com>
1 parent 0d2b3c8 commit 6dbf0d2

4 files changed

Lines changed: 152 additions & 3 deletions

File tree

lib/AppInfo/Application.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use OCA\Circles\Dashboard\TeamDashboardWidget;
1717
use OCA\Circles\Events\AddingCircleMemberEvent;
1818
use OCA\Circles\Events\CircleMemberAddedEvent;
19+
use OCA\Circles\Events\CircleMemberRemovedEvent;
1920
use OCA\Circles\Events\DestroyingCircleEvent;
2021
use OCA\Circles\Events\Files\CreatingFileShareEvent;
2122
use OCA\Circles\Events\Files\FileShareCreatedEvent;
@@ -26,6 +27,7 @@
2627
use OCA\Circles\FileSharingTeamResourceProvider;
2728
use OCA\Circles\Handlers\WebfingerHandler;
2829
use OCA\Circles\Listeners\AccountUpdated;
30+
use OCA\Circles\Listeners\CircleMemberRemoved;
2931
use OCA\Circles\Listeners\Files\AddingMemberSendMail as ListenerFilesAddingMemberSendMail;
3032
use OCA\Circles\Listeners\Files\CreatingShareSendMail as ListenerFilesCreatingShareSendMail;
3133
use OCA\Circles\Listeners\Files\DestroyingCircle as ListenerFilesDestroyingCircle;
@@ -98,6 +100,9 @@ public function register(IRegistrationContext $context): void {
98100
$context->registerEventListener(UserChangedEvent::class, AccountUpdated::class);
99101
$context->registerEventListener(UserDeletedEvent::class, UserDeleted::class);
100102

103+
// Circle Events
104+
$context->registerEventListener(CircleMemberRemovedEvent::class, CircleMemberRemoved::class);
105+
101106
// Group Events
102107
$context->registerEventListener(GroupCreatedEvent::class, GroupCreated::class);
103108
$context->registerEventListener(GroupChangedEvent::class, GroupChanged::class);
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Circles\Listeners;
11+
12+
use Exception;
13+
use OCA\Circles\Events\CircleMemberRemovedEvent;
14+
use OCP\App\IAppManager;
15+
use OCP\EventDispatcher\Event;
16+
use OCP\EventDispatcher\IEventListener;
17+
use OCP\Files\Config\IMountProviderCollection;
18+
use OCP\Files\Config\IUserMountCache;
19+
use OCP\IUserManager;
20+
use OCP\Server;
21+
use Psr\Log\LoggerInterface;
22+
use Throwable;
23+
24+
/** @template-implements IEventListener<CircleMemberRemovedEvent> */
25+
class CircleMemberRemoved implements IEventListener {
26+
public function __construct(
27+
private readonly IUserManager $userManager,
28+
private readonly IAppManager $appManager,
29+
private readonly IUserMountCache $userMountCache,
30+
private readonly IMountProviderCollection $mountProviderCollection,
31+
private readonly LoggerInterface $logger,
32+
) {
33+
}
34+
35+
public function handle(Event $event): void {
36+
if (!($event instanceof CircleMemberRemovedEvent)) {
37+
return;
38+
}
39+
40+
$member = $event->getMember();
41+
if ($member === null) {
42+
return;
43+
}
44+
45+
$user = $this->userManager->get($member->getUserId());
46+
if ($user === null) {
47+
return;
48+
}
49+
50+
$circle = $event->getCircle();
51+
if (!$this->circleHasAssociatedGroupFolder($circle->getSingleId())) {
52+
return;
53+
}
54+
55+
try {
56+
// refresh list of mounts for user
57+
$mounts = $this->mountProviderCollection->getMountsForUser($user);
58+
$mounts[] = $this->mountProviderCollection->getHomeMountForUser($user);
59+
$this->userMountCache->registerMounts($user, $mounts);
60+
} catch (Exception $e) {
61+
$this->logger->debug('Failed to refresh mounts for user ' . $user->getUID(), ['exception' => $e]);
62+
}
63+
}
64+
65+
private function circleHasAssociatedGroupFolder(string $circleId): bool {
66+
if (!$this->appManager->isEnabledForUser('groupfolders')) {
67+
return false;
68+
}
69+
70+
try {
71+
$folderManager = Server::get(\OCA\GroupFolders\Folder\FolderManager::class);
72+
return $folderManager->hasFolderForCircle($circleId);
73+
} catch (Throwable $e) {
74+
$this->logger->debug('Failed to check if circle ' . $circleId . ' has an associated team folder', ['exception' => $e]);
75+
return false;
76+
}
77+
}
78+
}

lib/Listeners/GroupMemberRemoved.php

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,85 @@
1313

1414
use Exception;
1515
use OCA\Circles\Service\SyncService;
16+
use OCP\App\IAppManager;
1617
use OCP\EventDispatcher\Event;
1718
use OCP\EventDispatcher\IEventListener;
19+
use OCP\Files\Config\IMountProviderCollection;
20+
use OCP\Files\Config\IUserMountCache;
1821
use OCP\Group\Events\UserRemovedEvent;
22+
use OCP\Server;
23+
use Psr\Log\LoggerInterface;
24+
use Throwable;
1925

20-
/** @template-implements IEventListener<UserRemovedEvent|Event> */
26+
/** @template-implements IEventListener<UserRemovedEvent> */
2127
class GroupMemberRemoved implements IEventListener {
2228
/** @var SyncService */
2329
private $syncService;
2430

25-
public function __construct(SyncService $syncService) {
31+
/** @var IAppManager */
32+
private $appManager;
33+
34+
/** @var IUserMountCache */
35+
private $userMountCache;
36+
37+
/** @var IMountProviderCollection */
38+
private $mountProviderCollection;
39+
40+
/** @var LoggerInterface */
41+
private $logger;
42+
43+
public function __construct(
44+
SyncService $syncService,
45+
IAppManager $appManager,
46+
IUserMountCache $userMountCache,
47+
IMountProviderCollection $mountProviderCollection,
48+
LoggerInterface $logger,
49+
) {
2650
$this->syncService = $syncService;
51+
$this->appManager = $appManager;
52+
$this->userMountCache = $userMountCache;
53+
$this->mountProviderCollection = $mountProviderCollection;
54+
$this->logger = $logger;
2755
}
2856

2957
public function handle(Event $event): void {
3058
if (!($event instanceof UserRemovedEvent)) {
3159
return;
3260
}
3361

34-
$group = $event->getGroup();
3562
$user = $event->getUser();
63+
$group = $event->getGroup();
64+
3665
try {
3766
$this->syncService->groupMemberRemoved($group->getGID(), $user->getUID());
3867
} catch (Exception $e) {
3968
}
69+
70+
if (!$this->groupHasAssociatedGroupFolder($group->getGID())) {
71+
return;
72+
}
73+
74+
try {
75+
// refresh list of mounts for user
76+
$mounts = $this->mountProviderCollection->getMountsForUser($user);
77+
$mounts[] = $this->mountProviderCollection->getHomeMountForUser($user);
78+
$this->userMountCache->registerMounts($user, $mounts);
79+
} catch (Exception $e) {
80+
$this->logger->debug('Failed to refresh mounts for user ' . $user->getUID(), ['exception' => $e]);
81+
}
82+
}
83+
84+
private function groupHasAssociatedGroupFolder(string $groupId): bool {
85+
if (!$this->appManager->isEnabledForUser('groupfolders')) {
86+
return false;
87+
}
88+
89+
try {
90+
$folderManager = Server::get(\OCA\GroupFolders\Folder\FolderManager::class);
91+
return $folderManager->hasFolderForGroup($groupId);
92+
} catch (Throwable $e) {
93+
$this->logger->debug('Failed to check if group ' . $groupId . ' has an associated team folder', ['exception' => $e]);
94+
return false;
95+
}
4096
}
4197
}

tests/psalm-baseline.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,4 +424,14 @@
424424
<code><![CDATA[$s[$e]]]></code>
425425
</InvalidArrayOffset>
426426
</file>
427+
<file src="lib/Listeners/GroupMemberRemoved.php">
428+
<UndefinedClass>
429+
<code><![CDATA[\OCA\GroupFolders\Folder\FolderManager]]></code>
430+
</UndefinedClass>
431+
</file>
432+
<file src="lib/Listeners/CircleMemberRemoved.php">
433+
<UndefinedClass>
434+
<code><![CDATA[\OCA\GroupFolders\Folder\FolderManager]]></code>
435+
</UndefinedClass>
436+
</file>
427437
</files>

0 commit comments

Comments
 (0)