diff --git a/docs/capabilities.md b/docs/capabilities.md index f299a979790..458650c0be9 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -121,3 +121,6 @@ * `config => call => supported-reactions` - A list of emojis supported as call reactions. If the list is absent or empty, clients should not show the emoji reaction option in calls. * `config => chat => typing-privacy` - User defined numeric value to enable 1 or disable 0 the typing indicator to other users * `typing-privacy` - Support toggle typing privacy + +## 18 +* `threads` - Chat messages have a thread ID exposed which allows clients to only list chat messages of a dedicated messages stream diff --git a/docs/chat.md b/docs/chat.md index 2db6cd7b879..55f057952ce 100644 --- a/docs/chat.md +++ b/docs/chat.md @@ -43,24 +43,25 @@ 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 | -| `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 | +| field | type | Description | +|-----------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` | int | ID of the comment | +| `threadId` | int | ID of the top most parent comment, indicating the thread of this message (`0` for the messages without a parent) (only available with `threads` capability) | +| `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 | +| `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 | #### Parent data diff --git a/lib/Capabilities.php b/lib/Capabilities.php index 8692e988448..f93a71aa3d4 100644 --- a/lib/Capabilities.php +++ b/lib/Capabilities.php @@ -119,6 +119,7 @@ public function getCapabilities(): array { 'single-conversation-status', 'chat-keep-notifications', 'typing-privacy', + // FIXME Publish once the API is approved by the clients 'threads', ], 'config' => [ 'attachments' => [ diff --git a/lib/Model/Message.php b/lib/Model/Message.php index aa9f242b9a3..408addb9f0c 100644 --- a/lib/Model/Message.php +++ b/lib/Model/Message.php @@ -181,6 +181,7 @@ public function toArray(string $format): array { $data = [ 'id' => (int) $this->getComment()->getId(), + 'threadId' => (int) $this->getComment()->getTopmostParentId(), 'token' => $this->getRoom()->getToken(), 'actorType' => $this->getActorType(), 'actorId' => $this->getActorId(), diff --git a/tests/integration/features/bootstrap/FeatureContext.php b/tests/integration/features/bootstrap/FeatureContext.php index 9288761cca4..72f3c50ef30 100644 --- a/tests/integration/features/bootstrap/FeatureContext.php +++ b/tests/integration/features/bootstrap/FeatureContext.php @@ -2233,6 +2233,7 @@ protected function compareDataResponse(TableNode $formData = null) { $includeReferenceId = in_array('referenceId', $formData->getRow(0), true); $includeReactions = in_array('reactions', $formData->getRow(0), true); $includeReactionsSelf = in_array('reactionsSelf', $formData->getRow(0), true); + $includeThreadId = in_array('threadId', $formData->getRow(0), true); $expected = $formData->getHash(); $count = count($expected); @@ -2242,6 +2243,10 @@ protected function compareDataResponse(TableNode $formData = null) { $messages[$i]['messageParameters'] = 'IGNORE'; } + if ($includeThreadId && !is_numeric($expected[$i]['threadId'])) { + $expected[$i]['threadId'] = self::$textToMessageId[$expected[$i]['threadId']]; + } + $result = preg_match('/POLL_ID\(([^)]+)\)/', $expected[$i]['messageParameters'], $matches); if ($result) { $expected[$i]['messageParameters'] = str_replace($matches[0], '"' . self::$questionToPollId[$matches[1]] . '"', $expected[$i]['messageParameters']); @@ -2255,7 +2260,7 @@ protected function compareDataResponse(TableNode $formData = null) { } } - Assert::assertEquals($expected, array_map(function ($message) use ($includeParents, $includeReferenceId, $includeReactions, $includeReactionsSelf) { + Assert::assertEquals($expected, array_map(function ($message) use ($includeParents, $includeReferenceId, $includeReactions, $includeReactionsSelf, $includeThreadId) { $data = [ 'room' => self::$tokenToIdentifier[$message['token']], 'actorType' => $message['actorType'], @@ -2282,6 +2287,9 @@ protected function compareDataResponse(TableNode $formData = null) { $data['reactionsSelf'] = null; } } + if ($includeThreadId) { + $data['threadId'] = $message['threadId']; + } return $data; }, $messages)); } diff --git a/tests/integration/features/chat-2/reply.feature b/tests/integration/features/chat-2/reply.feature index 42404ce583e..1ae0ff2c7cd 100644 --- a/tests/integration/features/chat-2/reply.feature +++ b/tests/integration/features/chat-2/reply.feature @@ -13,13 +13,13 @@ Feature: chat-2/reply And user "participant1" sends message "Message 1" to room "group room" with 201 When user "participant1" sends reply "Message 1-1" on message "Message 1" to room "group room" with 201 Then user "participant1" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | And user "participant2" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | Scenario: user can reply to other's messages Given user "participant1" creates room "group room" (v4) @@ -28,13 +28,13 @@ Feature: chat-2/reply And user "participant1" sends message "Message 1" to room "group room" with 201 When user "participant2" sends reply "Message 1-1" on message "Message 1" to room "group room" with 201 Then user "participant1" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | And user "participant2" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | Scenario: several users can reply to the same message several times Given user "participant1" creates room "group room" (v4) @@ -46,19 +46,19 @@ Feature: chat-2/reply And user "participant1" sends reply "Message 1-3" on message "Message 1" to room "group room" with 201 And user "participant2" sends reply "Message 1-4" on message "Message 1" to room "group room" with 201 Then user "participant1" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant2 | participant2-displayname | Message 1-4 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1-3 | [] | Message 1 | - | group room | users | participant2 | participant2-displayname | Message 1-2 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant2 | participant2-displayname | Message 1-4 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-3 | [] | Message 1 | Message 1 | + | group room | users | participant2 | participant2-displayname | Message 1-2 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | And user "participant2" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant2 | participant2-displayname | Message 1-4 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1-3 | [] | Message 1 | - | group room | users | participant2 | participant2-displayname | Message 1-2 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant2 | participant2-displayname | Message 1-4 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-3 | [] | Message 1 | Message 1 | + | group room | users | participant2 | participant2-displayname | Message 1-2 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | @@ -72,23 +72,23 @@ Feature: chat-2/reply # The file message parameters are not relevant for this test and are quite # large, so they are simply ignored. And user "participant1" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant1 | participant1-displayname | {file} | "IGNORE" | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant1 | participant1-displayname | {file} | "IGNORE" | | 0 | And user "participant2" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant1 | participant1-displayname | {file} | "IGNORE" | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant1 | participant1-displayname | {file} | "IGNORE" | | 0 | When user "participant1" sends reply "Message X-1" on message "{file}" to room "group room" with 201 And user "participant2" sends reply "Message X-2" on message "{file}" to room "group room" with 201 Then user "participant1" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant2 | participant2-displayname | Message X-2 | [] | {file} | - | group room | users | participant1 | participant1-displayname | Message X-1 | [] | {file} | - | group room | users | participant1 | participant1-displayname | {file} | "IGNORE" | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant2 | participant2-displayname | Message X-2 | [] | {file} | {file} | + | group room | users | participant1 | participant1-displayname | Message X-1 | [] | {file} | {file} | + | group room | users | participant1 | participant1-displayname | {file} | "IGNORE" | | 0 | And user "participant2" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant2 | participant2-displayname | Message X-2 | [] | {file} | - | group room | users | participant1 | participant1-displayname | Message X-1 | [] | {file} | - | group room | users | participant1 | participant1-displayname | {file} | "IGNORE" | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant2 | participant2-displayname | Message X-2 | [] | {file} | {file} | + | group room | users | participant1 | participant1-displayname | Message X-1 | [] | {file} | {file} | + | group room | users | participant1 | participant1-displayname | {file} | "IGNORE" | | 0 | Scenario: user can not reply to commands Given user "participant1" creates room "group room" (v4) @@ -128,15 +128,15 @@ Feature: chat-2/reply And user "participant1" sends reply "Message 1-1" on message "Message 1" to room "group room" with 201 When user "participant1" sends reply "Message 1-1-1" on message "Message 1-1" to room "group room" with 201 Then user "participant1" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | - | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | And user "participant2" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | - | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | Scenario: user can reply to other's replies Given user "participant1" creates room "group room" (v4) @@ -147,17 +147,17 @@ Feature: chat-2/reply When user "participant1" sends reply "Message 1-1-1" on message "Message 1-1" to room "group room" with 201 And user "participant2" sends reply "Message 1-1-1-1" on message "Message 1-1-1" to room "group room" with 201 Then user "participant1" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant2 | participant2-displayname | Message 1-1-1-1 | [] | Message 1-1-1 | - | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | - | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant2 | participant2-displayname | Message 1-1-1-1 | [] | Message 1-1-1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | Message 1 | + | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | And user "participant2" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant2 | participant2-displayname | Message 1-1-1-1 | [] | Message 1-1-1 | - | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | - | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant2 | participant2-displayname | Message 1-1-1-1 | [] | Message 1-1-1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | Message 1 | + | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | Scenario: several users can reply to the same reply several times Given user "participant1" creates room "group room" (v4) @@ -170,21 +170,21 @@ Feature: chat-2/reply And user "participant1" sends reply "Message 1-1-3" on message "Message 1-1" to room "group room" with 201 And user "participant2" sends reply "Message 1-1-4" on message "Message 1-1" to room "group room" with 201 Then user "participant1" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant2 | participant2-displayname | Message 1-1-4 | [] | Message 1-1 | - | group room | users | participant1 | participant1-displayname | Message 1-1-3 | [] | Message 1-1 | - | group room | users | participant2 | participant2-displayname | Message 1-1-2 | [] | Message 1-1 | - | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | - | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant2 | participant2-displayname | Message 1-1-4 | [] | Message 1-1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-1-3 | [] | Message 1-1 | Message 1 | + | group room | users | participant2 | participant2-displayname | Message 1-1-2 | [] | Message 1-1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | Message 1 | + | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | And user "participant2" sees the following messages in room "group room" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant2 | participant2-displayname | Message 1-1-4 | [] | Message 1-1 | - | group room | users | participant1 | participant1-displayname | Message 1-1-3 | [] | Message 1-1 | - | group room | users | participant2 | participant2-displayname | Message 1-1-2 | [] | Message 1-1 | - | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | - | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant2 | participant2-displayname | Message 1-1-4 | [] | Message 1-1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-1-3 | [] | Message 1-1 | Message 1 | + | group room | users | participant2 | participant2-displayname | Message 1-1-2 | [] | Message 1-1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1-1-1 | [] | Message 1-1 | Message 1 | + | group room | users | participant2 | participant2-displayname | Message 1-1 | [] | Message 1 | Message 1 | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | Scenario: getting parent and quote works Given user "participant1" creates room "group room" (v4) @@ -194,14 +194,14 @@ Feature: chat-2/reply And user "participant1" sends message "Message 2" to room "group room" with 201 And user "participant2" sends reply "Message 2-1" on message "Message 2" to room "group room" with 201 Then user "participant1" sees the following messages in room "group room" starting with "Message 1" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant1 | participant1-displayname | Message 1 | [] | | - | group room | users | participant1 | participant1-displayname | Message 2 | [] | | - | group room | users | participant2 | participant2-displayname | Message 2-1 | [] | Message 2 | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant1 | participant1-displayname | Message 1 | [] | | 0 | + | group room | users | participant1 | participant1-displayname | Message 2 | [] | | 0 | + | group room | users | participant2 | participant2-displayname | Message 2-1 | [] | Message 2 | Message 2 | Then user "participant1" sees the following messages in room "group room" starting with "Message 2" with 200 - | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | - | group room | users | participant1 | participant1-displayname | Message 2 | [] | | - | group room | users | participant2 | participant2-displayname | Message 2-1 | [] | Message 2 | + | room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | threadId | + | group room | users | participant1 | participant1-displayname | Message 2 | [] | | 0 | + | group room | users | participant2 | participant2-displayname | Message 2-1 | [] | Message 2 | Message 2 |