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
47 changes: 24 additions & 23 deletions docs/chat.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,29 +43,30 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`: since Nextcloud 13
- Data:
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) |
| `actorId` | string | Actor id of the message author |
| `actorDisplayName` | string | Display name of the message author (can be empty for type `deleted_users` and `guests`) |
| `timestamp` | int | Timestamp in seconds and UTC time zone |
| `systemMessage` | string | empty for normal chat message or the type of the system message (untranslated) |
| `messageType` | string | Currently known types are `comment`, `comment_deleted`, `system` and `command` |
| `isReplyable` | bool | True if the user can post a reply to this message (only available with `chat-replies` capability) |
| `referenceId` | string | A reference string that was given while posting the message to be able to identify a sent message again (only available with `chat-reference-id` capability) |
| `message` | string | Message string with placeholders (see [Rich Object String](https://github.com/nextcloud/server/issues/1706)) |
| `messageParameters` | array | Message parameters for `message` (see [Rich Object String](https://github.com/nextcloud/server/issues/1706)) |
| `expirationTimestamp` | int | Unix time stamp when the message expires and show be removed from the clients UI without further note or warning (only available with `message-expiration` capability) |
| `parent` | array | **Optional:** See `Parent data` below |
| `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) |
| 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) |
| `actorId` | string | Actor id of the message author |
| `actorDisplayName` | string | Display name of the message author (can be empty for type `deleted_users` and `guests`) |
| `timestamp` | int | Timestamp in seconds and UTC time zone |
| `systemMessage` | string | empty for normal chat message or the type of the system message (untranslated) |
| `messageType` | string | Currently known types are `comment`, `comment_deleted`, `system` and `command` |
| `isReplyable` | bool | True if the user can post a reply to this message (only available with `chat-replies` capability) |
| `referenceId` | string | A reference string that was given while posting the message to be able to identify a sent message again (only available with `chat-reference-id` capability) |
| `message` | string | Message string with placeholders (see [Rich Object String](https://github.com/nextcloud/server/issues/1706)) |
| `messageParameters` | array | Message parameters for `message` (see [Rich Object String](https://github.com/nextcloud/server/issues/1706)) |
| `expirationTimestamp` | int | Unix time stamp when the message expires and show be removed from the clients UI without further note or warning (only available with `message-expiration` capability) |
| `parent` | array | **Optional:** See `Parent data` below |
| `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 | **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
60 changes: 39 additions & 21 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,35 +521,41 @@ public function editMessage(Room $chat, IComment $comment, Participant $particip
$metaData['last_edited_time'] = $editTime->getTimestamp();
$comment->setMetaData($metaData);

$mentionsBefore = $comment->getMentions();
$usersDirectlyMentionedBefore = $this->notifier->getMentionedUserIds($comment);
$usersToNotifyBefore = $this->notifier->getUsersToNotify($chat, $comment, []);
$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);
$mentionsAfter = $comment->getMentions();
if (!$wasSilent) {
$mentionsAfter = $comment->getMentions();
}

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

$removedMentions = empty($mentionsAfter) ? $mentionsBefore : array_udiff($mentionsBefore, $mentionsAfter, [$this, 'compareMention']);
$addedMentions = empty($mentionsBefore) ? $mentionsAfter : array_udiff($mentionsAfter, $mentionsBefore, [$this, 'compareMention']);
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);
}
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);
if (!empty($addedMentions)) {
$usersDirectlyMentionedAfter = $this->notifier->getMentionedUserIds($comment);
$addedUsersDirectMentioned = array_diff($usersDirectlyMentionedAfter, $usersDirectlyMentionedBefore);

$alreadyNotifiedUsers = $this->notifier->notifyMentionedUsers($chat, $comment, $usersToNotifyBefore, silent: false);
if (!empty($alreadyNotifiedUsers)) {
$userIds = array_column($alreadyNotifiedUsers, 'id');
$this->participantService->markUsersAsMentioned($chat, $userIds, (int) $comment->getId(), $addedUsersDirectMentioned);
$alreadyNotifiedUsers = $this->notifier->notifyMentionedUsers($chat, $comment, $usersToNotifyBefore, silent: false);
if (!empty($alreadyNotifiedUsers)) {
$userIds = array_column($alreadyNotifiedUsers, 'id');
$this->participantService->markUsersAsMentioned($chat, $userIds, (int) $comment->getId(), $addedUsersDirectMentioned);
}
}
}

Expand Down
17 changes: 14 additions & 3 deletions 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');
if ($currentUserIsActor) {
$parsedMessage = $this->l->t('You 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
Loading
Loading