diff options
author | Joas Schilling <coding@schilljs.com> | 2021-08-25 18:30:20 +0300 |
---|---|---|
committer | Joas Schilling <coding@schilljs.com> | 2021-08-25 18:30:20 +0300 |
commit | a073dc4f5ef63b5c068a56aa69b4178757b237cc (patch) | |
tree | a9629d60f103cbaac205fcee8af79839f6df9fb7 /lib | |
parent | 1253bb22e8a0dee0a7f7eb25d629800ce40e7dca (diff) |
Also remove circle members when removing a circle
Signed-off-by: Joas Schilling <coding@schilljs.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Service/MembershipService.php | 122 | ||||
-rw-r--r-- | lib/Service/ParticipantService.php | 92 |
2 files changed, 198 insertions, 16 deletions
diff --git a/lib/Service/MembershipService.php b/lib/Service/MembershipService.php new file mode 100644 index 000000000..511d89a9b --- /dev/null +++ b/lib/Service/MembershipService.php @@ -0,0 +1,122 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Talk\Service; + +use OCA\Circles\CirclesManager; +use OCA\Circles\Model\Member; +use OCA\Circles\Model\Membership; +use OCA\Talk\Model\Attendee; +use OCA\Talk\Model\AttendeeMapper; +use OCA\Talk\Room; +use OCP\App\IAppManager; +use OCP\IGroupManager; +use OCP\IUser; +use Psr\Log\LoggerInterface; + +class MembershipService { + + /** @var IAppManager */ + protected $appManager; + /** @var IGroupManager */ + protected $groupManager; + /** @var AttendeeMapper */ + protected $attendeeMapper; + + public function __construct(IAppManager $appManager, + IGroupManager $groupManager, + AttendeeMapper $attendeeMapper) { + $this->appManager = $appManager; + $this->groupManager = $groupManager; + $this->attendeeMapper = $attendeeMapper; + } + + /** + * @param Room $room + * @param IUser[] $users + * @return IUser[] + */ + public function getUsersWithoutOtherMemberships(Room $room, array $users): array { + $users = $this->filterUsersWithOtherGroupMemberships($room, $users); + $users = $this->filterUsersWithOtherCircleMemberships($room, $users); + return $users; + } + + /** + * @param Room $room + * @param IUser[] $users + * @return IUser[] + */ + protected function filterUsersWithOtherGroupMemberships(Room $room, array $users): array { + $groupAttendees = $this->attendeeMapper->getActorsByType($room->getId(), Attendee::ACTOR_GROUPS); + $groupIds = array_map(static function(Attendee $attendee) { + return $attendee->getActorId(); + }, $groupAttendees); + + if (empty($groupIds)) { + return $users; + } + + return array_filter($users, function (IUser $user) use ($groupIds) { + // Only delete users when the user is not member via another group + $userGroups = $this->groupManager->getUserGroupIds($user); + return empty(array_intersect($userGroups, $groupIds)); + }); + } + + /** + * @param Room $room + * @param IUser[] $users + * @return IUser[] + */ + protected function filterUsersWithOtherCircleMemberships(Room $room, array $users): array { + if (empty($users)) { + return $users; + } + $anyUser = reset($users); + if (!$this->appManager->isEnabledForUser('circles', $anyUser)) { + \OC::$server->get(LoggerInterface::class)->debug('Circles not enabled', ['app' => 'spreed']); + return $users; + } + + $circleAttendees = $this->attendeeMapper->getActorsByType($room->getId(), Attendee::ACTOR_CIRCLES); + $circleIds = array_map(static function(Attendee $attendee) { + return $attendee->getActorId(); + }, $circleAttendees); + + if (empty($circleIds)) { + return $users; + } + + $circlesManager = \OC::$server->get(CirclesManager::class); + return array_filter($users, function (IUser $user) use ($circlesManager, $circleIds) { + // Only delete users when the user is not member via another circle + $federatedUser = $circlesManager->getFederatedUser($user->getUID(), Member::TYPE_USER); + $memberships = $federatedUser->getMemberships(); + $userCircles = array_map(static function(Membership $membership) { + return $membership->getCircleId(); + }, $memberships); + return empty(array_intersect($userCircles, $circleIds)); + }); + } +} diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index a79dc5f71..d564a2e47 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -82,6 +82,8 @@ class ParticipantService { private $userManager; /** @var IGroupManager */ private $groupManager; + /** @var MembershipService */ + private $membershipService; /** @var ITimeFactory */ private $timeFactory; @@ -95,6 +97,7 @@ class ParticipantService { IEventDispatcher $dispatcher, IUserManager $userManager, IGroupManager $groupManager, + MembershipService $membershipService, ITimeFactory $timeFactory) { $this->serverConfig = $serverConfig; $this->talkConfig = $talkConfig; @@ -106,6 +109,7 @@ class ParticipantService { $this->dispatcher = $dispatcher; $this->userManager = $userManager; $this->groupManager = $groupManager; + $this->membershipService = $membershipService; $this->timeFactory = $timeFactory; } @@ -426,7 +430,7 @@ class ParticipantService { } catch (\Exception $e) { } - $circlesManager->stopSession($federatedUser); + $circlesManager->stopSession(); throw new ParticipantNotFoundException('Circle not found or not a member'); } @@ -629,40 +633,96 @@ class ParticipantService { if ($participant->getAttendee()->getActorType() === Attendee::ACTOR_GROUPS) { $this->removeGroupMembers($room, $participant, $reason); + } else if ($participant->getAttendee()->getActorType() === Attendee::ACTOR_CIRCLES) { + $this->removeCircleMembers($room, $participant, $reason); } } + public function getActorsByType(Room $room, string $actorType): array { + return $this->attendeeMapper->getActorsByType($room->getId(), $actorType); + } + public function removeGroupMembers(Room $room, Participant $removedGroupParticipant, string $reason): void { $removedGroup = $this->groupManager->get($removedGroupParticipant->getAttendee()->getActorId()); if (!$removedGroup instanceof IGroup) { return; } - $attendeeGroups = $this->attendeeMapper->getActorsByType($room->getId(), Attendee::ACTOR_GROUPS); - - $groupsInRoom = []; - foreach ($attendeeGroups as $attendee) { - $groupsInRoom[] = $attendee->getActorId(); - } - + $users = $this->membershipService->getUsersWithoutOtherMemberships($room, $removedGroup->getUsers()); $attendees = []; - foreach ($removedGroup->getUsers() as $user) { + foreach ($users as $user) { try { $participant = $room->getParticipant($user->getUID()); + $participantType = $participant->getAttendee()->getParticipantType(); + + $attendees[] = $participant->getAttendee(); + if ($participantType === Participant::USER) { + // Only remove normal users, not moderators/admins + $this->removeAttendee($room, $participant, $reason, true); + } } catch (ParticipantNotFoundException $e) { + } + } + + $attendeeEvent = new AttendeesRemovedEvent($room, $attendees); + $this->dispatcher->dispatchTyped($attendeeEvent); + } + + public function removeCircleMembers(Room $room, Participant $removedCircleParticipant, string $reason): void { + try { + $circlesManager = \OC::$server->get(CirclesManager::class); + $circlesManager->startSuperSession(); + $circle = $circlesManager->getCircle($removedCircleParticipant->getAttendee()->getActorId()); + $circlesManager->stopSession(); + } catch (\Exception $e) { + // Circles not enabled + return; + } + + $circlesManager->startSuperSession(); + try { + $circle = $circlesManager->getCircle($removedCircleParticipant->getAttendee()->getActorId()); + $circlesManager->stopSession(); + } catch (\Exception $e) { + $circlesManager->stopSession(); + return; + } + + $membersInCircle = $circle->getInheritedMembers(); + $users = []; + foreach ($membersInCircle as $member) { + /** @var Member $member */ + if ($member->getUserType() !== Member::TYPE_USER || $member->getUserId() === '') { + // Not a user? continue; } - $userGroups = $this->groupManager->getUserGroupIds($user); - $stillHasGroup = array_intersect($userGroups, $groupsInRoom); - if (!empty($stillHasGroup)) { + if ($member->getStatus() !== Member::STATUS_INVITED && $member->getStatus() !== Member::STATUS_MEMBER) { + // Only allow invited and regular members continue; } - $attendees[] = $participant->getAttendee(); - if ($participant->getAttendee()->getParticipantType() === Participant::USER) { - // Only remove normal users, not moderators/admins - $this->removeAttendee($room, $participant, $reason, true); + $users[] = $this->userManager->get($member->getUserId()); + } + + + if (empty($users)) { + return; + } + + $users = $this->membershipService->getUsersWithoutOtherMemberships($room, $users); + $attendees = []; + foreach ($users as $user) { + try { + $participant = $room->getParticipant($user->getUID()); + $participantType = $participant->getAttendee()->getParticipantType(); + + $attendees[] = $participant->getAttendee(); + if ($participantType === Participant::USER) { + // Only remove normal users, not moderators/admins + $this->removeAttendee($room, $participant, $reason, true); + } + } catch (ParticipantNotFoundException $e) { } } |