Add system messages for group attendees

Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
Joas Schilling 2021-06-11 17:08:47 +02:00
Родитель ff4ed33e8e
Коммит b9e5fe2bcc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 7076EA9751AACDDA
8 изменённых файлов: 222 добавлений и 3 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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();

Просмотреть файл

@ -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 {
}

Просмотреть файл

@ -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;
}
}

Просмотреть файл

@ -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 {
}

Просмотреть файл

@ -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);
}