Skip to content

Commit

Permalink
feat(chat): Store and expose whether a message or call was silent
Browse files Browse the repository at this point in the history
Signed-off-by: Joas Schilling <coding@schilljs.com>
  • Loading branch information
nickvergessen committed Jan 30, 2024
1 parent 0f03723 commit 0d1fc13
Show file tree
Hide file tree
Showing 16 changed files with 126 additions and 51 deletions.
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

0 comments on commit 0d1fc13

Please sign in to comment.