feat: Initial implementation of reactions notifications in federated convos

Signed-off-by: skalidindi53 <s.teja2004@gmail.com>
This commit is contained in:
skalidindi53
2024-08-29 18:45:42 -05:00
parent ab396ab287
commit 5a8333596f
4 changed files with 157 additions and 0 deletions

View File

@ -560,4 +560,29 @@ class BackendNotifier {
return $server;
}
public function sendReactionNotification(
string $remoteServer,
int $localAttendeeId,
string $accessToken,
string $localToken,
array $reactionData
): ?bool {
$remote = $this->prepareRemoteUrl($remoteServer);
$notification = $this->cloudFederationFactory->getCloudFederationNotification();
$notification->setMessage(
FederationManager::NOTIFICATION_REACTION_ADDED,
FederationManager::TALK_ROOM_RESOURCE,
(string)$localAttendeeId,
[
'remoteServerUrl' => $this->getServerRemoteUrl(),
'sharedSecret' => $accessToken,
'remoteToken' => $localToken,
'reactionData' => $reactionData,
]
);
return $this->sendUpdateToRemote($remote, $notification);
}
}

View File

@ -46,6 +46,7 @@ class FederationManager {
public const NOTIFICATION_PARTICIPANT_MODIFIED = 'PARTICIPANT_MODIFIED';
public const NOTIFICATION_ROOM_MODIFIED = 'ROOM_MODIFIED';
public const NOTIFICATION_MESSAGE_POSTED = 'MESSAGE_POSTED';
public const NOTIFICATION_REACTION_ADDED = 'talk-reaction-added';
public const TOKEN_LENGTH = 64;
public function __construct(

View File

@ -37,6 +37,8 @@ class MessageSentListener implements IEventListener {
protected MessageParser $messageParser,
protected IFactory $l10nFactory,
protected ChatManager $chatManager,
protected IUserManager $userManager,
protected IAppConfig $appConfig,
) {
}
@ -57,6 +59,14 @@ class MessageSentListener implements IEventListener {
$chatMessage = $this->messageParser->createMessage($event->getRoom(), null, $event->getComment(), $l);
$this->messageParser->parseMessage($chatMessage);
$messageType = $chatMessage->getMessageType();
// Handle reaction events
if ($messageType === ChatManager::VERB_REACTION) {
$this->createReactionNotification($event->getRoom(), $event->getComment());
return;
}
$systemMessage = $chatMessage->getMessageType() === ChatManager::VERB_SYSTEM ? $chatMessage->getMessageRaw() : '';
if ($systemMessage !== 'message_edited'
&& $systemMessage !== 'message_deleted'
@ -124,4 +134,84 @@ class MessageSentListener implements IEventListener {
}
}
}
private function createReactionNotification(Room $chat, IComment $reaction): void {
$originalCommentId = $reaction->getObjectId();
$originalComment = $this->chatManager->getCommentById($originalCommentId);
if ($originalComment === null) {
return;
}
// Check if the original comment's author should be notified
if ($originalComment->getActorType() === Attendee::ACTOR_USERS || $originalComment->getActorType() === Attendee::ACTOR_FEDERATED_USERS) {
try {
$participant = $this->participantService->getParticipant($chat, $originalComment->getActorId(), false);
} catch (ParticipantNotFoundException $e) {
return;
}
$notificationLevel = $participant->getAttendee()->getNotificationLevel();
if ($notificationLevel === Participant::NOTIFY_DEFAULT) {
if ($chat->getType() === Room::TYPE_ONE_TO_ONE) {
$notificationLevel = Participant::NOTIFY_ALWAYS;
} else {
$notificationLevel = $this->getDefaultGroupNotification();
}
}
if ($notificationLevel === Participant::NOTIFY_ALWAYS) {
$this->sendReactionNotification(
$participant,
$chat,
$reaction,
$originalComment
);
}
}
}
private function sendReactionNotification(
Participant $participant,
Room $room,
IComment $reaction,
IComment $originalComment
): void {
$attendee = $participant->getAttendee();
$cloudId = $this->cloudIdManager->resolveCloudId($attendee->getActorId());
$notificationData = [
'remoteMessageId' => (int)$originalComment->getId(),
'reaction' => $reaction->getMessage(),
'reactorType' => $reaction->getActorType(),
'reactorId' => $reaction->getActorId(),
'reactorDisplayName' => $this->getDisplayName($reaction->getActorType(), $reaction->getActorId()),
'creationDatetime' => $reaction->getCreationDateTime()->format(\DateTime::ATOM),
];
// Send the notification using BackendNotifier
$success = $this->backendNotifier->sendReactionNotification(
$cloudId->getRemote(),
$attendee->getId(),
$attendee->getAccessToken(),
$room->getToken(),
$notificationData
);
if ($success === null) {
$this->participantService->removeAttendee($room, $participant, AAttendeeRemovedEvent::REASON_LEFT);
}
}
private function getDisplayName(string $actorType, string $actorId): string {
if ($actorType === Attendee::ACTOR_USERS) {
$user = $this->userManager->get($actorId);
return $user ? $user->getDisplayName() : $actorId;
} elseif ($actorType === Attendee::ACTOR_FEDERATED_USERS) {
$cloudId = $this->cloudIdManager->resolveCloudId($actorId);
return $cloudId->getDisplayName() ?? $actorId;
}
return $actorId;
}
}

View File

@ -509,3 +509,44 @@ Feature: federation/chat
| actorType | actorId | actorDisplayName | reaction |
| users | participant1 | participant1-displayname | 🚀 |
| federated_users | participant2@{$REMOTE_URL} | participant2-displayname | 🚀 |
# Scenario: Verifying Notifications for Local Participants
# Given the following "spreed" app config is set
# | federation_enabled | yes |
# And user "participant1" creates room "room" (v4)
# | roomType | 2 |
# | roomName | room |
# And user "participant1" adds federated_user "participant3" to room "room" with 200 (v4)
# And user "participant1" adds user "participant2" to room "room" with 200 (v4)
# And user "participant3" has the following invitations (v1)
# | remoteServerUrl | remoteToken | state | inviterCloudId | inviterDisplayName |
# | LOCAL | room | 0 | participant1@http://localhost:8080 | participant1-displayname |
# And user "participant3" accepts invite to room "room" of server "LOCAL" with 200 (v1)
# | id | name | type | remoteServer | remoteToken |
# | LOCAL::room | room | 2 | LOCAL | room |
# # Enable Notifications for Local User
# And user "participant2" sets notifications to all for room "room" (v4)
# #fed user
# #And user "participant3" sets notifications to all for room "room" (v4)
# And user "participant3" sets notifications to all for room "LOCAL::room" (v4)
# # Sending a Message
# When user "participant1" sends message "Message 1" to room "room" with 201
# And user "participant1" react with "🚀" on message "Message 1" to room "room" with 201
# | actorType | actorId | actorDisplayName | reaction |
# | users | participant1 | participant1-displayname | 🚀 |
# # Verification for Message Notification
# Then user "participant2" has the following notifications
# | app | object_type | object_id | subject | message |
# | spreed | chat | room/Message 1 | participant1-displayname sent a message in conversation room | Message 1 |
# | spreed | room | room | participant1-displayname invited you to a group conversation: room | |
# Then user "participant3" has the following notifications
# | app | object_type | object_id | subject | message |
# | spreed | chat | LOCAL::room/Message 1 | participant1-displayname sent a message in conversation room | Message 1 |
# #| spreed | room | LOCAL::room | participant1-displayname invited you to a group conversation: room | |