Skip to content

Commit 472fb0b

Browse files
Merge pull request #2634 from nextcloud/backport/2615/stable34
[stable34] fix: refresh user mounts when removed from a group or circle that has associated team folders
2 parents d8f1cd4 + b1c2e98 commit 472fb0b

4 files changed

Lines changed: 154 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;
@@ -102,6 +104,9 @@ public function register(IRegistrationContext $context): void {
102104
$context->registerEventListener(UserChangedEvent::class, AccountUpdated::class);
103105
$context->registerEventListener(UserDeletedEvent::class, UserDeleted::class);
104106

107+
// Circle Events
108+
$context->registerEventListener(CircleMemberRemovedEvent::class, CircleMemberRemoved::class);
109+
105110
// Group Events
106111
$context->registerEventListener(GroupCreatedEvent::class, GroupCreated::class);
107112
$context->registerEventListener(GroupChangedEvent::class, GroupChanged::class);
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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+
#[\Override]
36+
public function handle(Event $event): void {
37+
if (!($event instanceof CircleMemberRemovedEvent)) {
38+
return;
39+
}
40+
41+
$member = $event->getMember();
42+
if ($member === null) {
43+
return;
44+
}
45+
46+
$user = $this->userManager->get($member->getUserId());
47+
if ($user === null) {
48+
return;
49+
}
50+
51+
$circle = $event->getCircle();
52+
if (!$this->circleHasAssociatedGroupFolder($circle->getSingleId())) {
53+
return;
54+
}
55+
56+
try {
57+
// refresh list of mounts for user
58+
$mounts = $this->mountProviderCollection->getMountsForUser($user);
59+
$mounts[] = $this->mountProviderCollection->getHomeMountForUser($user);
60+
$this->userMountCache->registerMounts($user, $mounts);
61+
} catch (Exception $e) {
62+
$this->logger->debug('Failed to refresh mounts for user ' . $user->getUID(), ['exception' => $e]);
63+
}
64+
}
65+
66+
private function circleHasAssociatedGroupFolder(string $circleId): bool {
67+
if (!$this->appManager->isEnabledForUser('groupfolders')) {
68+
return false;
69+
}
70+
71+
try {
72+
$folderManager = Server::get(\OCA\GroupFolders\Folder\FolderManager::class);
73+
return $folderManager->hasFolderForCircle($circleId);
74+
} catch (Throwable $e) {
75+
$this->logger->debug('Failed to check if circle ' . $circleId . ' has an associated team folder', ['exception' => $e]);
76+
return false;
77+
}
78+
}
79+
}

lib/Listeners/GroupMemberRemoved.php

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,86 @@
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

57+
#[\Override]
2958
public function handle(Event $event): void {
3059
if (!($event instanceof UserRemovedEvent)) {
3160
return;
3261
}
3362

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

tests/psalm-baseline.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,4 +479,14 @@
479479
<code><![CDATA[$s[$e]]]></code>
480480
</InvalidArrayOffset>
481481
</file>
482+
<file src="lib/Listeners/GroupMemberRemoved.php">
483+
<UndefinedClass>
484+
<code><![CDATA[\OCA\GroupFolders\Folder\FolderManager]]></code>
485+
</UndefinedClass>
486+
</file>
487+
<file src="lib/Listeners/CircleMemberRemoved.php">
488+
<UndefinedClass>
489+
<code><![CDATA[\OCA\GroupFolders\Folder\FolderManager]]></code>
490+
</UndefinedClass>
491+
</file>
482492
</files>

0 commit comments

Comments
 (0)