diff options
-rw-r--r-- | docs/chat.md | 2 | ||||
-rw-r--r-- | lib/AppInfo/Application.php | 4 | ||||
-rw-r--r-- | lib/Chat/Parser/SystemMessage.php | 44 | ||||
-rw-r--r-- | lib/Chat/SystemMessage/Listener.php | 30 | ||||
-rw-r--r-- | lib/Events/AttendeesAddedEvent.php | 27 | ||||
-rw-r--r-- | lib/Events/AttendeesEvent.php | 45 | ||||
-rw-r--r-- | lib/Events/AttendeesRemovedEvent.php | 27 | ||||
-rw-r--r-- | lib/Service/ParticipantService.php | 46 |
8 files changed, 222 insertions, 3 deletions
diff --git a/docs/chat.md b/docs/chat.md index d3da178b8..d102a1b18 100644 --- a/docs/chat.md +++ b/docs/chat.md @@ -261,6 +261,8 @@ See [OCP\RichObjectStrings\Definitions](https://github.com/nextcloud/server/blob * `password_removed` - {actor} removed the password for the conversation * `user_added` - {actor} added {user} to the conversation * `user_removed` - {actor} removed {user} from the conversation +* `group_added` - {actor} added group {group} to the conversation +* `group_removed` - {actor} removed group {group} from the conversation * `moderator_promoted` - {actor} promoted {user} to moderator * `moderator_demoted` - {actor} demoted {user} from moderator * `guest_moderator_promoted` - {actor} promoted {user} to moderator diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 9f624d178..f18a1c2ae 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -36,6 +36,8 @@ use OCA\Talk\Collaboration\Resources\ConversationProvider; use OCA\Talk\Collaboration\Resources\Listener as ResourceListener; use OCA\Talk\Config; use OCA\Talk\Dashboard\TalkWidget; +use OCA\Talk\Events\AttendeesAddedEvent; +use OCA\Talk\Events\AttendeesRemovedEvent; use OCA\Talk\Events\ChatEvent; use OCA\Talk\Events\RoomEvent; use OCA\Talk\Deck\DeckPluginLoader; @@ -111,6 +113,8 @@ class Application extends App implements IBootstrap { $context->registerEventListener(UserChangedEvent::class, UserDisplayNameListener::class); $context->registerEventListener(\OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent::class, DeckPluginLoader::class); $context->registerEventListener(RegisterOperationsEvent::class, RegisterOperationsListener::class); + $context->registerEventListener(AttendeesAddedEvent::class, SystemMessageListener::class); + $context->registerEventListener(AttendeesRemovedEvent::class, SystemMessageListener::class); $context->registerSearchProvider(ConversationSearch::class); $context->registerSearchProvider(CurrentMessageSearch::class); diff --git a/lib/Chat/Parser/SystemMessage.php b/lib/Chat/Parser/SystemMessage.php index 669ac3f8a..ce71303c0 100644 --- a/lib/Chat/Parser/SystemMessage.php +++ b/lib/Chat/Parser/SystemMessage.php @@ -35,6 +35,8 @@ use OCP\Files\InvalidPathException; use OCP\Files\IRootFolder; use OCP\Files\Node; use OCP\Files\NotFoundException; +use OCP\IGroup; +use OCP\IGroupManager; use OCP\IL10N; use OCP\IPreview as IPreviewManager; use OCP\IURLGenerator; @@ -46,6 +48,8 @@ class SystemMessage { /** @var IUserManager */ protected $userManager; + /** @var IGroupManager */ + protected $groupManager; /** @var GuestManager */ protected $guestManager; /** @var IPreviewManager */ @@ -62,15 +66,19 @@ class SystemMessage { /** @var string[] */ protected $displayNames = []; /** @var string[] */ + protected $groupNames = []; + /** @var string[] */ protected $guestNames = []; public function __construct(IUserManager $userManager, + IGroupManager $groupManager, GuestManager $guestManager, IPreviewManager $previewManager, RoomShareProvider $shareProvider, IRootFolder $rootFolder, IURLGenerator $url) { $this->userManager = $userManager; + $this->groupManager = $groupManager; $this->guestManager = $guestManager; $this->previewManager = $previewManager; $this->shareProvider = $shareProvider; @@ -270,6 +278,22 @@ class SystemMessage { $parsedMessage = $this->l->t('An administrator removed {user}'); } } + } elseif ($message === 'group_added') { + $parsedParameters['group'] = $this->getGroup($parameters['group']); + $parsedMessage = $this->l->t('{actor} added group {group}'); + if ($currentUserIsActor) { + $parsedMessage = $this->l->t('You added group {group}'); + } elseif ($cliIsActor) { + $parsedMessage = $this->l->t('An administrator added group {group}'); + } + } elseif ($message === 'group_removed') { + $parsedParameters['group'] = $this->getGroup($parameters['group']); + $parsedMessage = $this->l->t('{actor} removed group {group}'); + if ($currentUserIsActor) { + $parsedMessage = $this->l->t('You removed group {group}'); + } elseif ($cliIsActor) { + $parsedMessage = $this->l->t('An administrator removed group {group}'); + } } elseif ($message === 'moderator_promoted') { $parsedParameters['user'] = $this->getUser($parameters['user']); $parsedMessage = $this->l->t('{actor} promoted {user} to moderator'); @@ -519,6 +543,18 @@ class SystemMessage { ]; } + protected function getGroup(string $gid): array { + if (!isset($this->groupNames[$gid])) { + $this->groupNames[$gid] = $this->getDisplayNameGroup($gid); + } + + return [ + 'type' => 'group', + 'id' => $gid, + 'name' => $this->groupNames[$gid], + ]; + } + protected function getDisplayName(string $uid): string { $user = $this->userManager->get($uid); if ($user instanceof IUser) { @@ -527,6 +563,14 @@ class SystemMessage { return $uid; } + protected function getDisplayNameGroup(string $gid): string { + $group = $this->groupManager->get($gid); + if ($group instanceof IGroup) { + return $group->getDisplayName(); + } + return $gid; + } + protected function getGuest(Room $room, string $actorId): array { if (!isset($this->guestNames[$actorId])) { $this->guestNames[$actorId] = $this->getGuestName($room, $actorId); diff --git a/lib/Chat/SystemMessage/Listener.php b/lib/Chat/SystemMessage/Listener.php index c36af4980..4b1facb3e 100644 --- a/lib/Chat/SystemMessage/Listener.php +++ b/lib/Chat/SystemMessage/Listener.php @@ -25,6 +25,8 @@ namespace OCA\Talk\Chat\SystemMessage; use OCA\Talk\Chat\ChatManager; use OCA\Talk\Events\AddParticipantsEvent; +use OCA\Talk\Events\AttendeesAddedEvent; +use OCA\Talk\Events\AttendeesRemovedEvent; use OCA\Talk\Events\ModifyLobbyEvent; use OCA\Talk\Events\ModifyParticipantEvent; use OCA\Talk\Events\ModifyRoomEvent; @@ -40,14 +42,16 @@ use OCA\Talk\Share\RoomShareProvider; use OCA\Talk\TalkSession; use OCA\Talk\Webinary; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventDispatcher; +use OCP\EventDispatcher\IEventListener; use OCP\IRequest; use OCP\IUser; use OCP\IUserSession; use OCP\Share\IShare; use Symfony\Component\EventDispatcher\GenericEvent; -class Listener { +class Listener implements IEventListener { /** @var IRequest */ protected $request; @@ -331,6 +335,30 @@ class Listener { $dispatcher->addListener(RoomShareProvider::class . '::' . 'share_file_again', $listener); } + public function handle(Event $event): void { + if ($event instanceof AttendeesAddedEvent) { + $this->attendeesAddedEvent($event); + } elseif ($event instanceof AttendeesRemovedEvent) { + $this->attendeesRemovedEvent($event); + } + } + + protected function attendeesAddedEvent(AttendeesAddedEvent $event): void { + foreach ($event->getAttendees() as $attendee) { + if ($attendee->getActorType() === Attendee::ACTOR_GROUPS) { + $this->sendSystemMessage($event->getRoom(), 'group_added', ['group' => $attendee->getActorId()]); + } + } + } + + protected function attendeesRemovedEvent(AttendeesRemovedEvent $event): void { + foreach ($event->getAttendees() as $attendee) { + if ($attendee->getActorType() === Attendee::ACTOR_GROUPS) { + $this->sendSystemMessage($event->getRoom(), 'group_removed', ['group' => $attendee->getActorId()]); + } + } + } + protected function sendSystemMessage(Room $room, string $message, array $parameters = [], Participant $participant = null): void { if ($participant instanceof Participant) { $actorType = $participant->getAttendee()->getActorType(); diff --git a/lib/Events/AttendeesAddedEvent.php b/lib/Events/AttendeesAddedEvent.php new file mode 100644 index 000000000..c7b684b26 --- /dev/null +++ b/lib/Events/AttendeesAddedEvent.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2021 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\Events; + +class AttendeesAddedEvent extends AttendeesEvent { +} diff --git a/lib/Events/AttendeesEvent.php b/lib/Events/AttendeesEvent.php new file mode 100644 index 000000000..c78998b6b --- /dev/null +++ b/lib/Events/AttendeesEvent.php @@ -0,0 +1,45 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2021 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\Events; + +use OCA\Talk\Model\Attendee; +use OCA\Talk\Room; + +class AttendeesEvent extends RoomEvent { + /** @var Attendee[] */ + protected $attendees; + + public function __construct(Room $room, + array $attendees) { + parent::__construct($room); + $this->attendees = $attendees; + } + + /** + * @return Attendee[] + */ + public function getAttendees(): array { + return $this->attendees; + } +} diff --git a/lib/Events/AttendeesRemovedEvent.php b/lib/Events/AttendeesRemovedEvent.php new file mode 100644 index 000000000..fe93b19bb --- /dev/null +++ b/lib/Events/AttendeesRemovedEvent.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2021 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\Events; + +class AttendeesRemovedEvent extends AttendeesEvent { +} diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index 2d1762dcc..54f2c398d 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -27,6 +27,8 @@ use OCA\Circles\Model\Circle; use OCA\Circles\Model\Member; use OCA\Talk\Config; use OCA\Talk\Events\AddParticipantsEvent; +use OCA\Talk\Events\AttendeesAddedEvent; +use OCA\Talk\Events\AttendeesRemovedEvent; use OCA\Talk\Events\JoinRoomGuestEvent; use OCA\Talk\Events\JoinRoomUserEvent; use OCA\Talk\Events\ModifyParticipantEvent; @@ -275,6 +277,9 @@ class ParticipantService { $attendee->setParticipantType(Participant::GUEST); $attendee->setLastReadMessage($lastMessage); $this->attendeeMapper->insert($attendee); + + $attendeeEvent = new AttendeesAddedEvent($room, [$attendee]); + $this->dispatcher->dispatchTyped($attendeeEvent); } $session = $this->sessionService->createSessionForAttendee($attendee); @@ -306,6 +311,7 @@ class ParticipantService { $lastMessage = (int) $room->getLastMessage()->getId(); } + $attendees = []; foreach ($participants as $participant) { $readPrivacy = Participant::PRIVACY_PUBLIC; if ($participant['actorType'] === Attendee::ACTOR_USERS) { @@ -323,8 +329,13 @@ class ParticipantService { $attendee->setLastReadMessage($lastMessage); $attendee->setReadPrivacy($readPrivacy); $this->attendeeMapper->insert($attendee); + + $attendees[] = $attendee; } + $attendeeEvent = new AttendeesAddedEvent($room, $attendees); + $this->dispatcher->dispatchTyped($attendeeEvent); + $this->dispatcher->dispatch(Room::EVENT_AFTER_USERS_ADD, $event); } @@ -377,6 +388,9 @@ class ParticipantService { $attendee->setParticipantType(Participant::USER); $attendee->setReadPrivacy(Participant::PRIVACY_PRIVATE); $this->attendeeMapper->insert($attendee); + + $attendeeEvent = new AttendeesAddedEvent($room, [$attendee]); + $this->dispatcher->dispatchTyped($attendeeEvent); } $this->addUsers($room, $newParticipants); @@ -448,6 +462,9 @@ class ParticipantService { // $attendee->setParticipantType(Participant::USER); // $attendee->setReadPrivacy(Participant::PRIVACY_PRIVATE); // $this->attendeeMapper->insert($attendee); +// +// $attendeeEvent = new AttendeesAddedEvent($room, [$attendee]); +// $this->dispatcher->dispatchTyped($attendeeEvent); // } $this->addUsers($room, $newParticipants); @@ -479,6 +496,9 @@ class ParticipantService { $this->attendeeMapper->insert($attendee); // FIXME handle duplicate invites gracefully + $attendeeEvent = new AttendeesAddedEvent($room, [$attendee]); + $this->dispatcher->dispatchTyped($attendeeEvent); + return new Participant($room, $attendee, null); } @@ -538,12 +558,15 @@ class ParticipantService { if ($participant->getAttendee()->getParticipantType() === Participant::USER_SELF_JOINED) { $this->attendeeMapper->delete($participant->getAttendee()); + + $attendeeEvent = new AttendeesRemovedEvent($room, [$participant->getAttendee()]); + $this->dispatcher->dispatchTyped($attendeeEvent); } $this->dispatcher->dispatch(Room::EVENT_AFTER_ROOM_DISCONNECT, $event); } - public function removeAttendee(Room $room, Participant $participant, string $reason): void { + public function removeAttendee(Room $room, Participant $participant, string $reason, bool $attendeeEventIsTriggeredAlready = false): void { $isUser = $participant->getAttendee()->getActorType() === Attendee::ACTOR_USERS; $sessions = $this->sessionService->getAllSessionsForAttendee($participant->getAttendee()); @@ -560,6 +583,11 @@ class ParticipantService { $this->sessionMapper->deleteByAttendeeId($participant->getAttendee()->getId()); $this->attendeeMapper->delete($participant->getAttendee()); + if (!$attendeeEventIsTriggeredAlready) { + $attendeeEvent = new AttendeesRemovedEvent($room, [$participant->getAttendee()]); + $this->dispatcher->dispatchTyped($attendeeEvent); + } + if ($isUser) { $this->dispatcher->dispatch(Room::EVENT_AFTER_USER_REMOVE, $event); } else { @@ -584,6 +612,7 @@ class ParticipantService { $groupsInRoom[] = $attendee->getActorId(); } + $attendees = []; foreach ($removedGroup->getUsers() as $user) { try { $participant = $room->getParticipant($user->getUID()); @@ -597,11 +626,15 @@ class ParticipantService { continue; } + $attendees[] = $participant->getAttendee(); if ($participant->getAttendee()->getParticipantType() === Participant::USER) { // Only remove normal users, not moderators/admins - $this->removeAttendee($room, $participant, $reason); + $this->removeAttendee($room, $participant, $reason, true); } } + + $attendeeEvent = new AttendeesRemovedEvent($room, $attendees); + $this->dispatcher->dispatchTyped($attendeeEvent); } public function removeUser(Room $room, IUser $user, string $reason): void { @@ -623,6 +656,9 @@ class ParticipantService { $this->attendeeMapper->delete($attendee); + $attendeeEvent = new AttendeesRemovedEvent($room, [$attendee]); + $this->dispatcher->dispatchTyped($attendeeEvent); + $this->dispatcher->dispatch(Room::EVENT_AFTER_USER_REMOVE, $event); } @@ -657,14 +693,20 @@ class ParticipantService { ->andWhere($query->expr()->isNull('s.id')); $attendeeIds = []; + $attendees = []; $result = $query->execute(); while ($row = $result->fetch()) { + $attendeeIds[] = (int) $row['a_id']; + $attendees[] = $this->attendeeMapper->createAttendeeFromRow($row); } $result->closeCursor(); $this->attendeeMapper->deleteByIds($attendeeIds); + $attendeeEvent = new AttendeesRemovedEvent($room, $attendees); + $this->dispatcher->dispatchTyped($attendeeEvent); + $this->dispatcher->dispatch(Room::EVENT_AFTER_GUESTS_CLEAN, $event); } |