diff --git a/ts/models/messages.ts b/ts/models/messages.ts index e57d2b79a..f7292344d 100644 --- a/ts/models/messages.ts +++ b/ts/models/messages.ts @@ -2482,12 +2482,18 @@ export class MessageModel extends window.Backbone.Model { if (!storyQuoteIsFromSelf) { return true; } + + // The sender is not a recipient for this story if (sendState === undefined) { return false; } + + // Group replies are always allowed if (!isDirectConversation(conversation.attributes)) { - return false; + return true; } + + // For 1:1 stories, we need to check if they can be replied to return sendState.isAllowedToReplyToStory !== false; }); diff --git a/ts/test-mock/messaging/stories_test.ts b/ts/test-mock/messaging/stories_test.ts index 7fab1d477..5904bebbc 100644 --- a/ts/test-mock/messaging/stories_test.ts +++ b/ts/test-mock/messaging/stories_test.ts @@ -4,6 +4,7 @@ import createDebug from 'debug'; import Long from 'long'; import { Proto, StorageState } from '@signalapp/mock-server'; +import type { Group } from '@signalapp/mock-server'; import * as durations from '../../util/durations'; import { uuidToBytes } from '../../util/uuidToBytes'; @@ -24,6 +25,7 @@ describe('story/messaging', function unknownContacts() { let bootstrap: Bootstrap; let app: App; + let group: Group; beforeEach(async () => { bootstrap = new Bootstrap(); @@ -81,6 +83,20 @@ describe('story/messaging', function unknownContacts() { }, }); + // Add a group for story send + const members = [...contacts].slice(0, 10); + group = await phone.createGroup({ + title: 'Mock Group', + members: [phone, ...members], + }); + + state = state + .addGroup(group, { + whitelisted: true, + storySendMode: Proto.GroupV2Record.StorySendMode.ENABLED, + }) + .pinGroup(group); + // Finally whitelist and pin contacts for (const contact of [first, second]) { state = state.addContact(contact, { @@ -192,4 +208,69 @@ describe('story/messaging', function unknownContacts() { .locator(`[data-testid="${second.device.uuid}"] >> "second reply"`) .waitFor(); }); + + it('allows replies to groups', async () => { + const { desktop, contacts } = bootstrap; + + const window = await app.getWindow(); + + debug('waiting for storage service sync to complete'); + await app.waitForStorageService(); + + const leftPane = window.locator('.left-pane-wrapper'); + + debug('Create and send a story to the group'); + await leftPane.getByRole('button', { name: 'Stories' }).click(); + await window.getByRole('button', { name: 'Add a story' }).first().click(); + await window.getByRole('button', { name: 'Text story' }).click(); + await window.locator('.TextAttachment').click(); + await window.getByRole('textbox', { name: 'Add text' }).type('hello'); + await window.getByRole('button', { name: 'Next' }).click(); + await window + .locator('.Checkbox__container') + .getByText('Mock Group') + .click(); + await window.getByRole('button', { name: 'Send story' }).click(); + + // Grab the time the story was sent at + const time = await window.locator('time').nth(1).getAttribute('datetime'); + if (!time) { + throw new Error('Cannot locate story time'); + } + const sentAt = new Date(time).valueOf(); + + debug('Contact sends reply to group story'); + await contacts[0].sendRaw( + desktop, + { + dataMessage: { + body: 'first reply', + storyContext: { + authorUuid: desktop.uuid, + sentTimestamp: Long.fromNumber(sentAt), + }, + groupV2: { + masterKey: group.masterKey, + }, + timestamp: Long.fromNumber(sentAt + 1), + }, + }, + { timestamp: sentAt + 1 } + ); + + debug('Ensure sender sees the reply'); + await window + .locator('.StoryListItem__button') + .getByText('Mock Group') + .click(); + // For some reason we need to click the story & exit before the reply shows up + await window.getByRole('button', { name: 'Close' }).click(); + await window + .locator('.StoryListItem__button') + .getByText('Mock Group') + .click(); + + await window.getByText('1 reply').click(); + await window.getByText('first reply').waitFor(); + }); }); diff --git a/ts/util/findStoryMessage.ts b/ts/util/findStoryMessage.ts index 8789f4170..5f25346bc 100644 --- a/ts/util/findStoryMessage.ts +++ b/ts/util/findStoryMessage.ts @@ -50,7 +50,7 @@ export async function findStoryMessages( isStoryAMatch(item, conversationId, ourConversationId, authorUuid, sentAt) ); - if (found.length !== 0) { + if (found.length === 0) { log.info('findStoryMessages: message not found', sentAt); return []; }