Skip to content
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
4 changes: 4 additions & 0 deletions lib/Controller/ChatController.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ private function resolveReplyTo(int $replyTo, string $replyToToken, string $acto

$parentActorId = $parent->getActorId();
$parentActorType = $parent->getActorType();
if ($parentActorType === $actorType && $parentActorId === $actorId) {
throw new \InvalidArgumentException('reply-to', Http::STATUS_BAD_REQUEST);
}

// Validate if the members are part of the convo
try {
$this->participantService->getParticipantByActor($targetParentRoom, $actorType, $actorId);
Expand Down
49 changes: 47 additions & 2 deletions tests/integration/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -2752,6 +2752,28 @@ public function userSendsReplyToRoom(string $user, string $reply, string $messag
}
}

#[Then('/^user "([^"]*)" sends private reply ("[^"]*"|\'[^\']*\') on message ("[^"]*"|\'[^\']*\') from room "([^"]*)" to room "([^"]*)" with (\d+)(?: \((v1)\))?$/')]
public function userSendsPrivateReplyToRoom(string $user, string $reply, string $message, string $sourceIdentifier, string $targetIdentifier, int $statusCode, string $apiVersion = 'v1'): void {
$reply = substr($reply, 1, -1);
$message = substr($message, 1, -1);

$replyTo = self::$textToMessageId[$message];

$this->setCurrentUser($user);
$this->sendRequest(
'POST', '/apps/spreed/api/' . $apiVersion . '/chat/' . self::$identifierToToken[$targetIdentifier],
new TableNode([['message', $reply], ['replyTo', $replyTo], ['replyToToken', self::$identifierToToken[$sourceIdentifier]]])
);
$this->assertStatusCode($this->response, $statusCode);
sleep(1); // make sure Postgres manages the order of the messages

$response = $this->getDataFromResponse($this->response);
if (isset($response['id'])) {
self::$textToMessageId[$reply] = $response['id'];
self::$messageIdToText[$response['id']] = $reply;
}
}

#[Then('next message request has the following parameters set')]
public function setChatParametersForNextRequest(?TableNode $formData = null): void {
$parameters = [];
Expand Down Expand Up @@ -2907,6 +2929,13 @@ protected function compareDataResponse(?TableNode $formData = null): void {
static fn (string $field): bool => str_starts_with($field, 'metaData.')
)
);
$includeParentMetaDataKeys = array_map(
static fn (string $field): string => substr($field, strlen('parentMetaData.')),
array_filter(
$formData->getRow(0),
static fn (string $field): bool => str_starts_with($field, 'parentMetaData.')
)
);

$expected = $formData->getHash();
$count = count($expected);
Expand Down Expand Up @@ -2983,9 +3012,19 @@ protected function compareDataResponse(?TableNode $formData = null): void {
$messages[$i]['threadReplies'] = null;
}
}

if (!empty($includeParentMetaDataKeys)) {
foreach ($includeParentMetaDataKeys as $key) {
if ($key === 'replyToMessageId' && isset($expected[$i]['parentMetaData.' . $key])) {
$expected[$i]['parentMetaData.' . $key] = self::$textToMessageId[$expected[$i]['parentMetaData.' . $key]];
} elseif ($key === 'replyToConversationToken' && isset($expected[$i]['parentMetaData.' . $key])) {
$expected[$i]['parentMetaData.' . $key] = self::$identifierToToken[$expected[$i]['parentMetaData.' . $key]];
}
}
}
}

