|
3 | 3 |
|
4 | 4 | import type { |
5 | 5 | ReadonlyMessageAttributesType, |
6 | | - MessageAttributesType, |
| 6 | + ConversationAttributesType, |
7 | 7 | } from '../model-types.d.ts'; |
8 | 8 | import { type AciString } from '../types/ServiceId.std.js'; |
9 | 9 | import type { ProcessedStoryContext } from '../textsecure/Types.d.ts'; |
10 | | -import { DataReader } from '../sql/Client.preload.js'; |
11 | 10 | import { createLogger } from '../logging/log.std.js'; |
12 | 11 | import { getAuthorId } from '../messages/sources.preload.js'; |
| 12 | +import { itemStorage } from '../textsecure/Storage.preload.js'; |
| 13 | +import { isDirectConversation } from './whatTypeOfConversation.dom.js'; |
13 | 14 |
|
14 | 15 | const log = createLogger('findStoryMessage'); |
15 | 16 |
|
16 | | -export async function findStoryMessages( |
17 | | - conversationId: string, |
18 | | - storyContext?: ProcessedStoryContext |
19 | | -): Promise<Array<MessageAttributesType>> { |
| 17 | +export type FindStoryMessageOptionsType = Readonly<{ |
| 18 | + conversation: ConversationAttributesType; |
| 19 | + senderId: string; |
| 20 | + storyContext?: ProcessedStoryContext; |
| 21 | +}>; |
| 22 | + |
| 23 | +export async function findStoryMessage({ |
| 24 | + conversation, |
| 25 | + senderId, |
| 26 | + storyContext, |
| 27 | +}: FindStoryMessageOptionsType): Promise< |
| 28 | + ReadonlyMessageAttributesType | undefined |
| 29 | +> { |
20 | 30 | if (!storyContext) { |
21 | | - return []; |
| 31 | + return undefined; |
22 | 32 | } |
23 | 33 |
|
24 | 34 | const { authorAci, sentTimestamp: sentAt } = storyContext; |
25 | 35 |
|
26 | 36 | if (!sentAt) { |
27 | | - return []; |
| 37 | + return undefined; |
28 | 38 | } |
29 | 39 |
|
30 | 40 | if (authorAci == null) { |
31 | | - return []; |
| 41 | + return undefined; |
32 | 42 | } |
33 | 43 |
|
34 | 44 | const ourConversationId = |
35 | 45 | window.ConversationController.getOurConversationIdOrThrow(); |
| 46 | + const ourAci = itemStorage.user.getCheckedAci(); |
| 47 | + |
| 48 | + const found = await window.MessageCache.findBySentAt( |
| 49 | + sentAt, |
| 50 | + ({ attributes: candidate }) => { |
| 51 | + if ( |
| 52 | + !isStoryAMatch( |
| 53 | + candidate, |
| 54 | + conversation.id, |
| 55 | + ourConversationId, |
| 56 | + authorAci, |
| 57 | + sentAt |
| 58 | + ) |
| 59 | + ) { |
| 60 | + return false; |
| 61 | + } |
| 62 | + |
| 63 | + const sendStateByConversationId = |
| 64 | + candidate.sendStateByConversationId || {}; |
| 65 | + const sendState = sendStateByConversationId[senderId]; |
| 66 | + |
| 67 | + const storyQuoteIsFromSelf = candidate.sourceServiceId === ourAci; |
| 68 | + |
| 69 | + if (!storyQuoteIsFromSelf) { |
| 70 | + return true; |
| 71 | + } |
| 72 | + |
| 73 | + // The sender is not a recipient for this story |
| 74 | + if (sendState === undefined) { |
| 75 | + return false; |
| 76 | + } |
| 77 | + |
| 78 | + // Group replies are always allowed |
| 79 | + if (!isDirectConversation(conversation)) { |
| 80 | + return true; |
| 81 | + } |
36 | 82 |
|
37 | | - const messages = await DataReader.getMessagesBySentAt(sentAt); |
38 | | - const found = messages.filter(item => |
39 | | - isStoryAMatch(item, conversationId, ourConversationId, authorAci, sentAt) |
| 83 | + // For 1:1 stories, we need to check if they can be replied to |
| 84 | + return sendState.isAllowedToReplyToStory !== false; |
| 85 | + } |
40 | 86 | ); |
41 | 87 |
|
42 | | - if (found.length === 0) { |
| 88 | + if (found == null) { |
43 | 89 | log.info('findStoryMessages: message not found', sentAt); |
44 | | - return []; |
| 90 | + return undefined; |
45 | 91 | } |
46 | 92 |
|
47 | | - return found; |
| 93 | + return found.attributes; |
48 | 94 | } |
49 | 95 |
|
50 | 96 | function isStoryAMatch( |
|
0 commit comments