Skip to content

Commit

Permalink
feat: Initial implementation of reactions notifications in federated …
Browse files Browse the repository at this point in the history
…convos

Signed-off-by: skalidindi53 <[email protected]>
  • Loading branch information
skalidindi53 committed Sep 30, 2024
1 parent ab396ab commit 5a83335
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 0 deletions.
25 changes: 25 additions & 0 deletions lib/Federation/BackendNotifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -560,4 +560,29 @@ protected function getServerRemoteUrl(): string {

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);
}
}
1 change: 1 addition & 0 deletions lib/Federation/FederationManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
90 changes: 90 additions & 0 deletions lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public function __construct(
protected MessageParser $messageParser,
protected IFactory $l10nFactory,
protected ChatManager $chatManager,
protected IUserManager $userManager,

Check failure on line 40 in lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedClass

lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php:40:3: UndefinedClass: Class, interface or enum named OCA\Talk\Federation\Proxy\TalkV1\Notifier\IUserManager does not exist (see https://psalm.dev/019)
protected IAppConfig $appConfig,

Check failure on line 41 in lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedClass

lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php:41:3: UndefinedClass: Class, interface or enum named OCA\Talk\Federation\Proxy\TalkV1\Notifier\IAppConfig does not exist (see https://psalm.dev/019)
) {
}

Expand All @@ -57,6 +59,14 @@ public function handle(Event $event): void {
$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());

Check failure on line 66 in lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

InvalidArgument

lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php:66:38: InvalidArgument: Argument 1 of OCA\Talk\Federation\Proxy\TalkV1\Notifier\MessageSentListener::createReactionNotification expects OCA\Talk\Federation\Proxy\TalkV1\Notifier\Room, but OCA\Talk\Room provided (see https://psalm.dev/004)
return;
}

$systemMessage = $chatMessage->getMessageType() === ChatManager::VERB_SYSTEM ? $chatMessage->getMessageRaw() : '';
if ($systemMessage !== 'message_edited'
&& $systemMessage !== 'message_deleted'
Expand Down Expand Up @@ -124,4 +134,84 @@ public function handle(Event $event): void {
}
}
}

private function createReactionNotification(Room $chat, IComment $reaction): void {

Check failure on line 138 in lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedClass

lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php:138:46: UndefinedClass: Class, interface or enum named OCA\Talk\Federation\Proxy\TalkV1\Notifier\Room does not exist (see https://psalm.dev/019)
$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,

Check failure on line 175 in lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedClass

lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php:175:3: UndefinedClass: Class, interface or enum named OCA\Talk\Federation\Proxy\TalkV1\Notifier\Participant does not exist (see https://psalm.dev/019)
Room $room,

Check failure on line 176 in lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedClass

lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php:176:3: UndefinedClass: Class, interface or enum named OCA\Talk\Federation\Proxy\TalkV1\Notifier\Room does not exist (see https://psalm.dev/019)
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);

Check failure on line 208 in lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedClass

lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php:208:12: UndefinedClass: Class, interface or enum named OCA\Talk\Federation\Proxy\TalkV1\Notifier\IUserManager does not exist (see https://psalm.dev/019)
return $user ? $user->getDisplayName() : $actorId;
} elseif ($actorType === Attendee::ACTOR_FEDERATED_USERS) {
$cloudId = $this->cloudIdManager->resolveCloudId($actorId);
return $cloudId->getDisplayName() ?? $actorId;

Check failure on line 212 in lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis

UndefinedInterfaceMethod

lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php:212:21: UndefinedInterfaceMethod: Method OCP\Federation\ICloudId::getDisplayName does not exist (see https://psalm.dev/181)
}
return $actorId;
}

}
41 changes: 41 additions & 0 deletions tests/integration/features/federation/chat.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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 | |

0 comments on commit 5a83335

Please sign in to comment.