From 35326a0fcace13cb9a619975b47c70b926d7068a Mon Sep 17 00:00:00 2001 From: samin-z Date: Tue, 16 Jun 2026 17:18:02 +0200 Subject: [PATCH 1/3] apply remove share for users/teams/groups Signed-off-by: samin-z --- lib/AppInfo/Application.php | 6 +++ lib/Db/ShareMapper.php | 12 ++++++ lib/Listener/ReceiverCleanupListener.php | 54 ++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 lib/Listener/ReceiverCleanupListener.php diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index fc7548b272..f45c0d52d0 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -9,6 +9,7 @@ use Exception; use OCA\Analytics\Datasource\DatasourceEvent; +use OCA\Circles\Events\CircleDestroyedEvent; use OCA\Tables\Capabilities; use OCA\Tables\Event\RowDeletedEvent; use OCA\Tables\Event\TableDeletedEvent; @@ -18,6 +19,7 @@ use OCA\Tables\Listener\AnalyticsDatasourceListener; use OCA\Tables\Listener\BeforeTemplateRenderedListener; use OCA\Tables\Listener\LoadAdditionalListener; +use OCA\Tables\Listener\ReceiverCleanupListener; use OCA\Tables\Listener\TablesReferenceListener; use OCA\Tables\Listener\UserDeletedListener; use OCA\Tables\Listener\WhenRowDeletedAuditLogListener; @@ -39,6 +41,7 @@ use OCP\Collaboration\Reference\RenderReferenceEvent; use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent; use OCP\DB\Events\AddMissingIndicesEvent; +use OCP\Group\Events\BeforeGroupDeletedEvent; use OCP\User\Events\BeforeUserDeletedEvent; class Application extends App implements IBootstrap { @@ -85,6 +88,9 @@ public function register(IRegistrationContext $context): void { $context->registerEventListener(RowDeletedEvent::class, WhenRowDeletedAuditLogListener::class); $context->registerEventListener(TableOwnershipTransferredEvent::class, WhenTableTransferredAuditLogListener::class); $context->registerEventListener(AddMissingIndicesEvent::class, AddMissingIndicesListener::class); + $context->registerEventListener(UserDeletedEvent::class, ReceiverCleanupListener::class); + $context->registerEventListener(BeforeGroupDeletedEvent::class, ReceiverCleanupListener::class); + $context->registerEventListener(CircleDestroyedEvent::class, ReceiverCleanupListener::class); $context->registerSearchProvider(SearchTablesProvider::class); diff --git a/lib/Db/ShareMapper.php b/lib/Db/ShareMapper.php index 85b8d09823..a48a00e976 100644 --- a/lib/Db/ShareMapper.php +++ b/lib/Db/ShareMapper.php @@ -195,4 +195,16 @@ public function changeReceiverForNode(string $nodeType, int $nodeId, string $new ->andWhere($qb->expr()->eq('receiver_type', $qb->createNamedParameter('user', IQueryBuilder::PARAM_STR))) ->executeStatement(); } + + + /** + * @throws Exception + */ + public function deleteByReceiver(string $receiver, string $receiverType): int { + $qb = $this->db->getQueryBuilder(); + return $qb->delete($this->table) + ->where($qb->expr()->eq('receiver', $qb->createNamedParameter($receiver, IQueryBuilder::PARAM_STR))) + ->andWhere($qb->expr()->eq('receiver_type', $qb->createNamedParameter($receiverType, IQueryBuilder::PARAM_STR))) + ->executeStatement(); + } } diff --git a/lib/Listener/ReceiverCleanupListener.php b/lib/Listener/ReceiverCleanupListener.php new file mode 100644 index 0000000000..4572ccec83 --- /dev/null +++ b/lib/Listener/ReceiverCleanupListener.php @@ -0,0 +1,54 @@ + */ +class ReceiverCleanupListener implements IEventListener { + public function __construct( + private ShareMapper $shareMapper, + private CirclesManager $circlesManager, + ) { + } + + public function handle(Event $event): void { + if ($event instanceof UserDeletedEvent) { + $this->cleanupByParticipant('user', $event->getUser()->getUID()); + } elseif ($event instanceof BeforeGroupDeletedEvent) { + $this->cleanupGroupShares($event->getGroup()->getGID()); + } elseif ($event instanceof CircleDestroyedEvent) { + $this->cleanupByParticipant('circle', $event->getCircle()->getSingleId()); + } + } + + private function cleanupGroupShares(string $gid): void { + $this->cleanupByParticipant('group', $gid); + + try { + $singleId = $this->circlesManager + ->getFederatedUser($gid, Member::TYPE_GROUP) + ->getSingleId(); + } catch (\Throwable) { + return; + } + + $this->cleanupByParticipant('group', $singleId); + } + + private function cleanupByParticipant(string $type, string $participant): void { + $this->shareMapper->deleteByReceiver($participant, $type); + } +} From edf270ea93dff693a0fb2e77f9cdfd48cac73ffa Mon Sep 17 00:00:00 2001 From: samin-z Date: Wed, 17 Jun 2026 12:09:59 +0200 Subject: [PATCH 2/3] simplify logic Signed-off-by: samin-z --- lib/Db/ShareMapper.php | 1 - lib/Listener/ReceiverCleanupListener.php | 34 ++++++++++-------------- tests/stub.phpstub | 6 +++++ 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/Db/ShareMapper.php b/lib/Db/ShareMapper.php index a48a00e976..9e632f8140 100644 --- a/lib/Db/ShareMapper.php +++ b/lib/Db/ShareMapper.php @@ -196,7 +196,6 @@ public function changeReceiverForNode(string $nodeType, int $nodeId, string $new ->executeStatement(); } - /** * @throws Exception */ diff --git a/lib/Listener/ReceiverCleanupListener.php b/lib/Listener/ReceiverCleanupListener.php index 4572ccec83..bde1b7e8e1 100644 --- a/lib/Listener/ReceiverCleanupListener.php +++ b/lib/Listener/ReceiverCleanupListener.php @@ -7,48 +7,42 @@ namespace OCA\Tables\Listener; -use OCA\Circles\CirclesManager; use OCA\Circles\Events\CircleDestroyedEvent; -use OCA\Circles\Model\Member; +use OCA\Tables\Constants\ShareReceiverType; use OCA\Tables\Db\ShareMapper; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\Group\Events\BeforeGroupDeletedEvent; use OCP\User\Events\UserDeletedEvent; +use Psr\Log\LoggerInterface; /** @template-implements IEventListener */ class ReceiverCleanupListener implements IEventListener { public function __construct( private ShareMapper $shareMapper, - private CirclesManager $circlesManager, + private LoggerInterface $logger, ) { } public function handle(Event $event): void { if ($event instanceof UserDeletedEvent) { - $this->cleanupByParticipant('user', $event->getUser()->getUID()); + $this->cleanupByParticipant(ShareReceiverType::USER, $event->getUser()->getUID()); } elseif ($event instanceof BeforeGroupDeletedEvent) { - $this->cleanupGroupShares($event->getGroup()->getGID()); + $this->cleanupByParticipant(ShareReceiverType::GROUP, $event->getGroup()->getGID()); } elseif ($event instanceof CircleDestroyedEvent) { - $this->cleanupByParticipant('circle', $event->getCircle()->getSingleId()); + $this->cleanupByParticipant(ShareReceiverType::CIRCLE, $event->getCircle()->getSingleId()); } } - private function cleanupGroupShares(string $gid): void { - $this->cleanupByParticipant('group', $gid); - + private function cleanupByParticipant(string $type, string $participant): void { try { - $singleId = $this->circlesManager - ->getFederatedUser($gid, Member::TYPE_GROUP) - ->getSingleId(); - } catch (\Throwable) { - return; + $this->shareMapper->deleteByReceiver($participant, $type); + } catch (\Throwable $e) { + $this->logger->warning('cleanup table shares for deleted receiver has failed: ' . $e->getMessage(), [ + 'exception' => $e, + 'receiver_type' => $type, + 'receiver' => $participant, + ]); } - - $this->cleanupByParticipant('group', $singleId); - } - - private function cleanupByParticipant(string $type, string $participant): void { - $this->shareMapper->deleteByReceiver($participant, $type); } } diff --git a/tests/stub.phpstub b/tests/stub.phpstub index 800bb6518f..395fc64656 100644 --- a/tests/stub.phpstub +++ b/tests/stub.phpstub @@ -21,6 +21,12 @@ namespace OCA\Circles\Model { } } +namespace OCA\Circles\Events { + class CircleDestroyedEvent extends \OCP\EventDispatcher\Event { + public function getCircle(): \OCA\Circles\Model\Circle {} + } +} + namespace OC\Collaboration\Reference { class LinkReferenceProvider implements IReferenceProvider { abstract public function matchReference(string $referenceText): bool {} From 823b6bfca3f2a21886fbde13c7084cd8b511e585 Mon Sep 17 00:00:00 2001 From: samin-z Date: Wed, 24 Jun 2026 17:43:50 +0200 Subject: [PATCH 3/3] update to use GroupDeletedEvent update to use GroupDeletedEvent Signed-off-by: samin-z --- lib/AppInfo/Application.php | 5 +++-- lib/Listener/ReceiverCleanupListener.php | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index f45c0d52d0..0b4b0c1c47 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -41,8 +41,9 @@ use OCP\Collaboration\Reference\RenderReferenceEvent; use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent; use OCP\DB\Events\AddMissingIndicesEvent; -use OCP\Group\Events\BeforeGroupDeletedEvent; +use OCP\Group\Events\GroupDeletedEvent; use OCP\User\Events\BeforeUserDeletedEvent; +use OCP\User\Events\UserDeletedEvent; class Application extends App implements IBootstrap { public const APP_ID = 'tables'; @@ -89,7 +90,7 @@ public function register(IRegistrationContext $context): void { $context->registerEventListener(TableOwnershipTransferredEvent::class, WhenTableTransferredAuditLogListener::class); $context->registerEventListener(AddMissingIndicesEvent::class, AddMissingIndicesListener::class); $context->registerEventListener(UserDeletedEvent::class, ReceiverCleanupListener::class); - $context->registerEventListener(BeforeGroupDeletedEvent::class, ReceiverCleanupListener::class); + $context->registerEventListener(GroupDeletedEvent::class, ReceiverCleanupListener::class); $context->registerEventListener(CircleDestroyedEvent::class, ReceiverCleanupListener::class); $context->registerSearchProvider(SearchTablesProvider::class); diff --git a/lib/Listener/ReceiverCleanupListener.php b/lib/Listener/ReceiverCleanupListener.php index bde1b7e8e1..f35213c9b2 100644 --- a/lib/Listener/ReceiverCleanupListener.php +++ b/lib/Listener/ReceiverCleanupListener.php @@ -12,11 +12,11 @@ use OCA\Tables\Db\ShareMapper; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; -use OCP\Group\Events\BeforeGroupDeletedEvent; +use OCP\Group\Events\GroupDeletedEvent; use OCP\User\Events\UserDeletedEvent; use Psr\Log\LoggerInterface; -/** @template-implements IEventListener */ +/** @template-implements IEventListener */ class ReceiverCleanupListener implements IEventListener { public function __construct( private ShareMapper $shareMapper, @@ -27,7 +27,7 @@ public function __construct( public function handle(Event $event): void { if ($event instanceof UserDeletedEvent) { $this->cleanupByParticipant(ShareReceiverType::USER, $event->getUser()->getUID()); - } elseif ($event instanceof BeforeGroupDeletedEvent) { + } elseif ($event instanceof GroupDeletedEvent) { $this->cleanupByParticipant(ShareReceiverType::GROUP, $event->getGroup()->getGID()); } elseif ($event instanceof CircleDestroyedEvent) { $this->cleanupByParticipant(ShareReceiverType::CIRCLE, $event->getCircle()->getSingleId());