Assert::assertEquals($expected, array_map(function ($message, $expected) use ($includeParents, $includeReferenceId, $includeReactions, $includeReactionsSelf, $includeLastEdit, $includeMessageType, $includeThreadTitle, $includeThreadReplies, $includeMetaDataKeys) {
Assert::assertEquals($expected, array_map(function ($message, $expected) use ($includeParents, $includeReferenceId, $includeReactions, $includeReactionsSelf, $includeLastEdit, $includeMessageType, $includeThreadTitle, $includeThreadReplies, $includeMetaDataKeys, $includeParentMetaDataKeys) {
$data = [
'room' => self::$tokenToIdentifier[$message['token']],
'actorType' => $message['actorType'],
Expand Down Expand Up @@ -3038,7 +3077,6 @@ protected function compareDataResponse(?TableNode $formData = null): void {

if (!empty($includeMetaDataKeys)) {
$metaData = $message['metaData'] ?? [];
var_dump($message['message'], $metaData);
foreach ($includeMetaDataKeys as $key) {
$data['metaData.' . $key] = $metaData[$key] ?? 'UNSET';
$expectedValue = $expected['metaData.' . $key];
Expand All @@ -3048,6 +3086,13 @@ protected function compareDataResponse(?TableNode $formData = null): void {
}
}

if (!empty($includeParentMetaDataKeys)) {
$parentMetaData = $message['parent']['metaData'] ?? [];
foreach ($includeParentMetaDataKeys as $key) {
$data['parentMetaData.' . $key] = $parentMetaData[$key] ?? 'UNSET';
}
}

return $data;
}, $messages, $expected));
}
Expand Down
196 changes: 196 additions & 0 deletions tests/integration/features/chat-4/private-reply.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
Feature: chat-4/private-reply
Background:
Given user "participant1" exists
Given user "participant2" exists
Given user "participant3" exists
And group "attendees1" exists
And user "participant1" is member of group "attendees1"
And user "participant2" is member of group "attendees1"

Scenario: user can send a private reply from a group room to a one-to-one room
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant2" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
And user "participant2" joins room "one-to-one room" with 200 (v4)
And user "participant1" sends message "Original Message" to room "group room" with 201
When user "participant2" sends private reply "Private Response" on message "Original Message" from room "group room" to room "one-to-one room" with 201
Then user "participant2" sees the following messages in room "one-to-one room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage |
| one-to-one room | users | participant2 | participant2-displayname | Private Response | [] | Original Message |
And user "participant1" sees the following messages in room "one-to-one room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage |
| one-to-one room | users | participant2 | participant2-displayname | Private Response | [] | Original Message |

Scenario: user can send a private reply to their own message
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant1" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant2 |
And user "participant1" sends message "My Message" to room "group room" with 201
When user "participant1" sends private reply "Follow-up" on message "My Message" from room "group room" to room "one-to-one room" with 400

Scenario: multiple private replies to the same message
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| roomName | group room |
| invite | attendees1 |
And user "participant2" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
And user "participant1" sends message "Original" to room "group room" with 201
When user "participant2" sends private reply "Reply 1" on message "Original" from room "group room" to room "one-to-one room" with 201
And user "participant2" sends private reply "Reply 2" on message "Original" from room "group room" to room "one-to-one room" with 201
Then user "participant1" sees the following messages in room "one-to-one room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | parentMetaData.replyToConversationName | parentMetaData.replyToActorDisplayName | parentMetaData.replyToMessageId | parentMetaData.replyToConversationToken |
| one-to-one room | users | participant2 | participant2-displayname | Reply 2 | [] | Original | group room | participant1-displayname | Original | group room |
| one-to-one room | users | participant2 | participant2-displayname | Reply 1 | [] | Original | group room | participant1-displayname | Original | group room |

Scenario: private reply parent contains correct metadata
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| roomName | group room |
| invite | attendees1 |
And user "participant2" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
And user "participant1" sends message "Source Message" to room "group room" with 201
When user "participant2" sends private reply "Private Reply" on message "Source Message" from room "group room" to room "one-to-one room" with 201
Then user "participant2" sees the following messages in room "one-to-one room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage | parentMetaData.replyToConversationName | parentMetaData.replyToActorDisplayName | parentMetaData.replyToMessageId | parentMetaData.replyToConversationToken |
| one-to-one room | users | participant2 | participant2-displayname | Private Reply | [] | Source Message | group room | participant1-displayname | Source Message | group room |

Scenario: private reply does not show the link message in the message list
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant2" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
And user "participant1" sends message "Original" to room "group room" with 201
When user "participant2" sends private reply "Reply" on message "Original" from room "group room" to room "one-to-one room" with 201
# Only the actual reply should be visible, not the internal link message
Then user "participant1" sees the following messages in room "one-to-one room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage |
| one-to-one room | users | participant2 | participant2-displayname | Reply | [] | Original |

Scenario: private reply does not affect the source conversation
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant2" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
And user "participant1" sends message "Original" to room "group room" with 201
When user "participant2" sends private reply "Reply" on message "Original" from room "group room" to room "one-to-one room" with 201
# Source conversation should still only have the original message
Then user "participant1" sees the following messages in room "group room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters |
| group room | users | participant1 | participant1-displayname | Original | [] |

Scenario: user can reply normally to a private reply message in the one-to-one room
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant2" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
And user "participant1" sends message "Original" to room "group room" with 201
And user "participant2" sends private reply "Private Reply" on message "Original" from room "group room" to room "one-to-one room" with 201
When user "participant1" sends reply "Follow-up" on message "Private Reply" to room "one-to-one room" with 201
Then user "participant1" sees the following messages in room "one-to-one room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage |
| one-to-one room | users | participant1 | participant1-displayname | Follow-up | [] | Private Reply |
| one-to-one room | users | participant2 | participant2-displayname | Private Reply | [] | Original |

Scenario: cannot send a private reply to a group room
Given user "participant1" creates room "group room1" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant1" creates room "group room2" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant1" sends message "Original" to room "group room1" with 201
When user "participant1" sends private reply "Reply" on message "Original" from room "group room1" to room "group room2" with 400

Scenario: cannot send a private reply to a public room
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant1" creates room "public room" (v4)
| roomType | 3 |
| invite | attendees1 |
And user "participant1" sends message "Original" to room "group room" with 201
When user "participant1" sends private reply "Reply" on message "Original" from room "group room" to room "public room" with 400

Scenario: cannot send a private reply when sender is not in the source conversation
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant3" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
And user "participant1" sends message "Original" to room "group room" with 201
# participant3 is not in "group room"
When user "participant3" sends private reply "Reply" on message "Original" from room "group room" to room "one-to-one room" with 403

Scenario: cannot send a private reply when original author left the source conversation
Given user "participant2" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant2" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
And user "participant1" sends message "Original" to room "group room" with 201
# Remove participant1 (original message author) from the group room
And user "participant1" removes themselves from room "group room" with 200 (v4)
When user "participant2" sends private reply "Reply" on message "Original" from room "group room" to room "one-to-one room" with 403

Scenario: cannot send a private reply to a system message
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant2" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
# Get system messages so they are added to the known messages list
And user "participant1" sees the following system messages in room "group room" with 200
| room | actorType | actorId | actorDisplayName | systemMessage |
| group room | users | participant1 | participant1-displayname | user_added |
| group room | users | participant1 | participant1-displayname | group_added |
| group room | users | participant1 | participant1-displayname | conversation_created |
When user "participant2" sends private reply "Reply" on message "conversation_created" from room "group room" to room "one-to-one room" with 400

Scenario: editing the original message does not change the private reply parent snapshot
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant2" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
And user "participant1" sends message "Original Message" to room "group room" with 201
And user "participant2" sends private reply "Private Reply" on message "Original Message" from room "group room" to room "one-to-one room" with 201
When user "participant1" edits message "Original Message" in room "group room" to "Edited Message" with 200
# The private reply parent should still show the original text (snapshot)
Then user "participant2" sees the following messages in room "one-to-one room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage |
| one-to-one room | users | participant2 | participant2-displayname | Private Reply | [] | Original Message |

Scenario: deleting the original message does not affect the private reply parent snapshot
Given user "participant1" creates room "group room" (v4)
| roomType | 2 |
| invite | attendees1 |
And user "participant2" creates room "one-to-one room" (v4)
| roomType | 1 |
| invite | participant1 |
And user "participant1" sends message "Original Message" to room "group room" with 201
And user "participant2" sends private reply "Private Reply" on message "Original Message" from room "group room" to room "one-to-one room" with 201
When user "participant1" deletes message "Original Message" from room "group room" with 200
# The private reply parent should still show the original text (snapshot)
Then user "participant2" sees the following messages in room "one-to-one room" with 200
| room | actorType | actorId | actorDisplayName | message | messageParameters | parentMessage |
| one-to-one room | users | participant2 | participant2-displayname | Private Reply | [] | Original Message |
Loading