From d7bd1a82446aad44bf8b78914a0639cd2d9f73f3 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 18 Dec 2020 16:22:15 +0100 Subject: [PATCH 01/19] Add a method to add group members directly to a conversation Signed-off-by: Joas Schilling --- lib/Command/Room/TRoomCommand.php | 9 +-------- lib/Controller/RoomController.php | 27 ++------------------------- lib/Service/ParticipantService.php | 23 +++++++++++++++++++++++ 3 files changed, 26 insertions(+), 33 deletions(-) diff --git a/lib/Command/Room/TRoomCommand.php b/lib/Command/Room/TRoomCommand.php index 06061662bf2..94a2c7869ef 100644 --- a/lib/Command/Room/TRoomCommand.php +++ b/lib/Command/Room/TRoomCommand.php @@ -230,21 +230,14 @@ protected function addRoomParticipantsByGroup(Room $room, array $groupIds): void return; } - $users = []; foreach ($groupIds as $groupId) { $group = $this->groupManager->get($groupId); if ($group === null) { throw new InvalidArgumentException(sprintf("Group '%s' not found.", $groupId)); } - $groupUsers = array_map(function (IUser $user) { - return $user->getUID(); - }, $group->getUsers()); - - $users = array_merge($users, array_values($groupUsers)); + $this->participantService->addGroup($room, $group); } - - $this->addRoomParticipants($room, array_unique($users)); } /** diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php index a0bd1908ffc..4adcbbf398d 100644 --- a/lib/Controller/RoomController.php +++ b/lib/Controller/RoomController.php @@ -673,23 +673,7 @@ protected function createGroupRoom(string $targetGroupName): DataResponse { // Create the room $name = $this->roomService->prepareConversationName($targetGroup->getDisplayName()); $room = $this->roomService->createConversation(Room::GROUP_CALL, $name, $currentUser); - - $usersInGroup = $targetGroup->getUsers(); - $participants = []; - foreach ($usersInGroup as $user) { - if ($currentUser->getUID() === $user->getUID()) { - // Owner is already added. - continue; - } - - $participants[] = [ - 'actorType' => Attendee::ACTOR_USERS, - 'actorId' => $user->getUID(), - 'displayName' => $user->getDisplayName(), - ]; - } - - $this->participantService->addUsers($room, $participants); + $this->participantService->addGroup($room, $targetGroup); return new DataResponse($this->formatRoom($room, $room->getParticipant($currentUser->getUID(), false)), Http::STATUS_CREATED); } @@ -1050,14 +1034,7 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u return new DataResponse([], Http::STATUS_NOT_FOUND); } - $usersInGroup = $group->getUsers(); - foreach ($usersInGroup as $user) { - $participantsToAdd[] = [ - 'actorType' => Attendee::ACTOR_USERS, - 'actorId' => $user->getUID(), - 'displayName' => $user->getDisplayName(), - ]; - } + $this->participantService->addGroup($this->room, $group); } elseif ($source === 'circles') { if (!$this->appManager->isEnabledForUser('circles')) { return new DataResponse([], Http::STATUS_BAD_REQUEST); diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index 867a664af43..0ae59bf7b35 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -50,6 +50,7 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IDBConnection; +use OCP\IGroup; use OCP\IUser; use OCP\IUserManager; use OCP\IGroupManager; @@ -300,6 +301,28 @@ public function addUsers(Room $room, array $participants): void { $this->dispatcher->dispatch(Room::EVENT_AFTER_USERS_ADD, $event); } + public function addGroup(Room $room, IGroup $group): void { + $usersInGroup = $group->getUsers(); + + $participants = $this->getParticipantUserIds($room); + + $newParticipants = []; + foreach ($usersInGroup as $user) { + if (in_array($user->getUID(), $participants, true)) { + // Participant is already in the conversation, so skip them. + continue; + } + + $newParticipants[] = [ + 'actorType' => Attendee::ACTOR_USERS, + 'actorId' => $user->getUID(), + 'displayName' => $user->getDisplayName(), + ]; + } + + $this->addUsers($room, $newParticipants); + } + /** * @param Room $room * @param string $email From db91242f45ff9ed40b266fa1e8403c5fbf806eca Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 18 Dec 2020 16:35:18 +0100 Subject: [PATCH 02/19] Keep track of added groups Signed-off-by: Joas Schilling --- lib/Model/Attendee.php | 1 + lib/Service/ParticipantService.php | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/lib/Model/Attendee.php b/lib/Model/Attendee.php index 40d4663db23..d70e05495a6 100644 --- a/lib/Model/Attendee.php +++ b/lib/Model/Attendee.php @@ -52,6 +52,7 @@ */ class Attendee extends Entity { public const ACTOR_USERS = 'users'; + public const ACTOR_GROUP = 'group'; public const ACTOR_GUESTS = 'guests'; public const ACTOR_EMAILS = 'emails'; diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index 0ae59bf7b35..3f14164151f 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -320,6 +320,24 @@ public function addGroup(Room $room, IGroup $group): void { ]; } + try { + $this->attendeeMapper->findByActor($room->getId(), Attendee::ACTOR_GROUP, $group->getGID()); + } catch (DoesNotExistException $e) { + $lastMessage = 0; + if ($room->getLastMessage() instanceof IComment) { + $lastMessage = (int) $room->getLastMessage()->getId(); + } + + $attendee = new Attendee(); + $attendee->setRoomId($room->getId()); + $attendee->setActorType(Attendee::ACTOR_GROUP); + $attendee->setActorId($group->getGID()); + $attendee->setParticipantType(Participant::USER); + $attendee->setLastReadMessage($lastMessage); + $attendee->setReadPrivacy(Participant::PRIVACY_PUBLIC); + $this->attendeeMapper->insert($attendee); + } + $this->addUsers($room, $newParticipants); } From 2db230b4042aef1932df3d8170cd6420288f3864 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 18 Dec 2020 16:54:39 +0100 Subject: [PATCH 03/19] Add and remove users from conversations when their group membership changes Signed-off-by: Joas Schilling --- lib/AppInfo/Application.php | 5 ++ lib/Listener/GroupMembershipListener.php | 100 +++++++++++++++++++++++ lib/Manager.php | 17 +++- 3 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 lib/Listener/GroupMembershipListener.php diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 56a25854ab9..a02cde54ca4 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -45,6 +45,7 @@ use OCA\Talk\Listener\BeforeUserLoggedOutListener; use OCA\Talk\Listener\CSPListener; use OCA\Talk\Listener\FeaturePolicyListener; +use OCA\Talk\Listener\GroupMembershipListener; use OCA\Talk\Listener\RestrictStartingCalls as RestrictStartingCallsListener; use OCA\Talk\Listener\UserDeletedListener; use OCA\Talk\Listener\UserDisplayNameListener; @@ -71,6 +72,8 @@ use OCP\AppFramework\Utility\ITimeFactory; use OCP\Collaboration\Resources\IProviderManager; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Group\Events\UserAddedEvent; +use OCP\Group\Events\UserRemovedEvent; use OCP\IServerContainer; use OCP\IUser; use OCP\Security\CSP\AddContentSecurityPolicyEvent; @@ -95,6 +98,8 @@ public function register(IRegistrationContext $context): void { $context->registerEventListener(AddContentSecurityPolicyEvent::class, CSPListener::class); $context->registerEventListener(AddFeaturePolicyEvent::class, FeaturePolicyListener::class); $context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class); + $context->registerEventListener(UserAddedEvent::class, GroupMembershipListener::class); + $context->registerEventListener(UserRemovedEvent::class, GroupMembershipListener::class); $context->registerEventListener(BeforeUserLoggedOutEvent::class, BeforeUserLoggedOutListener::class); $context->registerEventListener(BeforeTemplateRenderedEvent::class, PublicShareTemplateLoader::class); $context->registerEventListener(BeforeTemplateRenderedEvent::class, PublicShareAuthTemplateLoader::class); diff --git a/lib/Listener/GroupMembershipListener.php b/lib/Listener/GroupMembershipListener.php new file mode 100644 index 00000000000..7c0bd129476 --- /dev/null +++ b/lib/Listener/GroupMembershipListener.php @@ -0,0 +1,100 @@ + + * + * @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 . + * + */ + +namespace OCA\Talk\Listener; + +use OCA\Talk\Manager; +use OCA\Talk\Model\Attendee; +use OCA\Talk\Room; +use OCA\Talk\Service\ParticipantService; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\Group\Events\UserAddedEvent; +use OCP\Group\Events\UserRemovedEvent; +use OCP\IGroup; +use OCP\IGroupManager; +use OCP\IUser; + +class GroupMembershipListener implements IEventListener { + + /** @var IGroupManager */ + private $groupManager; + /** @var Manager */ + private $manager; + /** @var ParticipantService */ + private $participantService; + + public function __construct(IGroupManager $groupManager, + Manager $manager, + ParticipantService $participantService) { + $this->groupManager = $groupManager; + $this->manager = $manager; + $this->participantService = $participantService; + } + + public function handle(Event $event): void { + if ($event instanceof UserAddedEvent) { + $this->addNewMemberToRooms($event->getGroup(), $event->getUser()); + } + if ($event instanceof UserRemovedEvent) { + $this->removeFormerMemberFromRooms($event->getGroup(), $event->getUser()); + } + } + + protected function addNewMemberToRooms(IGroup $group, IUser $user): void { + $rooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUP, $group->getGID()); + + foreach ($rooms as $room) { + $this->participantService->addUsers($room, [[ + 'actorType' => Attendee::ACTOR_USERS, + 'actorId' => $user->getUID(), + ]]); + } + } + + protected function removeFormerMemberFromRooms(IGroup $group, IUser $user): void { + $rooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUP, $group->getGID()); + if (empty($rooms)) { + return; + } + + $userGroupIds = $this->groupManager->getUserGroupIds($user); + + $furtherMemberships = []; + foreach ($userGroupIds as $groupId) { + $groupRooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUP, $groupId); + foreach ($groupRooms as $room) { + $furtherMemberships[$room->getId()] = true; + } + } + + $rooms = array_filter($rooms, static function (Room $room) use ($furtherMemberships) { + // Only delete from rooms where the user is not member via another group + return !isset($furtherMemberships[$room->getId()]); + }); + + foreach ($rooms as $room) { + $this->participantService->removeUser($room, $user, Room::PARTICIPANT_REMOVED); + } + } +} diff --git a/lib/Manager.php b/lib/Manager.php index 30861c33836..dc7b034850c 100644 --- a/lib/Manager.php +++ b/lib/Manager.php @@ -304,14 +304,25 @@ public function searchRoomsByToken(string $searchToken = '', int $limit = null, * @return Room[] */ public function getRoomsForUser(string $userId, array $sessionIds = [], bool $includeLastMessage = false): array { + return $this->getRoomsForActor(Attendee::ACTOR_USERS, $userId, $sessionIds, $includeLastMessage); + } + + /** + * @param string $actorType + * @param string $actorId + * @param array $sessionIds A list of talk sessions to consider for loading (otherwise no session is loaded) + * @param bool $includeLastMessage + * @return Room[] + */ + public function getRoomsForActor(string $actorType, string $actorId, array $sessionIds = [], bool $includeLastMessage = false): array { $query = $this->db->getQueryBuilder(); $helper = new SelectHelper(); $helper->selectRoomsTable($query); $helper->selectAttendeesTable($query); $query->from('talk_rooms', 'r') ->leftJoin('r', 'talk_attendees', 'a', $query->expr()->andX( - $query->expr()->eq('a.actor_id', $query->createNamedParameter($userId)), - $query->expr()->eq('a.actor_type', $query->createNamedParameter(Attendee::ACTOR_USERS)), + $query->expr()->eq('a.actor_id', $query->createNamedParameter($actorId)), + $query->expr()->eq('a.actor_type', $query->createNamedParameter($actorType)), $query->expr()->eq('a.room_id', 'r.id') )) ->where($query->expr()->isNotNull('a.id')); @@ -337,7 +348,7 @@ public function getRoomsForUser(string $userId, array $sessionIds = [], bool $in } $room = $this->createRoomObject($row); - if ($userId !== null && isset($row['actor_id'])) { + if ($actorType === Attendee::ACTOR_USERS && isset($row['actor_id'])) { $room->setParticipant($row['actor_id'], $this->createParticipantObject($room, $row)); } $rooms[] = $room; From b37dade08f4e33c309f1b7bade1de4ea42e01988 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 25 Mar 2021 15:07:06 +0100 Subject: [PATCH 04/19] Fix constant value to plural Signed-off-by: Joas Schilling --- lib/Listener/GroupMembershipListener.php | 6 +++--- lib/Model/Attendee.php | 2 +- lib/Service/ParticipantService.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Listener/GroupMembershipListener.php b/lib/Listener/GroupMembershipListener.php index 7c0bd129476..af3a5f847c4 100644 --- a/lib/Listener/GroupMembershipListener.php +++ b/lib/Listener/GroupMembershipListener.php @@ -62,7 +62,7 @@ public function handle(Event $event): void { } protected function addNewMemberToRooms(IGroup $group, IUser $user): void { - $rooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUP, $group->getGID()); + $rooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUPS, $group->getGID()); foreach ($rooms as $room) { $this->participantService->addUsers($room, [[ @@ -73,7 +73,7 @@ protected function addNewMemberToRooms(IGroup $group, IUser $user): void { } protected function removeFormerMemberFromRooms(IGroup $group, IUser $user): void { - $rooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUP, $group->getGID()); + $rooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUPS, $group->getGID()); if (empty($rooms)) { return; } @@ -82,7 +82,7 @@ protected function removeFormerMemberFromRooms(IGroup $group, IUser $user): void $furtherMemberships = []; foreach ($userGroupIds as $groupId) { - $groupRooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUP, $groupId); + $groupRooms = $this->manager->getRoomsForActor(Attendee::ACTOR_GROUPS, $groupId); foreach ($groupRooms as $room) { $furtherMemberships[$room->getId()] = true; } diff --git a/lib/Model/Attendee.php b/lib/Model/Attendee.php index d70e05495a6..d840a9fd446 100644 --- a/lib/Model/Attendee.php +++ b/lib/Model/Attendee.php @@ -52,7 +52,7 @@ */ class Attendee extends Entity { public const ACTOR_USERS = 'users'; - public const ACTOR_GROUP = 'group'; + public const ACTOR_GROUPS = 'groups'; public const ACTOR_GUESTS = 'guests'; public const ACTOR_EMAILS = 'emails'; diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index 3f14164151f..66674eeb769 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -321,7 +321,7 @@ public function addGroup(Room $room, IGroup $group): void { } try { - $this->attendeeMapper->findByActor($room->getId(), Attendee::ACTOR_GROUP, $group->getGID()); + $this->attendeeMapper->findByActor($room->getId(), Attendee::ACTOR_GROUPS, $group->getGID()); } catch (DoesNotExistException $e) { $lastMessage = 0; if ($room->getLastMessage() instanceof IComment) { @@ -330,7 +330,7 @@ public function addGroup(Room $room, IGroup $group): void { $attendee = new Attendee(); $attendee->setRoomId($room->getId()); - $attendee->setActorType(Attendee::ACTOR_GROUP); + $attendee->setActorType(Attendee::ACTOR_GROUPS); $attendee->setActorId($group->getGID()); $attendee->setParticipantType(Participant::USER); $attendee->setLastReadMessage($lastMessage); From b532b28bba8a7aed13d64819e1d381fd0bd5aaf3 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 25 Mar 2021 15:07:22 +0100 Subject: [PATCH 05/19] Fix command integration tests Signed-off-by: Joas Schilling --- tests/integration/features/command/create.feature | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration/features/command/create.feature b/tests/integration/features/command/create.feature index 3febbfdd49d..21667e76f46 100644 --- a/tests/integration/features/command/create.feature +++ b/tests/integration/features/command/create.feature @@ -52,6 +52,7 @@ Feature: create And user "participant1" sees the following attendees in room "room1" with 200 (v4) | actorType | actorId | participantType | | users | participant1 | 1 | + | groups | group1 | 3 | | users | participant2 | 3 | Scenario: Create a public room for participant1 as owner group1 as users with password and readonly and listable @@ -67,6 +68,7 @@ Feature: create And user "participant1" sees the following attendees in room "room1" with 200 (v4) | actorType | actorId | participantType | | users | participant1 | 1 | + | groups | group1 | 3 | | users | participant2 | 3 | From 9edff03d3e5bcdc92a4f7e9f7f4a2994d9f0e13a Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 25 Mar 2021 16:07:08 +0100 Subject: [PATCH 06/19] Add expected group to output Signed-off-by: Joas Schilling --- tests/integration/features/conversation/add-participant.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/features/conversation/add-participant.feature b/tests/integration/features/conversation/add-participant.feature index 7be8b1db4ca..81e340c598b 100644 --- a/tests/integration/features/conversation/add-participant.feature +++ b/tests/integration/features/conversation/add-participant.feature @@ -105,6 +105,7 @@ Feature: public | actorType | actorId | participantType | | users | participant1 | 1 | | users | participant2 | 3 | + | groups | group1 | 3 | | users | participant3 | 3 | And user "participant3" is participant of the following rooms (v4) | id | type | participantType | From 55981dbbefab86bd71651e3cca9111d60a44a61e Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 25 Mar 2021 16:07:23 +0100 Subject: [PATCH 07/19] Make sure existing self-joined users are converted to added users Signed-off-by: Joas Schilling --- lib/Controller/RoomController.php | 2 +- lib/Service/ParticipantService.php | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php index 4adcbbf398d..3891edc998c 100644 --- a/lib/Controller/RoomController.php +++ b/lib/Controller/RoomController.php @@ -1034,7 +1034,7 @@ public function addParticipantToRoom(string $newParticipant, string $source = 'u return new DataResponse([], Http::STATUS_NOT_FOUND); } - $this->participantService->addGroup($this->room, $group); + $this->participantService->addGroup($this->room, $group, $participants); } elseif ($source === 'circles') { if (!$this->appManager->isEnabledForUser('circles')) { return new DataResponse([], Http::STATUS_BAD_REQUEST); diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index 66674eeb769..2b04f7f248f 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -301,14 +301,33 @@ public function addUsers(Room $room, array $participants): void { $this->dispatcher->dispatch(Room::EVENT_AFTER_USERS_ADD, $event); } - public function addGroup(Room $room, IGroup $group): void { + /** + * @param Room $room + * @param IGroup $group + * @param Participant[] $existingParticipants + */ + public function addGroup(Room $room, IGroup $group, array $existingParticipants = []): void { $usersInGroup = $group->getUsers(); - $participants = $this->getParticipantUserIds($room); + if (empty($existingParticipants)) { + $participants = $this->getParticipantsForRoom($room); + } + + $participantsByUserId = []; + foreach ($existingParticipants as $participant) { + if ($participant->getAttendee()->getActorType() === Attendee::ACTOR_USERS) { + $participantsByUserId[$participant->getAttendee()->getActorId()] = $participant; + } + } $newParticipants = []; foreach ($usersInGroup as $user) { - if (in_array($user->getUID(), $participants, true)) { + $existingParticipant = $participantsByUserId[$user->getUID()] ?? null; + if ($existingParticipant instanceof Participant) { + if ($existingParticipant->getAttendee()->getParticipantType() === Participant::USER_SELF_JOINED) { + $this->updateParticipantType($room, $existingParticipant, Participant::USER); + } + // Participant is already in the conversation, so skip them. continue; } From 4ccc537c14a7659a42af6c616a78b8aef1e8ec3d Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 25 Mar 2021 16:38:10 +0100 Subject: [PATCH 08/19] Save and show the display name of groups Signed-off-by: Joas Schilling --- lib/Controller/RoomController.php | 2 ++ lib/Service/ParticipantService.php | 1 + 2 files changed, 3 insertions(+) diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php index 3891edc998c..9c55e67c5d3 100644 --- a/lib/Controller/RoomController.php +++ b/lib/Controller/RoomController.php @@ -979,6 +979,8 @@ public function getParticipants(bool $includeStatus = false): DataResponse { continue; } + $result['displayName'] = $participant->getAttendee()->getDisplayName(); + } elseif ($participant->getAttendee()->getActorType() === Attendee::ACTOR_GROUPS) { $result['displayName'] = $participant->getAttendee()->getDisplayName(); } diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index 2b04f7f248f..00e81bbcd4c 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -351,6 +351,7 @@ public function addGroup(Room $room, IGroup $group, array $existingParticipants $attendee->setRoomId($room->getId()); $attendee->setActorType(Attendee::ACTOR_GROUPS); $attendee->setActorId($group->getGID()); + $attendee->setDisplayName($group->getDisplayName()); $attendee->setParticipantType(Participant::USER); $attendee->setLastReadMessage($lastMessage); $attendee->setReadPrivacy(Participant::PRIVACY_PUBLIC); From 1e666027b393cb1da0e2400aa4b12faaaa1d95ca Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 25 Mar 2021 17:05:20 +0100 Subject: [PATCH 09/19] Show groups at the end and don't allow promoting Signed-off-by: Joas Schilling --- .../CurrentParticipants/CurrentParticipants.vue | 17 ++++++++++++++++- .../Participant/Participant.vue | 12 ++++++++++-- src/constants.js | 1 + 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/components/RightSidebar/Participants/CurrentParticipants/CurrentParticipants.vue b/src/components/RightSidebar/Participants/CurrentParticipants/CurrentParticipants.vue index 97797426a0c..b2e91f7cd8f 100644 --- a/src/components/RightSidebar/Participants/CurrentParticipants/CurrentParticipants.vue +++ b/src/components/RightSidebar/Participants/CurrentParticipants/CurrentParticipants.vue @@ -32,7 +32,7 @@