Skip to content

Commit 0ee2748

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 9e0edce commit 0ee2748

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
@@ -39,6 +39,7 @@
3939
use OCA\Circles\Dashboard\TeamDashboardWidget;
4040
use OCA\Circles\Events\AddingCircleMemberEvent;
4141
use OCA\Circles\Events\CircleMemberAddedEvent;
42+
use OCA\Circles\Events\CircleMemberRemovedEvent;
4243
use OCA\Circles\Events\DestroyingCircleEvent;
4344
use OCA\Circles\Events\Files\CreatingFileShareEvent;
4445
use OCA\Circles\Events\Files\FileShareCreatedEvent;
@@ -49,6 +50,7 @@
4950
use OCA\Circles\FileSharingTeamResourceProvider;
5051
use OCA\Circles\Handlers\WebfingerHandler;
5152
use OCA\Circles\Listeners\AccountUpdated;
53+
use OCA\Circles\Listeners\CircleMemberRemoved;
5254
use OCA\Circles\Listeners\Files\AddingMemberSendMail as ListenerFilesAddingMemberSendMail;
5355
use OCA\Circles\Listeners\Files\CreatingShareSendMail as ListenerFilesCreatingShareSendMail;
5456
use OCA\Circles\Listeners\Files\DestroyingCircle as ListenerFilesDestroyingCircle;
@@ -123,6 +125,9 @@ public function register(IRegistrationContext $context): void {
123125
$context->registerEventListener(UserChangedEvent::class, AccountUpdated::class);
124126
$context->registerEventListener(UserDeletedEvent::class, UserDeleted::class);
125127

128+
// Circle Events
129+
$context->registerEventListener(CircleMemberRemovedEvent::class, CircleMemberRemoved::class);
130+
126131
// Group Events
127132
$context->registerEventListener(GroupCreatedEvent::class, GroupCreated::class);
128133
$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
@@ -33,29 +33,85 @@
3333

3434
use Exception;
3535
use OCA\Circles\Service\SyncService;
36+
use OCP\App\IAppManager;
3637
use OCP\EventDispatcher\Event;
3738
use OCP\EventDispatcher\IEventListener;
39+
use OCP\Files\Config\IMountProviderCollection;
40+
use OCP\Files\Config\IUserMountCache;
3841
use OCP\Group\Events\UserRemovedEvent;
42+
use OCP\Server;
43+
use Psr\Log\LoggerInterface;
44+
use Throwable;
3945

40-
/** @template-implements IEventListener<UserRemovedEvent|Event> */
46+
/** @template-implements IEventListener<UserRemovedEvent> */
4147
class GroupMemberRemoved implements IEventListener {
4248
/** @var SyncService */
4349
private $syncService;
4450

45-
public function __construct(SyncService $syncService) {
51+
/** @var IAppManager */
52+
private $appManager;
53+
54+
/** @var IUserMountCache */
55+
private $userMountCache;
56+
57+
/** @var IMountProviderCollection */
58+
private $mountProviderCollection;
59+
60+
/** @var LoggerInterface */
61+
private $logger;
62+
63+
public function __construct(
64+
SyncService $syncService,
65+
IAppManager $appManager,
66+
IUserMountCache $userMountCache,
67+
IMountProviderCollection $mountProviderCollection,
68+
LoggerInterface $logger,
69+
) {
4670
$this->syncService = $syncService;
71+
$this->appManager = $appManager;
72+
$this->userMountCache = $userMountCache;
73+
$this->mountProviderCollection = $mountProviderCollection;
74+
$this->logger = $logger;
4775
}
4876

4977
public function handle(Event $event): void {
5078
if (!($event instanceof UserRemovedEvent)) {
5179
return;
5280
}
5381

54-
$group = $event->getGroup();
5582
$user = $event->getUser();
83+
$group = $event->getGroup();
84+
5685
try {
5786
$this->syncService->groupMemberRemoved($group->getGID(), $user->getUID());
5887
} catch (Exception $e) {
5988
}
89+
90+
if (!$this->groupHasAssociatedGroupFolder($group->getGID())) {
91+
return;
92+
}
93+
94+
try {
95+
// refresh list of mounts for user
96+
$mounts = $this->mountProviderCollection->getMountsForUser($user);
97+
$mounts[] = $this->mountProviderCollection->getHomeMountForUser($user);
98+
$this->userMountCache->registerMounts($user, $mounts);
99+
} catch (Exception $e) {
100+
$this->logger->debug('Failed to refresh mounts for user ' . $user->getUID(), ['exception' => $e]);
101+
}
102+
}
103+
104+
private function groupHasAssociatedGroupFolder(string $groupId): bool {
105+
if (!$this->appManager->isEnabledForUser('groupfolders')) {
106+
return false;
107+
}
108+
109+
try {
110+
$folderManager = Server::get(\OCA\GroupFolders\Folder\FolderManager::class);
111+
return $folderManager->hasFolderForGroup($groupId);
112+
} catch (Throwable $e) {
113+
$this->logger->debug('Failed to check if group ' . $groupId . ' has an associated team folder', ['exception' => $e]);
114+
return false;
115+
}
60116
}
61117
}

tests/psalm-baseline.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,4 +409,14 @@
409409
<code><![CDATA[$s[$e]]]></code>
410410
</InvalidArrayOffset>
411411
</file>
412+
<file src="lib/Listeners/GroupMemberRemoved.php">
413+
<UndefinedClass>
414+
<code><![CDATA[\OCA\GroupFolders\Folder\FolderManager]]></code>
415+
</UndefinedClass>
416+
</file>
417+
<file src="lib/Listeners/CircleMemberRemoved.php">
418+
<UndefinedClass>
419+
<code><![CDATA[\OCA\GroupFolders\Folder\FolderManager]]></code>
420+
</UndefinedClass>
421+
</file>
412422
</files>

0 commit comments

Comments
 (0)