Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(chat): Store and expose whether a message or call was silent #11449

Merged
merged 1 commit into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,4 @@
## 19
* `delete-messages-unlimited` - Whether messages can be deleted at any time (used to be restricted to 6 hours after posting)
* `edit-messages` - Whether messages can be edited (restricted to 24 hours after posting)
* `silent-send-state` - Whether messages contain a flag that they were sent silently
11 changes: 6 additions & 5 deletions docs/chat.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`: since Nextcloud 13
Array of messages, each message has at least:

| field | type | Description |
|----------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|----------------------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id` | int | ID of the comment |
| `token` | string | Conversation token |
| `actorType` | string | See [Constants - Actor types of chat messages](constants.md#actor-types-of-chat-messages) |
Expand All @@ -62,10 +62,11 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`: since Nextcloud 13
| `reactions` | int[] | **Optional:** An array map with relation between reaction emoji and total count of reactions with this emoji |
| `reactionsSelf` | string[] | **Optional:** When the user reacted this is the list of emojis the user reacted with |
| `markdown` | bool | **Optional:** Whether the message should be rendered as markdown or shown as plain text |
| `lastEditActorType` | string | Actor type of the last editing author - See [Constants - Actor types of chat messages](constants.md#actor-types-of-chat-messages) (only available with `edit-messages` capability and when the message was actually edited) |
| `lastEditActorId` | string | Actor id of the last editing author (only available with `edit-messages` capability and when the message was actually edited) |
| `lastEditActorDisplayName` | string | Display name of the last editing author (only available with `edit-messages` capability and when the message was actually edited) (can be empty for type `deleted_users` and `guests`) |
| `lastEditTimestamp` | int | Unix time stamp when the message was last edited (only available with `edit-messages` capability and when the message was actually edited) |
| `lastEditActorType` | string | **Optional:** Actor type of the last editing author - See [Constants - Actor types of chat messages](constants.md#actor-types-of-chat-messages) (only available with `edit-messages` capability and when the message was actually edited) |
| `lastEditActorId` | string | **Optional:** Actor id of the last editing author (only available with `edit-messages` capability and when the message was actually edited) |
| `lastEditActorDisplayName` | string | **Optional:** Display name of the last editing author (only available with `edit-messages` capability and when the message was actually edited) (can be empty for type `deleted_users` and `guests`) |
| `lastEditTimestamp` | int | **Optional:** Unix time stamp when the message was last edited (only available with `edit-messages` capability and when the message was actually edited) |
| `silent` | bool | **Optional:** Whether the message was sent silently (only available with `silent-send-state` capability) |

#### Parent data

Expand Down
1 change: 1 addition & 0 deletions lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ public function getCapabilities(): array {
'sip-support-dialout',
'delete-messages-unlimited',
'edit-messages',
'silent-send-state',
],
'config' => [
'attachments' => [
Expand Down
22 changes: 20 additions & 2 deletions lib/Chat/ChatManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ public function addSystemMessage(
$comment->setVerb(self::VERB_SYSTEM);
}

if ($silent) {
$comment->setMetaData([
'silent' => true,
]);
}

$this->setMessageExpiration($chat, $comment);

$shouldFlush = $this->notificationManager->defer();
Expand Down Expand Up @@ -291,6 +297,12 @@ public function sendMessage(Room $chat, ?Participant $participant, string $actor
}
}

if ($silent) {
$comment->setMetaData([
'silent' => true,
]);
}

$event = new BeforeChatMessageSentEvent($chat, $comment, $participant, $silent);
$this->dispatcher->dispatchTyped($event);

Expand Down Expand Up @@ -509,27 +521,32 @@ public function editMessage(Room $chat, IComment $comment, Participant $particip
$metaData['last_edited_time'] = $editTime->getTimestamp();
$comment->setMetaData($metaData);

$wasSilent = $metaData['silent'] ?? false;

if (!$wasSilent) {
$mentionsBefore = $comment->getMentions();
$usersDirectlyMentionedBefore = $this->notifier->getMentionedUserIds($comment);
$usersToNotifyBefore = $this->notifier->getUsersToNotify($chat, $comment, []);
}
$comment->setMessage($message, self::MAX_CHAT_LENGTH);
if (!$wasSilent) {
$mentionsAfter = $comment->getMentions();
}

$this->commentsManager->save($comment);
$this->referenceManager->invalidateCache($chat->getToken());

if (!$wasSilent) {
$removedMentions = empty($mentionsAfter) ? $mentionsBefore : array_udiff($mentionsBefore, $mentionsAfter, [$this, 'compareMention']);
$addedMentions = empty($mentionsBefore) ? $mentionsAfter : array_udiff($mentionsAfter, $mentionsBefore, [$this, 'compareMention']);

// FIXME Not needed when it was silent, once it's stored in metadata
if (!empty($removedMentions)) {
$usersToNotifyAfter = $this->notifier->getUsersToNotify($chat, $comment, []);
$removedUsersMentioned = array_udiff($usersToNotifyBefore, $usersToNotifyAfter, [$this, 'compareMention']);
$userIds = array_column($removedUsersMentioned, 'id');
$this->notifier->removeMentionNotificationAfterEdit($chat, $comment, $userIds);
}

// FIXME silent support, once it's stored in metadata
if (!empty($addedMentions)) {
$usersDirectlyMentionedAfter = $this->notifier->getMentionedUserIds($comment);
$addedUsersDirectMentioned = array_diff($usersDirectlyMentionedAfter, $usersDirectlyMentionedBefore);
Expand All @@ -540,6 +557,7 @@ public function editMessage(Room $chat, IComment $comment, Participant $particip
$this->participantService->markUsersAsMentioned($chat, $userIds, (int) $comment->getId(), $addedUsersDirectMentioned);
}
}
}

return $this->addSystemMessage(
$chat,
Expand Down
13 changes: 12 additions & 1 deletion lib/Chat/Parser/SystemMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,20 @@ protected function parseMessage(Message $chatMessage): void {
$parsedMessage = $this->l->t('An administrator removed the description');
}
} elseif ($message === 'call_started') {
$parsedMessage = $this->l->t('{actor} started a call');
$metaData = $comment->getMetaData() ?? [];
$silentCall = $metaData['silent'] ?? false;
if ($silentCall) {
if ($currentUserIsActor) {
$parsedMessage = $this->l->t('You started a silent call');
} else {
$parsedMessage = $this->l->t('{actor} started a silent call');
}
} else {
if ($currentUserIsActor) {
$parsedMessage = $this->l->t('You started a call');
} else {
$parsedMessage = $this->l->t('{actor} started a call');
}
}
} elseif ($message === 'call_joined') {
$parsedMessage = $this->l->t('{actor} joined the call');
Expand Down
3 changes: 2 additions & 1 deletion lib/Chat/SystemMessage/Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ protected function sendSystemMessageAboutBeginOfCall(BeforeParticipantModifiedEv
if ($this->participantService->hasActiveSessionsInCall($event->getRoom())) {
$this->sendSystemMessage($event->getRoom(), 'call_joined', [], $event->getParticipant());
} else {
$this->sendSystemMessage($event->getRoom(), 'call_started', [], $event->getParticipant());
$silent = $event->getDetail(AParticipantModifiedEvent::DETAIL_IN_CALL_SILENT) ?? false;
$this->sendSystemMessage($event->getRoom(), 'call_started', [], $event->getParticipant(), silent: $silent);
}
}

Expand Down
5 changes: 5 additions & 0 deletions lib/Model/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ public function toArray(string $format): array {
$data['deleted'] = true;
}

$metaData = $this->comment->getMetaData() ?? [];
if ($metaData['silent']) {
$data['silent'] = true;
}

return $data;
}
}
1 change: 1 addition & 0 deletions lib/ResponseDefinitions.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
* lastEditActorId?: string,
* lastEditActorType?: string,
* lastEditTimestamp?: int,
* silent?: bool,
* }
*
* @psalm-type TalkChatMessageWithParent = TalkChatMessage&array{parent?: TalkChatMessage}
Expand Down
3 changes: 3 additions & 0 deletions openapi-backend-sipbridge.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@
"lastEditTimestamp": {
"type": "integer",
"format": "int64"
},
"silent": {
"type": "boolean"
}
}
},
Expand Down
3 changes: 3 additions & 0 deletions openapi-federation.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@
"lastEditTimestamp": {
"type": "integer",
"format": "int64"
},
"silent": {
"type": "boolean"
}
}
},
Expand Down
3 changes: 3 additions & 0 deletions openapi-full.json
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@
"lastEditTimestamp": {
"type": "integer",
"format": "int64"
},
"silent": {
"type": "boolean"
}
}
},
Expand Down
3 changes: 3 additions & 0 deletions openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@
"lastEditTimestamp": {
"type": "integer",
"format": "int64"
},
"silent": {
"type": "boolean"
}
}
},
Expand Down
11 changes: 9 additions & 2 deletions tests/integration/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -2648,7 +2648,7 @@ protected function compareDataResponse(TableNode $formData = null) {
}
}

Assert::assertEquals($expected, array_map(function ($message) use ($includeParents, $includeReferenceId, $includeReactions, $includeReactionsSelf, $includeLastEdit) {
Assert::assertEquals($expected, array_map(function ($message, $expected) use ($includeParents, $includeReferenceId, $includeReactions, $includeReactionsSelf, $includeLastEdit) {
$data = [
'room' => self::$tokenToIdentifier[$message['token']],
'actorType' => $message['actorType'],
Expand All @@ -2665,6 +2665,9 @@ protected function compareDataResponse(TableNode $formData = null) {
if ($includeReferenceId) {
$data['referenceId'] = $message['referenceId'];
}
if (isset($expected['silent'])) {
$data['silent'] = isset($message['silent']) ? json_encode($message['silent']) : '!ISSET';
}
if ($includeReactions) {
$data['reactions'] = json_encode($message['reactions'], JSON_UNESCAPED_UNICODE);
}
Expand All @@ -2684,7 +2687,7 @@ protected function compareDataResponse(TableNode $formData = null) {
}
}
return $data;
}, $messages));
}, $messages, $expected));
}

/**
Expand Down Expand Up @@ -2773,6 +2776,10 @@ public function userSeesTheFollowingSystemMessagesInRoom($user, $identifier, $st
$data['messageParameters'] = json_encode($message['messageParameters']);
}

if (isset($expected['silent'])) {
$data['silent'] = isset($message['silent']) ? json_encode($message['silent']) : '!ISSET';
}

return $data;
}, $messages, $expected));
}
Expand Down
10 changes: 10 additions & 0 deletions tests/integration/features/callapi/notifications.feature
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ Feature: callapi/notifications
Given user "participant1" joins room "room" with 200 (v4)
Given user "participant2" joins room "room" with 200 (v4)
Given user "participant1" joins call "room" with 200 (v4)
Then user "participant2" sees the following system messages in room "room" with 200
| room | actorType | actorId | systemMessage | message | silent | messageParameters |
| room | users | participant1 | call_started | {actor} started a call | !ISSET | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"}} |
| room | users | participant1 | user_added | {actor} added you | !ISSET | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"},"user":{"type":"user","id":"participant2","name":"participant2-displayname"}} |
| room | users | participant1 | conversation_created | {actor} created the conversation | !ISSET | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"}} |
Then user "participant2" has the following notifications
| app | object_type | object_id | subject |
| spreed | call | room | A group call has started in room |
Expand All @@ -44,6 +49,11 @@ Feature: callapi/notifications
Given user "participant2" joins room "room" with 200 (v4)
Given user "participant1" joins call "room" with 200 (v4)
| silent | true |
Then user "participant2" sees the following system messages in room "room" with 200
| room | actorType | actorId | systemMessage | message | silent | messageParameters |
| room | users | participant1 | call_started | {actor} started a silent call | true | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"}} |
| room | users | participant1 | user_added | {actor} added you | !ISSET | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"},"user":{"type":"user","id":"participant2","name":"participant2-displayname"}} |
| room | users | participant1 | conversation_created | {actor} created the conversation | !ISSET | {"actor":{"type":"user","id":"participant1","name":"participant1-displayname"}} |
Then user "participant2" has the following notifications
| app | object_type | object_id | subject |
Given user "participant1" leaves call "room" with 200 (v4)
Expand Down
6 changes: 6 additions & 0 deletions tests/integration/features/chat-1/notifications.feature
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ Feature: chat/notifications
Then user "participant2" has the following notifications
| app | object_type | object_id | subject |
| spreed | chat | one-to-one room/Message 1 | participant1-displayname sent you a private message |
Then user "participant2" sees the following messages in room "one-to-one room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | silent |
| one-to-one room | users | participant1 | participant1-displayname | Message 1 | [] | !ISSET |

Scenario: Silent sent message when recipient is offline in the one-to-one
When user "participant1" creates room "one-to-one room" (v4)
Expand All @@ -54,6 +57,9 @@ Feature: chat/notifications
When user "participant1" silent sends message "Message 1" to room "one-to-one room" with 201
Then user "participant2" has the following notifications
| app | object_type | object_id | subject |
Then user "participant2" sees the following messages in room "one-to-one room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | silent |
| one-to-one room | users | participant1 | participant1-displayname | Message 1 | [] | true |

Scenario: Normal message when recipient disabled notifications in the one-to-one
When user "participant1" creates room "one-to-one room" (v4)
Expand Down
1 change: 1 addition & 0 deletions tests/php/CapabilitiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ public function setUp(): void {
'sip-support-dialout',
'delete-messages-unlimited',
'edit-messages',
'silent-send-state',
'message-expiration',
'reactions',
];
Expand Down
Loading