diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php index 99cfdcd9335..d44f836762c 100644 --- a/lib/Controller/RoomController.php +++ b/lib/Controller/RoomController.php @@ -1855,6 +1855,7 @@ public function rejectedDialOutRequest(string $callId, array $options = []): Dat * 400: The provided new state was invalid * 404: The participant did not have a session */ + #[FederationSupported] #[PublicPage] #[RequireParticipant] public function setSessionState(int $state): DataResponse { diff --git a/lib/Federation/CloudFederationProviderTalk.php b/lib/Federation/CloudFederationProviderTalk.php index ab91e17d57c..af814ea3e74 100644 --- a/lib/Federation/CloudFederationProviderTalk.php +++ b/lib/Federation/CloudFederationProviderTalk.php @@ -441,7 +441,7 @@ private function messagePosted(int $remoteAttendeeId, array $notification): arra } try { - $participant = $this->participantService->getParticipant($room, $invite->getUserId(), false); + $participant = $this->participantService->getParticipantWithActiveSession($room, $invite->getUserId()); } catch (ParticipantNotFoundException) { // Not accepted the invite yet return []; diff --git a/lib/Notification/FederationChatNotifier.php b/lib/Notification/FederationChatNotifier.php index e4e9966b259..74eb21865e3 100644 --- a/lib/Notification/FederationChatNotifier.php +++ b/lib/Notification/FederationChatNotifier.php @@ -30,6 +30,7 @@ use OCA\Talk\Model\Attendee; use OCA\Talk\Model\Message; use OCA\Talk\Model\ProxyCacheMessage; +use OCA\Talk\Model\Session; use OCA\Talk\Participant; use OCA\Talk\Room; use OCP\AppFramework\Services\IAppConfig; @@ -61,6 +62,11 @@ public function handleChatMessage(Room $room, Participant $participant, ProxyCac return; } + if ($participant->getSession() instanceof Session) { + // User has an active session + return; + } + // Also notify default participants in one-to-one chats or when the admin default is "always" $defaultLevel = $this->appConfig->getAppValueInt('default_group_notification', Participant::NOTIFY_MENTION); if ($participant->getAttendee()->getNotificationLevel() === Participant::NOTIFY_MENTION diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index f234f50977c..bbe5069aecf 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -1876,6 +1876,37 @@ public function getParticipant(Room $room, ?string $userId, $sessionId = null): return $participant; } + /** + * Get a participant with an active session if there is one, otherwise without session + * + * @param Room $room + * @param string $userId + * @return Participant + * @throws ParticipantNotFoundException When the user is not a participant + */ + public function getParticipantWithActiveSession(Room $room, string $userId): Participant { + if ($userId === '') { + throw new ParticipantNotFoundException('Not a user'); + } + + $query = $this->connection->getQueryBuilder(); + $helper = new SelectHelper(); + $helper->selectAttendeesTable($query); + $helper->selectSessionsTable($query); + $query->from('talk_attendees', 'a') + ->leftJoin('a', 'talk_sessions', 's', $query->expr()->andX( + $query->expr()->eq('a.id', 's.attendee_id'), + $query->expr()->eq('s.state', $query->createNamedParameter(Session::STATE_ACTIVE, IQueryBuilder::PARAM_INT)) + )) + ->where($query->expr()->eq('a.actor_type', $query->createNamedParameter(Attendee::ACTOR_USERS))) + ->andWhere($query->expr()->eq('a.actor_id', $query->createNamedParameter($userId))) + ->andWhere($query->expr()->eq('a.room_id', $query->createNamedParameter($room->getId()))) + ->setMaxResults(1); + + + return $this->getParticipantFromQuery($query, $room); + } + /** * @param Room $room * @param string|null $sessionId diff --git a/tests/integration/features/federation/chat.feature b/tests/integration/features/federation/chat.feature index 616e91ec749..9d3ebc4cc25 100644 --- a/tests/integration/features/federation/chat.feature +++ b/tests/integration/features/federation/chat.feature @@ -302,6 +302,37 @@ Feature: federation/chat Then user "participant2" has the following notifications | app | object_type | object_id | subject | message | + Scenario: Mentioning a federated user with an active session does not trigger a notification but inactive does + Given the following "spreed" app config is set + | federation_enabled | yes | + Given user "participant1" creates room "room" (v4) + | roomType | 3 | + | roomName | room | + And user "participant1" adds federated_user "participant2" to room "room" with 200 (v4) + And user "participant2" has the following invitations (v1) + | remoteServerUrl | remoteToken | state | inviterCloudId | inviterDisplayName | + | LOCAL | room | 0 | participant1@http://localhost:8080 | participant1-displayname | + And user "participant2" accepts invite to room "room" of server "LOCAL" with 200 (v1) + | id | name | type | remoteServer | remoteToken | + | room | room | 3 | LOCAL | room | + Then user "participant2" is participant of the following rooms (v4) + | id | type | + | room | 3 | + # Join and leave to clear the invite notification + Given user "participant2" joins room "LOCAL::room" with 200 (v4) + Given user "participant2" sets session state to 1 in room "LOCAL::room" with 200 (v4) + And user "guest" joins room "room" with 200 (v4) + When user "guest" sends message 'Sent to @"federated_user/participant2@{$REMOTE_URL}" while active' to room "room" with 201 + Given user "participant2" sets session state to 0 in room "LOCAL::room" with 200 (v4) + When user "guest" sends message 'User @"federated_user/participant2@{$REMOTE_URL}" is inactive' to room "room" with 201 + When user "guest" sends message "Message 3" to room "room" with 201 + Then user "participant2" has the following notifications + | app | object_type | object_id | subject | message | + | spreed | chat | room/User @"federated_user/participant2@{$REMOTE_URL}" is inactive | A guest mentioned you in conversation room | User @participant2-displayname is inactive | + Then user "participant2" reads message "Message 3" in room "LOCAL::room" with 200 (v1) + Then user "participant2" has the following notifications + | app | object_type | object_id | subject | message | + Scenario: Mentioning a federated user as a federated user that is a local user to the mentioned one also triggers a notification for them Given the following "spreed" app config is set | federation_enabled | yes |