From 42196036b53d5dacf44912d638a1ffb7fe099daf Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 28 Feb 2024 17:01:06 +0100 Subject: [PATCH] feat(federation): Federate unread information to proxies Signed-off-by: Joas Schilling --- lib/Federation/BackendNotifier.php | 6 ++++++ .../CloudFederationProviderTalk.php | 20 +++++++++++++++++-- .../TalkV1/Notifier/MessageSentListener.php | 19 ++++++++++++------ lib/Service/ParticipantService.php | 8 ++++++++ lib/Service/RoomFormatter.php | 8 +++++++- 5 files changed, 52 insertions(+), 9 deletions(-) diff --git a/lib/Federation/BackendNotifier.php b/lib/Federation/BackendNotifier.php index 487722c90cd9..975829ff03a1 100644 --- a/lib/Federation/BackendNotifier.php +++ b/lib/Federation/BackendNotifier.php @@ -278,6 +278,8 @@ public function sendRoomModifiedUpdate( /** * Send information to remote participants that a message was posted * Sent from Host server to Remote participant server + * + * @param array{unreadMessages: int, unreadMention: bool, unreadMentionDirect: bool} $unreadInfo */ public function sendMessageUpdate( string $remoteServer, @@ -286,6 +288,7 @@ public function sendMessageUpdate( string $accessToken, string $localToken, array $messageData, + array $unreadInfo, ): void { $remote = $this->prepareRemoteUrl($remoteServer); @@ -299,6 +302,7 @@ public function sendMessageUpdate( 'sharedSecret' => $accessToken, 'remoteToken' => $localToken, 'messageData' => $messageData, + 'unreadInfo' => $unreadInfo, ], ); @@ -324,6 +328,8 @@ public function sendUpdateDataToRemote(string $remote, array $data, int $try): v } protected function sendUpdateToRemote(string $remote, ICloudFederationNotification $notification, int $try = 0): void { + \OC::$server->getLogger()->error('sendUpdateToRemote'); + \OC::$server->getLogger()->error(json_encode($notification->getMessage())); $response = $this->federationProviderManager->sendNotification($remote, $notification); if (!is_array($response)) { $this->jobList->add(RetryJob::class, diff --git a/lib/Federation/CloudFederationProviderTalk.php b/lib/Federation/CloudFederationProviderTalk.php index 525784e2b355..0ff47da250b4 100644 --- a/lib/Federation/CloudFederationProviderTalk.php +++ b/lib/Federation/CloudFederationProviderTalk.php @@ -32,6 +32,7 @@ use OCA\Talk\Events\AAttendeeRemovedEvent; use OCA\Talk\Events\ARoomModifiedEvent; use OCA\Talk\Events\AttendeesAddedEvent; +use OCA\Talk\Exceptions\ParticipantNotFoundException; use OCA\Talk\Exceptions\RoomNotFoundException; use OCA\Talk\Manager; use OCA\Talk\Model\Attendee; @@ -309,7 +310,7 @@ private function roomModified(int $remoteAttendeeId, array $notification): array /** * @param int $remoteAttendeeId - * @param array{remoteServerUrl: string, sharedSecret: string, remoteToken: string, messageData: array{remoteMessageId: int, actorType: string, actorId: string, actorDisplayName: string, messageType: string, systemMessage: string, expirationDatetime: string, message: string, messageParameter: string}} $notification + * @param array{remoteServerUrl: string, sharedSecret: string, remoteToken: string, messageData: array{remoteMessageId: int, actorType: string, actorId: string, actorDisplayName: string, messageType: string, systemMessage: string, expirationDatetime: string, message: string, messageParameter: string}, unreadInfo: array{unreadMessages: int, unreadMention: bool, unreadMentionDirect: bool}} $notification * @return array * @throws ActionNotSupportedException * @throws AuthenticationFailedException @@ -338,7 +339,9 @@ private function messagePosted(int $remoteAttendeeId, array $notification): arra $message->setActorDisplayName($notification['messageData']['actorDisplayName']); $message->setMessageType($notification['messageData']['messageType']); $message->setSystemMessage($notification['messageData']['systemMessage']); - $message->setExpirationDateTime(new \DateTimeImmutable($notification['messageData']['expirationDatetime'])); + if ($notification['messageData']['expirationDatetime']) { + $message->setExpirationDateTime(new \DateTimeImmutable($notification['messageData']['expirationDatetime'])); + } $message->setMessage($notification['messageData']['message']); $message->setMessageParameters($notification['messageData']['messageParameter']); $this->proxyCacheMessagesMapper->insert($message); @@ -351,6 +354,19 @@ private function messagePosted(int $remoteAttendeeId, array $notification): arra } } + try { + $participant = $this->participantService->getParticipant($room, $invite->getUserId(), false); + } catch (ParticipantNotFoundException) { + throw new ShareNotFound(); + } + + $this->participantService->updateUnreadInfoForProxyParticipant( + $participant, + $notification['unreadInfo']['unreadMessages'], + $notification['unreadInfo']['unreadMention'], + $notification['unreadInfo']['unreadMentionDirect'], + ); + return []; } diff --git a/lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php b/lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php index 3c7dc3a854fd..e6920cc06540 100644 --- a/lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php +++ b/lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php @@ -48,6 +48,7 @@ public function __construct( protected ICloudIdManager $cloudIdManager, protected MessageParser $messageParser, protected IFactory $l10nFactory, + protected ChatManager $chatManager, ) { } @@ -90,15 +91,20 @@ public function handle(Event $event): void { 'messageParameter' => json_encode($chatMessage->getMessageParameters()), ]; - $notifiedServers = []; $participants = $this->participantService->getParticipantsByActorType($event->getRoom(), Attendee::ACTOR_FEDERATED_USERS); foreach ($participants as $participant) { - $cloudId = $this->cloudIdManager->resolveCloudId($participant->getAttendee()->getActorId()); + $attendee = $participant->getAttendee(); + $cloudId = $this->cloudIdManager->resolveCloudId($attendee->getActorId()); - if (isset($notifiedServers[$cloudId->getRemote()])) { - continue; - } - $notifiedServers[$cloudId->getRemote()] = true; + $lastReadMessage = $attendee->getLastReadMessage(); + $lastMention = $attendee->getLastMentionMessage(); + $lastMentionDirect = $attendee->getLastMentionDirect(); + + $unreadInfo = [ + 'unreadMessages' => $this->chatManager->getUnreadCount($event->getRoom(), $lastReadMessage), + 'unreadMention' => $lastMention !== 0 && $lastReadMessage < $lastMention, + 'unreadMentionDirect' => $lastMentionDirect !== 0 && $lastReadMessage < $lastMentionDirect + ]; $this->backendNotifier->sendMessageUpdate( $cloudId->getRemote(), @@ -106,6 +112,7 @@ public function handle(Event $event): void { $participant->getAttendee()->getAccessToken(), $event->getRoom()->getToken(), $messageData, + $unreadInfo, ); } } diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index c16510c59854..6d0711ed6c31 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -249,6 +249,14 @@ public function updateLastReadMessage(Participant $participant, int $lastReadMes $this->attendeeMapper->update($attendee); } + public function updateUnreadInfoForProxyParticipant(Participant $participant, int $unreadMessageCount, bool $hasMention, bool $hadDirectMention): void { + $attendee = $participant->getAttendee(); + $attendee->setLastReadMessage($unreadMessageCount); + $attendee->setLastMentionMessage($hasMention ? 1 : 0); + $attendee->setLastMentionDirect($hadDirectMention ? 1 : 0); + $this->attendeeMapper->update($attendee); + } + public function updateFavoriteStatus(Participant $participant, bool $isFavorite): void { $attendee = $participant->getAttendee(); $attendee->setFavorite($isFavorite); diff --git a/lib/Service/RoomFormatter.php b/lib/Service/RoomFormatter.php index bffb0d976e16..bc4cc6204a7f 100644 --- a/lib/Service/RoomFormatter.php +++ b/lib/Service/RoomFormatter.php @@ -287,7 +287,13 @@ public function formatRoomV4( if ($attendee->getActorType() === Attendee::ACTOR_USERS) { $currentUser = $this->userManager->get($attendee->getActorId()); - if ($currentUser instanceof IUser) { + if ($room->getRemoteServer() !== '') { + // For proxy conversations the information is the real counter, + // not the message ID requiring math afterward. + $roomData['unreadMessages'] = $attendee->getLastReadMessage(); + $roomData['unreadMention'] = (bool) $attendee->getLastMentionMessage(); + $roomData['unreadMentionDirect'] = (bool) $attendee->getLastMentionDirect(); + } elseif ($currentUser instanceof IUser) { $lastReadMessage = $attendee->getLastReadMessage(); if ($lastReadMessage === -1) { /*