diff --git a/ts/groups.ts b/ts/groups.ts index a6682c6678..f2fe49390d 100644 --- a/ts/groups.ts +++ b/ts/groups.ts @@ -2025,13 +2025,12 @@ export async function createGroupV2( forceSave: true, ourAci, }); - let model = new window.Whisper.Message(createdTheGroupMessage); - model = window.MessageCache.__DEPRECATED$register( - model.id, - model, + window.MessageCache.__DEPRECATED$register( + createdTheGroupMessage.id, + new window.Whisper.Message(createdTheGroupMessage), 'createGroupV2' ); - conversation.trigger('newmessage', model); + conversation.trigger('newmessage', createdTheGroupMessage); if (expireTimer) { await conversation.updateExpirationTimer(expireTimer, { @@ -3435,13 +3434,12 @@ async function appendChangeMessages( continue; } - let model = new window.Whisper.Message(changeMessage); - model = window.MessageCache.__DEPRECATED$register( - model.id, - model, + window.MessageCache.__DEPRECATED$register( + changeMessage.id, + new window.Whisper.Message(changeMessage), 'appendChangeMessages' ); - conversation.trigger('newmessage', model); + conversation.trigger('newmessage', changeMessage); newMessages += 1; } diff --git a/ts/jobs/helpers/sendReaction.ts b/ts/jobs/helpers/sendReaction.ts index 60b2205a1a..83882d613e 100644 --- a/ts/jobs/helpers/sendReaction.ts +++ b/ts/jobs/helpers/sendReaction.ts @@ -341,13 +341,12 @@ export async function sendReaction( forceSave: true, }); - void conversation.addSingleMessage( - window.MessageCache.__DEPRECATED$register( - reactionMessage.id, - reactionMessage, - 'sendReaction' - ) + window.MessageCache.__DEPRECATED$register( + reactionMessage.id, + reactionMessage, + 'sendReaction' ); + void conversation.addSingleMessage(reactionMessage.attributes); } } diff --git a/ts/messageModifiers/MessageReceipts.ts b/ts/messageModifiers/MessageReceipts.ts index 928570b46e..9542ff7870 100644 --- a/ts/messageModifiers/MessageReceipts.ts +++ b/ts/messageModifiers/MessageReceipts.ts @@ -4,8 +4,10 @@ import { z } from 'zod'; import { groupBy } from 'lodash'; -import type { MessageModel } from '../models/messages'; -import type { MessageAttributesType } from '../model-types.d'; +import type { + MessageAttributesType, + ReadonlyMessageAttributesType, +} from '../model-types.d'; import type { SendStateByConversationId } from '../messages/MessageSendState'; import { isOutgoing, isStory } from '../state/selectors/message'; import { getOwn } from '../util/getOwn'; @@ -376,7 +378,7 @@ const wasDeliveredWithSealedSender = ( const shouldDropReceipt = ( receipt: MessageReceiptAttributesType, - message: MessageAttributesType + message: ReadonlyMessageAttributesType ): boolean => { const { type } = receipt.receiptSync; switch (type) { @@ -395,25 +397,25 @@ const shouldDropReceipt = ( }; export async function forMessage( - message: MessageModel + message: ReadonlyMessageAttributesType ): Promise> { - if (!isOutgoing(message.attributes) && !isStory(message.attributes)) { + if (!isOutgoing(message) && !isStory(message)) { return []; } const logId = `MessageReceipts.forMessage(${getMessageIdForLogging( - message.attributes + message )})`; const ourAci = window.textsecure.storage.user.getCheckedAci(); - const sourceServiceId = getSourceServiceId(message.attributes); + const sourceServiceId = getSourceServiceId(message); if (ourAci !== sourceServiceId) { return []; } const receiptValues = Array.from(cachedReceipts.values()); - const sentAt = getMessageSentTimestamp(message.attributes, { log }); + const sentAt = getMessageSentTimestamp(message, { log }); const result = receiptValues.filter( item => item.receiptSync.messageSentAt === sentAt ); @@ -427,7 +429,7 @@ export async function forMessage( } return result.filter(receipt => { - if (shouldDropReceipt(receipt, message.attributes)) { + if (shouldDropReceipt(receipt, message)) { log.info( `${logId}: Dropping an early receipt ${receipt.receiptSync.type} for message ${sentAt}` ); diff --git a/ts/messageModifiers/Reactions.ts b/ts/messageModifiers/Reactions.ts index 80c33dbc89..bf8a40d7f9 100644 --- a/ts/messageModifiers/Reactions.ts +++ b/ts/messageModifiers/Reactions.ts @@ -2,7 +2,10 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { AciString } from '../types/ServiceId'; -import type { MessageAttributesType } from '../model-types.d'; +import type { + MessageAttributesType, + ReadonlyMessageAttributesType, +} from '../model-types.d'; import type { MessageModel } from '../models/messages'; import type { ReactionSource } from '../reactions/ReactionSource'; import { DataReader } from '../sql/Client'; @@ -41,11 +44,11 @@ function remove(reaction: ReactionAttributesType): void { } export function findReactionsForMessage( - message: MessageModel + message: ReadonlyMessageAttributesType ): Array { const matchingReactions = Array.from(reactions.values()).filter(reaction => { return isMessageAMatchForReaction({ - message: message.attributes, + message, targetTimestamp: reaction.targetTimestamp, targetAuthorAci: reaction.targetAuthorAci, reactionSenderConversationId: reaction.fromId, @@ -99,7 +102,7 @@ function isMessageAMatchForReaction({ targetAuthorAci, reactionSenderConversationId, }: { - message: MessageAttributesType; + message: ReadonlyMessageAttributesType; targetTimestamp: number; targetAuthorAci: string; reactionSenderConversationId: string; diff --git a/ts/messageModifiers/ReadSyncs.ts b/ts/messageModifiers/ReadSyncs.ts index 5cf2efd73a..35c6f6959c 100644 --- a/ts/messageModifiers/ReadSyncs.ts +++ b/ts/messageModifiers/ReadSyncs.ts @@ -3,7 +3,7 @@ import { z } from 'zod'; -import type { MessageModel } from '../models/messages'; +import type { ReadonlyMessageAttributesType } from '../model-types.d'; import * as Errors from '../types/errors'; import * as log from '../logging/log'; import { StartupQueue } from '../util/StartupQueue'; @@ -88,18 +88,16 @@ async function maybeItIsAReactionReadSync( } export async function forMessage( - message: MessageModel + message: ReadonlyMessageAttributesType ): Promise { - const logId = `ReadSyncs.forMessage(${getMessageIdForLogging( - message.attributes - )})`; + const logId = `ReadSyncs.forMessage(${getMessageIdForLogging(message)})`; const sender = window.ConversationController.lookupOrCreate({ - e164: message.get('source'), - serviceId: message.get('sourceServiceId'), + e164: message.source, + serviceId: message.sourceServiceId, reason: logId, }); - const messageTimestamp = getMessageSentTimestamp(message.attributes, { + const messageTimestamp = getMessageSentTimestamp(message, { log, }); const readSyncValues = Array.from(readSyncs.values()); @@ -169,7 +167,9 @@ export async function onSync(sync: ReadSyncAttributesType): Promise { // onReadMessage may result in messages older than this one being // marked read. We want those messages to have the same expire timer // start time as this one, so we pass the readAt value through. - drop(conversation.onReadMessage(message, readAt, newestSentAt)); + drop( + conversation.onReadMessage(message.attributes, readAt, newestSentAt) + ); }; // only available during initialization diff --git a/ts/messageModifiers/ViewOnceOpenSyncs.ts b/ts/messageModifiers/ViewOnceOpenSyncs.ts index f7cb779333..5bdccd44ee 100644 --- a/ts/messageModifiers/ViewOnceOpenSyncs.ts +++ b/ts/messageModifiers/ViewOnceOpenSyncs.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-only import type { AciString } from '../types/ServiceId'; -import type { MessageModel } from '../models/messages'; +import type { ReadonlyMessageAttributesType } from '../model-types.d'; import { DataReader } from '../sql/Client'; import * as Errors from '../types/errors'; import * as log from '../logging/log'; @@ -23,18 +23,18 @@ function remove(sync: ViewOnceOpenSyncAttributesType): void { } export function forMessage( - message: MessageModel + message: ReadonlyMessageAttributesType ): ViewOnceOpenSyncAttributesType | null { const logId = `ViewOnceOpenSyncs.forMessage(${getMessageIdForLogging( - message.attributes + message )})`; const viewOnceSyncValues = Array.from(viewOnceSyncs.values()); const syncBySourceServiceId = viewOnceSyncValues.find(item => { return ( - item.sourceAci === message.get('sourceServiceId') && - item.timestamp === message.get('sent_at') + item.sourceAci === message.sourceServiceId && + item.timestamp === message.sent_at ); }); @@ -45,10 +45,7 @@ export function forMessage( } const syncBySource = viewOnceSyncValues.find(item => { - return ( - item.source === message.get('source') && - item.timestamp === message.get('sent_at') - ); + return item.source === message.source && item.timestamp === message.sent_at; }); if (syncBySource) { log.info(`${logId}: Found early view once open sync for message`); diff --git a/ts/messageModifiers/ViewSyncs.ts b/ts/messageModifiers/ViewSyncs.ts index 8f36b40fb3..9f69e41bdf 100644 --- a/ts/messageModifiers/ViewSyncs.ts +++ b/ts/messageModifiers/ViewSyncs.ts @@ -3,7 +3,7 @@ import { z } from 'zod'; -import type { MessageModel } from '../models/messages'; +import type { ReadonlyMessageAttributesType } from '../model-types.d'; import * as Errors from '../types/errors'; import * as log from '../logging/log'; import { GiftBadgeStates } from '../components/conversation/Message'; @@ -44,18 +44,16 @@ async function remove(sync: ViewSyncAttributesType): Promise { } export async function forMessage( - message: MessageModel + message: ReadonlyMessageAttributesType ): Promise> { - const logId = `ViewSyncs.forMessage(${getMessageIdForLogging( - message.attributes - )})`; + const logId = `ViewSyncs.forMessage(${getMessageIdForLogging(message)})`; const sender = window.ConversationController.lookupOrCreate({ - e164: message.get('source'), - serviceId: message.get('sourceServiceId'), + e164: message.source, + serviceId: message.sourceServiceId, reason: logId, }); - const messageTimestamp = getMessageSentTimestamp(message.attributes, { + const messageTimestamp = getMessageSentTimestamp(message, { log, }); diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts index 6c987b743c..12a448035a 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -22,6 +22,9 @@ import { isShallowEqual } from '../util/isShallowEqual'; import { getInitials } from '../util/getInitials'; import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary'; import { getMessageSentTimestamp } from '../util/getMessageSentTimestamp'; +import { getNotificationTextForMessage } from '../util/getNotificationTextForMessage'; +import { getNotificationDataForMessage } from '../util/getNotificationDataForMessage'; +import type { ProfileNameChangeType } from '../util/getStringForProfileChange'; import type { AttachmentType, ThumbnailType } from '../types/Attachment'; import { toDayMillis } from '../util/timestamp'; import { areWeAdmin } from '../util/areWeAdmin'; @@ -35,6 +38,7 @@ import { import { getDraftPreview } from '../util/getDraftPreview'; import { hasDraft } from '../util/hasDraft'; import { missingCaseError } from '../util/missingCaseError'; +import { hydrateStoryContext } from '../util/hydrateStoryContext'; import * as Conversation from '../types/Conversation'; import type { StickerType, StickerWithHydratedData } from '../types/Stickers'; import * as Stickers from '../types/Stickers'; @@ -56,7 +60,6 @@ import type { ConversationColorType, CustomColorType, } from '../types/Colors'; -import type { MessageModel } from './messages'; import { getAuthor } from '../messages/helpers'; import { strictAssert } from '../util/assert'; import { isConversationMuted } from '../util/isConversationMuted'; @@ -173,6 +176,7 @@ import OS from '../util/os/osMain'; import { getMessageAuthorText } from '../util/getMessageAuthorText'; import { downscaleOutgoingAttachment } from '../util/attachments'; import { MessageRequestResponseEvent } from '../types/MessageRequestResponseEvent'; +import { hasExpiration } from '../types/Message2'; import type { MessageToDelete } from '../textsecure/messageReceiverEvents'; import { getConversationToDelete, @@ -399,7 +403,7 @@ export class ConversationModel extends window.Backbone // result in refresh via a getProps() call. See format() below. this.on( 'change', - (_model: MessageModel, options: { force?: boolean } = {}) => { + (_model: ConversationModel, options: { force?: boolean } = {}) => { const changedKeys = Object.keys(this.changed || {}); const isPropsCacheStillValid = !options.force && @@ -1395,10 +1399,8 @@ export class ConversationModel extends window.Backbone }); } - async onNewMessage(message: MessageModel): Promise { - const serviceId = message.get('sourceServiceId'); - const e164 = message.get('source'); - const sourceDevice = message.get('sourceDevice'); + async onNewMessage(message: MessageAttributesType): Promise { + const { sourceServiceId: serviceId, source: e164, sourceDevice } = message; const source = window.ConversationController.lookupOrCreate({ serviceId, @@ -1414,16 +1416,15 @@ export class ConversationModel extends window.Backbone // If it's a group story reply or a story message, we don't want to update // the last message or add new messages to redux. - const isGroupStoryReply = - isGroup(this.attributes) && message.get('storyId'); - if (isGroupStoryReply || isStory(message.attributes)) { + const isGroupStoryReply = isGroup(this.attributes) && message.storyId; + if (isGroupStoryReply || isStory(message)) { return; } // Change to message request state if contact was removed and sent message. if ( this.get('removalStage') === 'justNotification' && - isIncoming(message.attributes) + isIncoming(message) ) { this.set({ removalStage: 'messageRequest', @@ -1438,7 +1439,7 @@ export class ConversationModel extends window.Backbone // New messages might arrive while we're in the middle of a bulk fetch from the // database. We'll wait until that is done before moving forward. async addSingleMessage( - message: MessageModel, + message: MessageAttributesType, { isJustSent }: { isJustSent: boolean } = { isJustSent: false } ): Promise { await this.beforeAddSingleMessage(message); @@ -1446,8 +1447,10 @@ export class ConversationModel extends window.Backbone this.debouncedUpdateLastMessage(); } - private async beforeAddSingleMessage(message: MessageModel): Promise { - await message.hydrateStoryContext(undefined, { shouldSave: true }); + private async beforeAddSingleMessage( + message: MessageAttributesType + ): Promise { + await hydrateStoryContext(message.id, undefined, { shouldSave: true }); if (!this.newMessageQueue) { this.newMessageQueue = new PQueue({ @@ -1463,7 +1466,7 @@ export class ConversationModel extends window.Backbone } private doAddSingleMessage( - message: MessageModel, + message: MessageAttributesType, { isJustSent }: { isJustSent: boolean } ): void { const { messagesAdded } = window.reduxActions.conversations; @@ -1486,12 +1489,12 @@ export class ConversationModel extends window.Backbone } else if ( // The message has to be not a story or has to be a story reply in direct // conversation. - !isStory(message.attributes) && - (message.get('storyId') == null || isDirectConversation(this.attributes)) + !isStory(message) && + (message.storyId == null || isDirectConversation(this.attributes)) ) { messagesAdded({ conversationId, - messages: [{ ...message.attributes }], + messages: [{ ...message }], isActive: window.SignalContext.activeWindowService.isActive(), isJustSent, isNewMessage: true, @@ -1598,13 +1601,13 @@ export class ConversationModel extends window.Backbone storyId: undefined, }); - const cleaned: Array = await this.cleanModels(messages); + const cleaned = await this.cleanAttributes(messages); const scrollToMessageId = setFocus && metrics.newest ? metrics.newest.id : undefined; log.info( `${logId}: loaded ${cleaned.length} messages, ` + - `latest timestamp=${cleaned.at(-1)?.get('sent_at')}` + `latest timestamp=${cleaned.at(-1)?.sent_at}` ); // Because our `getOlderMessages` fetch above didn't specify a receivedAt, we got @@ -1615,9 +1618,7 @@ export class ConversationModel extends window.Backbone const unboundedFetch = true; messagesReset({ conversationId, - messages: cleaned.map((messageModel: MessageModel) => ({ - ...messageModel.attributes, - })), + messages: cleaned, metrics, scrollToMessageId, unboundedFetch, @@ -1666,18 +1667,16 @@ export class ConversationModel extends window.Backbone return; } - const cleaned = await this.cleanModels(models); + const cleaned = await this.cleanAttributes(models); log.info( `${logId}: loaded ${cleaned.length} messages, ` + - `first timestamp=${cleaned.at(0)?.get('sent_at')}` + `first timestamp=${cleaned.at(0)?.sent_at}` ); messagesAdded({ conversationId, - messages: cleaned.map((messageModel: MessageModel) => ({ - ...messageModel.attributes, - })), + messages: cleaned, isActive: window.SignalContext.activeWindowService.isActive(), isJustSent: false, isNewMessage: false, @@ -1726,12 +1725,10 @@ export class ConversationModel extends window.Backbone return; } - const cleaned = await this.cleanModels(models); + const cleaned = await this.cleanAttributes(models); messagesAdded({ conversationId, - messages: cleaned.map((messageModel: MessageModel) => ({ - ...messageModel.attributes, - })), + messages: cleaned, isActive: window.SignalContext.activeWindowService.isActive(), isJustSent: false, isNewMessage: false, @@ -1780,15 +1777,13 @@ export class ConversationModel extends window.Backbone }); const all = [...older, message, ...newer]; - const cleaned: Array = await this.cleanModels(all); + const cleaned = await this.cleanAttributes(all); const scrollToMessageId = options && options.disableScroll ? undefined : messageId; messagesReset({ conversationId, - messages: cleaned.map((messageModel: MessageModel) => ({ - ...messageModel.attributes, - })), + messages: cleaned, metrics, scrollToMessageId, }); @@ -1800,52 +1795,53 @@ export class ConversationModel extends window.Backbone } } - async cleanModels( + async cleanAttributes( messages: ReadonlyArray - ): Promise> { - const result = messages - .filter(message => Boolean(message.id)) - .map(message => - window.MessageCache.__DEPRECATED$register( - message.id, - message, - 'cleanModels' - ) - ); + ): Promise> { + const present = messages.filter(message => Boolean(message.id)); - const eliminated = messages.length - result.length; + const eliminated = messages.length - present.length; if (eliminated > 0) { - log.warn(`cleanModels: Eliminated ${eliminated} messages without an id`); + log.warn( + `cleanAttributes: Eliminated ${eliminated} messages without an id` + ); } const ourAci = window.textsecure.storage.user.getCheckedAci(); let upgraded = 0; - for (let max = result.length, i = 0; i < max; i += 1) { - const message = result[i]; - const { attributes } = message; - const { schemaVersion } = attributes; + const hydrated = await Promise.all( + present.map(async message => { + const { schemaVersion } = message; - if ((schemaVersion || 0) < Message.VERSION_NEEDED_FOR_DISPLAY) { - // Yep, we really do want to wait for each of these - // eslint-disable-next-line no-await-in-loop - const upgradedMessage = await upgradeMessageSchema(attributes); - message.set(upgradedMessage); - // eslint-disable-next-line no-await-in-loop - await DataWriter.saveMessage(upgradedMessage, { ourAci }); - upgraded += 1; - } - } - if (upgraded > 0) { - log.warn(`cleanModels: Upgraded schema of ${upgraded} messages`); - } + const model = window.MessageCache.__DEPRECATED$register( + message.id, + message, + 'cleanAttributes' + ); - await Promise.all( - result.map(model => - model.hydrateStoryContext(undefined, { shouldSave: true }) - ) + let upgradedMessage = message; + if ((schemaVersion || 0) < Message.VERSION_NEEDED_FOR_DISPLAY) { + // Yep, we really do want to wait for each of these + upgradedMessage = await upgradeMessageSchema(message); + model.set(upgradedMessage); + await DataWriter.saveMessage(upgradedMessage, { ourAci }); + upgraded += 1; + } + + const patch = await hydrateStoryContext(message.id, undefined, { + shouldSave: true, + }); + if (patch) { + return { ...upgradedMessage, ...patch }; + } + return upgradedMessage; + }) ); + if (upgraded > 0) { + log.warn(`cleanAttributes: Upgraded schema of ${upgraded} messages`); + } - return result; + return hydrated; } format(): ConversationType { @@ -2178,16 +2174,12 @@ export class ConversationModel extends window.Backbone messageRequestResponseEvent: event, }; - const id = await DataWriter.saveMessage(message, { + await DataWriter.saveMessage(message, { ourAci: window.textsecure.storage.user.getCheckedAci(), forceSave: true, }); - const model = new window.Whisper.Message({ - ...message, - id, - }); - window.MessageCache.toMessageAttributes(model.attributes); - this.trigger('newmessage', model); + window.MessageCache.toMessageAttributes(message); + this.trigger('newmessage', message); drop(this.updateLastMessage()); } @@ -2926,31 +2918,28 @@ export class ConversationModel extends window.Backbone receivedAt, }); - const message = { + const message: MessageAttributesType = { + id: generateGuid(), conversationId: this.id, type: 'chat-session-refreshed', + timestamp: receivedAt, sent_at: receivedAt, received_at: receivedAtCounter, received_at_ms: receivedAt, readStatus: ReadStatus.Unread, seenStatus: SeenStatus.Unseen, - // TODO: DESKTOP-722 - // this type does not fully implement the interface it is expected to - } as unknown as MessageAttributesType; + }; - const id = await DataWriter.saveMessage(message, { + await DataWriter.saveMessage(message, { ourAci: window.textsecure.storage.user.getCheckedAci(), }); - const model = window.MessageCache.__DEPRECATED$register( - id, - new window.Whisper.Message({ - ...message, - id, - }), + window.MessageCache.__DEPRECATED$register( + message.id, + message, 'addChatSessionRefreshed' ); - this.trigger('newmessage', model); + this.trigger('newmessage', message); void this.updateUnread(); } @@ -2977,34 +2966,31 @@ export class ConversationModel extends window.Backbone return; } - const message = { + const message: MessageAttributesType = { + id: generateGuid(), conversationId: this.id, type: 'delivery-issue', sourceServiceId: senderAci, sent_at: receivedAt, received_at: receivedAtCounter, received_at_ms: receivedAt, + timestamp: receivedAt, readStatus: ReadStatus.Unread, seenStatus: SeenStatus.Unseen, - // TODO: DESKTOP-722 - // this type does not fully implement the interface it is expected to - } as unknown as MessageAttributesType; + }; - const id = await DataWriter.saveMessage(message, { + await DataWriter.saveMessage(message, { ourAci: window.textsecure.storage.user.getCheckedAci(), }); - const model = window.MessageCache.__DEPRECATED$register( - id, - new window.Whisper.Message({ - ...message, - id, - }), + window.MessageCache.__DEPRECATED$register( + message.id, + message, 'addDeliveryIssue' ); - this.trigger('newmessage', model); + this.trigger('newmessage', message); - await this.notify(model); + await this.notify(message); void this.updateUnread(); } @@ -3048,13 +3034,13 @@ export class ConversationModel extends window.Backbone ourAci: window.textsecure.storage.user.getCheckedAci(), forceSave: true, }); - const model = window.MessageCache.__DEPRECATED$register( + window.MessageCache.__DEPRECATED$register( message.id, - new window.Whisper.Message(message), + message, 'addKeyChange' ); - this.trigger('newmessage', model); + this.trigger('newmessage', message); const serviceId = this.getServiceId(); @@ -3108,20 +3094,17 @@ export class ConversationModel extends window.Backbone schemaVersion: Message.VERSION_NEEDED_FOR_DISPLAY, }; - const id = await DataWriter.saveMessage(message, { + await DataWriter.saveMessage(message, { ourAci: window.textsecure.storage.user.getCheckedAci(), forceSave: true, }); - const model = window.MessageCache.__DEPRECATED$register( - id, - new window.Whisper.Message({ - ...message, - id, - }), + window.MessageCache.__DEPRECATED$register( + message.id, + message, 'addConversationMerge' ); - this.trigger('newmessage', model); + this.trigger('newmessage', message); } async addPhoneNumberDiscoveryIfNeeded(originalPni: PniString): Promise { @@ -3160,20 +3143,17 @@ export class ConversationModel extends window.Backbone schemaVersion: Message.VERSION_NEEDED_FOR_DISPLAY, }; - const id = await DataWriter.saveMessage(message, { + await DataWriter.saveMessage(message, { ourAci: window.textsecure.storage.user.getCheckedAci(), forceSave: true, }); - const model = window.MessageCache.__DEPRECATED$register( - id, - new window.Whisper.Message({ - ...message, - id, - }), + window.MessageCache.__DEPRECATED$register( + message.id, + message, 'addPhoneNumberDiscoveryIfNeeded' ); - this.trigger('newmessage', model); + this.trigger('newmessage', message); } async addVerifiedChange( @@ -3215,13 +3195,13 @@ export class ConversationModel extends window.Backbone ourAci: window.textsecure.storage.user.getCheckedAci(), forceSave: true, }); - const model = window.MessageCache.__DEPRECATED$register( + window.MessageCache.__DEPRECATED$register( message.id, - new window.Whisper.Message(message), + message, 'addVerifiedChange' ); - this.trigger('newmessage', model); + this.trigger('newmessage', message); drop(this.updateUnread()); const serviceId = this.getServiceId(); @@ -3237,11 +3217,12 @@ export class ConversationModel extends window.Backbone } async addProfileChange( - profileChange: unknown, + profileChange: ProfileNameChangeType, conversationId?: string ): Promise { const now = Date.now(); - const message = { + const message: MessageAttributesType = { + id: generateGuid(), conversationId: this.id, type: 'profile-change', sent_at: now, @@ -3249,24 +3230,21 @@ export class ConversationModel extends window.Backbone received_at_ms: now, readStatus: ReadStatus.Read, seenStatus: SeenStatus.NotApplicable, + timestamp: now, changedId: conversationId || this.id, profileChange, - // TODO: DESKTOP-722 - } as unknown as MessageAttributesType; + }; - const id = await DataWriter.saveMessage(message, { + await DataWriter.saveMessage(message, { ourAci: window.textsecure.storage.user.getCheckedAci(), }); - const model = window.MessageCache.__DEPRECATED$register( - id, - new window.Whisper.Message({ - ...message, - id, - }), + window.MessageCache.__DEPRECATED$register( + message.id, + message, 'addProfileChange' ); - this.trigger('newmessage', model); + this.trigger('newmessage', message); const serviceId = this.getServiceId(); if (isDirectConversation(this.attributes) && serviceId) { @@ -3287,37 +3265,33 @@ export class ConversationModel extends window.Backbone extra: Partial = {} ): Promise { const now = Date.now(); - const message: Partial = { + const message: MessageAttributesType = { + id: generateGuid(), conversationId: this.id, type, sent_at: now, received_at: incrementMessageCounter(), received_at_ms: now, + timestamp: now, + readStatus: ReadStatus.Read, seenStatus: SeenStatus.NotApplicable, ...extra, }; - const id = await DataWriter.saveMessage( - // TODO: DESKTOP-722 + await DataWriter.saveMessage(message, { + ourAci: window.textsecure.storage.user.getCheckedAci(), + }); + window.MessageCache.__DEPRECATED$register( + message.id, message as MessageAttributesType, - { - ourAci: window.textsecure.storage.user.getCheckedAci(), - } - ); - const model = window.MessageCache.__DEPRECATED$register( - id, - new window.Whisper.Message({ - ...(message as MessageAttributesType), - id, - }), 'addNotification' ); - this.trigger('newmessage', model); + this.trigger('newmessage', message); - return id; + return message.id; } async maybeSetPendingUniversalTimer( @@ -3489,7 +3463,7 @@ export class ConversationModel extends window.Backbone } async onReadMessage( - message: MessageModel, + message: MessageAttributesType, readAt?: number, newestSentAt?: number ): Promise { @@ -3506,8 +3480,8 @@ export class ConversationModel extends window.Backbone // sync. That's a notification explosion we don't need. return this.queueJob('onReadMessage', () => // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.markRead(message.get('received_at')!, { - newestSentAt: newestSentAt || message.get('sent_at'), + this.markRead(message.received_at!, { + newestSentAt: newestSentAt || message.sent_at, sendReadReceipts: false, readAt, }) @@ -3781,7 +3755,7 @@ export class ConversationModel extends window.Backbone now, extraReduxActions, }: { - message: MessageModel; + message: MessageAttributesType; dontAddMessage: boolean; dontClearDraft: boolean; now: number; @@ -3802,7 +3776,7 @@ export class ConversationModel extends window.Backbone if (!dontAddMessage) { this.doAddSingleMessage(message, { isJustSent: true }); } - const notificationData = message.getNotificationData(); + const notificationData = getNotificationDataForMessage(message); const draftProperties = dontClearDraft ? {} : { @@ -3811,14 +3785,16 @@ export class ConversationModel extends window.Backbone draftBodyRanges: [], draftTimestamp: null, quotedMessageId: undefined, - lastMessageAuthor: getMessageAuthorText(message.attributes), - lastMessageBodyRanges: message.get('bodyRanges'), + lastMessageAuthor: getMessageAuthorText(message), + lastMessageBodyRanges: message.bodyRanges, lastMessage: - notificationData?.text || message.getNotificationText() || '', + notificationData?.text || + getNotificationTextForMessage(message) || + '', lastMessageStatus: 'sending' as const, }; - const isEditMessage = Boolean(message.get('editHistory')); + const isEditMessage = Boolean(message.editHistory); this.set({ ...draftProperties, @@ -3988,17 +3964,16 @@ export class ConversationModel extends window.Backbone storyId, }); - const model = new window.Whisper.Message(attributes); - const message = window.MessageCache.__DEPRECATED$register( - model.id, - model, + window.MessageCache.__DEPRECATED$register( + attributes.id, + attributes, 'enqueueMessageForSend' ); const dbStart = Date.now(); strictAssert( - typeof message.attributes.timestamp === 'number', + typeof attributes.timestamp === 'number', 'Expected a timestamp' ); @@ -4006,14 +3981,14 @@ export class ConversationModel extends window.Backbone { type: conversationQueueJobEnum.enum.NormalMessage, conversationId: this.id, - messageId: message.id, + messageId: attributes.id, revision: this.get('revision'), }, async jobToInsert => { log.info( - `enqueueMessageForSend: saving message ${message.id} and job ${jobToInsert.id}` + `enqueueMessageForSend: saving message ${attributes.id} and job ${jobToInsert.id}` ); - await DataWriter.saveMessage(message.attributes, { + await DataWriter.saveMessage(attributes, { jobToInsert, forceSave: true, ourAci: window.textsecure.storage.user.getCheckedAci(), @@ -4032,14 +4007,14 @@ export class ConversationModel extends window.Backbone const renderStart = Date.now(); // Perform asynchronous tasks before entering the batching mode - await this.beforeAddSingleMessage(model); + await this.beforeAddSingleMessage(attributes); if (sticker) { - await addStickerPackReference(model.id, sticker.packId); + await addStickerPackReference(attributes.id, sticker.packId); } this.beforeMessageSend({ - message: model, + message: attributes, dontClearDraft, dontAddMessage: false, now, @@ -4184,35 +4159,27 @@ export class ConversationModel extends window.Backbone ) ); - const { preview, activity } = stats; - let previewMessage: MessageModel | undefined; - let activityMessage: MessageModel | undefined; + let { preview, activity } = stats; - // Register the message with MessageCache so that if it already exists + // Get the in-memory message from MessageCache so that if it already exists // in memory we use that data instead of the data from the db which may // be out of date. if (preview) { - previewMessage = window.MessageCache.__DEPRECATED$register( - preview.id, - preview, - 'previewMessage' - ); + const inMemory = window.MessageCache.accessAttributes(preview.id); + preview = inMemory || preview; } if (activity) { - activityMessage = window.MessageCache.__DEPRECATED$register( - activity.id, - activity, - 'activityMessage' - ); + const inMemory = window.MessageCache.accessAttributes(activity.id); + activity = inMemory || activity; } if ( this.hasDraft() && this.get('draftTimestamp') && - (!previewMessage || + (!preview || // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - previewMessage.get('sent_at') < this.get('draftTimestamp')!) + preview.sent_at < this.get('draftTimestamp')!) ) { return; } @@ -4220,38 +4187,37 @@ export class ConversationModel extends window.Backbone let timestamp = this.get('timestamp') || null; let lastMessageReceivedAt = this.get('lastMessageReceivedAt'); let lastMessageReceivedAtMs = this.get('lastMessageReceivedAtMs'); - if (activityMessage) { - const callId = activityMessage.get('callId'); + if (activity) { + const { callId } = activity; const callHistory = callId ? getCallHistorySelector(window.reduxStore.getState())(callId) : undefined; - timestamp = - callHistory?.timestamp || activityMessage.get('sent_at') || timestamp; - lastMessageReceivedAt = - activityMessage.get('received_at') || lastMessageReceivedAt; + timestamp = callHistory?.timestamp || activity.sent_at || timestamp; + lastMessageReceivedAt = activity.received_at || lastMessageReceivedAt; lastMessageReceivedAtMs = - activityMessage.get('received_at_ms') || lastMessageReceivedAtMs; + activity.received_at_ms || lastMessageReceivedAtMs; } - const notificationData = previewMessage?.getNotificationData(); + const notificationData = preview + ? getNotificationDataForMessage(preview) + : undefined; this.set({ lastMessage: - notificationData?.text || previewMessage?.getNotificationText() || '', + notificationData?.text || + (preview ? getNotificationTextForMessage(preview) : undefined) || + '', lastMessageBodyRanges: notificationData?.bodyRanges, lastMessagePrefix: notificationData?.emoji, - lastMessageAuthor: getMessageAuthorText(previewMessage?.attributes), + lastMessageAuthor: getMessageAuthorText(preview), lastMessageStatus: - (previewMessage - ? getMessagePropStatus(previewMessage.attributes, ourConversationId) - : null) || null, + (preview ? getMessagePropStatus(preview, ourConversationId) : null) || + null, lastMessageReceivedAt, lastMessageReceivedAtMs, timestamp, - lastMessageDeletedForEveryone: previewMessage - ? previewMessage.get('deletedForEveryone') - : false, + lastMessageDeletedForEveryone: preview?.deletedForEveryone || false, }); await DataWriter.updateConversation(this.attributes); @@ -4481,7 +4447,7 @@ export class ConversationModel extends window.Backbone fromSync?: boolean; isInitialSync?: boolean; } - ): Promise { + ): Promise { const isSetByOther = providedSource || providedSentAt !== undefined; if (isSignalConversation(this.attributes)) { @@ -4500,7 +4466,7 @@ export class ConversationModel extends window.Backbone createGroupChange: () => this.updateExpirationTimerInGroupV2(providedExpireTimer), }); - return false; + return; } if (!isSetByOther && this.isGroupV1AndDisabled()) { @@ -4512,7 +4478,7 @@ export class ConversationModel extends window.Backbone let expireTimer: DurationInSeconds | undefined = providedExpireTimer; let source = providedSource; if (this.get('left')) { - return false; + return; } if (!expireTimer) { @@ -4522,7 +4488,7 @@ export class ConversationModel extends window.Backbone this.get('expireTimer') === expireTimer || (!expireTimer && !this.get('expireTimer')) ) { - return null; + return; } const logId = @@ -4599,20 +4565,18 @@ export class ConversationModel extends window.Backbone forceSave: true, }); - const message = window.MessageCache.__DEPRECATED$register( + window.MessageCache.__DEPRECATED$register( id, - new window.Whisper.Message(attributes), + attributes, 'updateExpirationTimer' ); - void this.addSingleMessage(message); + void this.addSingleMessage(attributes); void this.updateUnread(); log.info( - `${logId}: added a notification received_at=${message.get('received_at')}` + `${logId}: added a notification received_at=${attributes.received_at}` ); - - return message; } isSealedSenderDisabled(): boolean { @@ -4754,10 +4718,10 @@ export class ConversationModel extends window.Backbone // first/last name in their profile data. const nameChanged = oldName !== newName; if (!isMe(this.attributes) && hadPreviousName && nameChanged) { - const change = { + const change: ProfileNameChangeType = { type: 'name', - oldName, - newName, + oldName: oldName ?? '', + newName: newName ?? '', }; await this.addProfileChange(change); @@ -5247,7 +5211,7 @@ export class ConversationModel extends window.Backbone } async notify( - message: Readonly, + message: Readonly, reaction?: Readonly ): Promise { // As a performance optimization don't perform any work if notifications are @@ -5265,7 +5229,7 @@ export class ConversationModel extends window.Backbone const ourPni = window.textsecure.storage.user.getCheckedPni(); const ourServiceIds: Set = new Set([ourAci, ourPni]); - const mentionsMe = (message.get('bodyRanges') || []).some(bodyRange => { + const mentionsMe = (message.bodyRanges || []).some(bodyRange => { if (!BodyRange.isMention(bodyRange)) { return false; } @@ -5278,7 +5242,7 @@ export class ConversationModel extends window.Backbone } } - if (!isIncoming(message.attributes) && !reaction) { + if (!isIncoming(message) && !reaction) { return; } @@ -5287,7 +5251,7 @@ export class ConversationModel extends window.Backbone const sender = reaction ? window.ConversationController.get(reaction.fromId) - : getAuthor(message.attributes); + : getAuthor(message); const senderName = sender ? sender.getTitle() : window.i18n('icu:unknownContact'); @@ -5300,20 +5264,17 @@ export class ConversationModel extends window.Backbone const { url, absolutePath } = await this.getAvatarOrIdenticon(); - const messageJSON = message.toJSON(); const messageId = message.id; - const isExpiringMessage = Message.hasExpiration(messageJSON); + const isExpiringMessage = hasExpiration(message); notificationService.add({ senderTitle, conversationId, - storyId: isMessageInDirectConversation - ? undefined - : message.get('storyId'), + storyId: isMessageInDirectConversation ? undefined : message.storyId, notificationIconUrl: url, notificationIconAbsolutePath: absolutePath, isExpiringMessage, - message: message.getNotificationText(), + message: getNotificationTextForMessage(message), messageId, reaction: reaction ? { @@ -5322,7 +5283,7 @@ export class ConversationModel extends window.Backbone targetTimestamp: reaction.targetTimestamp, } : undefined, - sentAt: message.get('timestamp'), + sentAt: message.timestamp, type: reaction ? NotificationType.Reaction : NotificationType.Message, }); } diff --git a/ts/models/messages.ts b/ts/models/messages.ts index a62cd01799..e6471d53c2 100644 --- a/ts/models/messages.ts +++ b/ts/models/messages.ts @@ -2126,10 +2126,10 @@ export class MessageModel extends window.Backbone.Model { return; } - conversation.trigger('newmessage', this); + conversation.trigger('newmessage', this.attributes); if (await shouldReplyNotifyUser(this.attributes, conversation)) { - await conversation.notify(this); + await conversation.notify(this.attributes); } // Increment the sent message count if this is an outgoing message @@ -2306,16 +2306,18 @@ export class MessageModel extends window.Backbone.Model { timestamp: reaction.timestamp, }); - const messageToAdd = window.MessageCache.__DEPRECATED$register( + window.MessageCache.__DEPRECATED$register( generatedMessage.id, generatedMessage, 'generatedMessage' ); if (isDirectConversation(targetConversation.attributes)) { - await targetConversation.addSingleMessage(messageToAdd); + await targetConversation.addSingleMessage( + generatedMessage.attributes + ); if (!targetConversation.get('active_at')) { targetConversation.set({ - active_at: messageToAdd.get('timestamp'), + active_at: generatedMessage.attributes.timestamp, }); await DataWriter.updateConversation(targetConversation.attributes); } @@ -2328,11 +2330,11 @@ export class MessageModel extends window.Backbone.Model { ); if ( await shouldReplyNotifyUser( - messageToAdd.attributes, + generatedMessage.attributes, targetConversation ) ) { - drop(targetConversation.notify(messageToAdd)); + drop(targetConversation.notify(generatedMessage.attributes)); } } } @@ -2403,7 +2405,7 @@ export class MessageModel extends window.Backbone.Model { this.set({ reactions }); if (isOutgoing(this.attributes) && isFromSomeoneElse) { - void conversation.notify(this, reaction); + void conversation.notify(this.attributes, reaction); } } } @@ -2465,14 +2467,14 @@ export class MessageModel extends window.Backbone.Model { forceSave: true, }); - void conversation.addSingleMessage( - window.MessageCache.__DEPRECATED$register( - generatedMessage.id, - generatedMessage, - 'generatedMessage2' - ) + window.MessageCache.__DEPRECATED$register( + generatedMessage.id, + generatedMessage, + 'generatedMessage2' ); + void conversation.addSingleMessage(generatedMessage.attributes); + jobData = { type: conversationQueueJobEnum.enum.NormalMessage, conversationId: conversation.id, diff --git a/ts/types/Message.ts b/ts/types/Message.ts index 334896f328..81e25c920a 100644 --- a/ts/types/Message.ts +++ b/ts/types/Message.ts @@ -13,11 +13,9 @@ export function getMentionsRegex(): RegExp { } export type Message = ( - | UserMessage | VerifiedChangeMessage | ProfileChangeNotificationMessage ) & { deletedForEveryone?: boolean }; -export type UserMessage = IncomingMessage | OutgoingMessage; export type IncomingMessage = Readonly< { @@ -109,16 +107,3 @@ export type MessageSchemaVersion6 = Partial< contact: Array; }> >; - -export const isUserMessage = (message: Message): message is UserMessage => - message.type === 'incoming' || message.type === 'outgoing'; - -export const hasExpiration = (message: Message): boolean => { - if (!isUserMessage(message)) { - return false; - } - - const { expireTimer } = message; - - return typeof expireTimer === 'number' && expireTimer > 0; -}; diff --git a/ts/types/Message2.ts b/ts/types/Message2.ts index 27cd8d0eae..bfb0969279 100644 --- a/ts/types/Message2.ts +++ b/ts/types/Message2.ts @@ -46,8 +46,6 @@ import { import { encryptLegacyAttachment } from '../util/encryptLegacyAttachment'; import { deepClone } from '../util/deepClone'; -export { hasExpiration } from './Message'; - export const GROUP = 'group'; export const PRIVATE = 'private'; @@ -1039,3 +1037,16 @@ async function deletePreviews( }) ); } + +export const isUserMessage = (message: MessageAttributesType): boolean => + message.type === 'incoming' || message.type === 'outgoing'; + +export const hasExpiration = (message: MessageAttributesType): boolean => { + if (!isUserMessage(message)) { + return false; + } + + const { expireTimer } = message; + + return typeof expireTimer === 'number' && expireTimer > 0; +}; diff --git a/ts/util/callDisposition.ts b/ts/util/callDisposition.ts index 6dcefadd26..0e75f4bf7a 100644 --- a/ts/util/callDisposition.ts +++ b/ts/util/callDisposition.ts @@ -1153,19 +1153,16 @@ async function saveCallHistory({ callId: callHistory.callId, }; - const id = await DataWriter.saveMessage(message, { + message.id = await DataWriter.saveMessage(message, { ourAci: window.textsecure.storage.user.getCheckedAci(), // We don't want to force save if we're updating an existing message forceSave: prevMessage == null, }); - log.info('saveCallHistory: Saved call history message:', id); + log.info('saveCallHistory: Saved call history message:', message.id); - const model = window.MessageCache.__DEPRECATED$register( - id, - new window.Whisper.Message({ - ...message, - id, - }), + window.MessageCache.__DEPRECATED$register( + message.id, + message, 'callDisposition' ); @@ -1175,7 +1172,7 @@ async function saveCallHistory({ } else { conversation.incrementMessageCount(); } - conversation.trigger('newmessage', model); + conversation.trigger('newmessage', message); } await conversation.updateLastMessage().catch(error => { diff --git a/ts/util/editHelpers.ts b/ts/util/editHelpers.ts index 3e60f3cb70..8bd2a3b537 100644 --- a/ts/util/editHelpers.ts +++ b/ts/util/editHelpers.ts @@ -50,17 +50,20 @@ export function getTargetOfThisEditTimestamp({ return originalTimestamp; } -export function getPropForTimestamp({ +export function getPropForTimestamp< + Attrs extends ReadonlyMessageAttributesType, + T extends keyof EditHistoryType, +>({ log, message, prop, targetTimestamp, }: { log: LoggerType; - message: MessageAttributesType; + message: Attrs; prop: T; targetTimestamp: number; -}): EditHistoryType[T] { +}): Attrs[T] { const logId = `getPropForTimestamp(${targetTimestamp}})`; const { editHistory } = message; @@ -74,7 +77,7 @@ export function getPropForTimestamp({ return message[prop]; } - return targetEdit[prop]; + return targetEdit[prop] as Attrs[T]; } export function getChangesForPropAtTimestamp({ diff --git a/ts/util/hydrateStoryContext.ts b/ts/util/hydrateStoryContext.ts index d7ab7313eb..85f6916ff1 100644 --- a/ts/util/hydrateStoryContext.ts +++ b/ts/util/hydrateStoryContext.ts @@ -19,7 +19,7 @@ export async function hydrateStoryContext( shouldSave?: boolean; isStoryErased?: boolean; } = {} -): Promise { +): Promise | undefined> { let messageAttributes: MessageAttributesType; try { messageAttributes = await window.MessageCache.resolveAttributes( @@ -27,12 +27,12 @@ export async function hydrateStoryContext( messageId ); } catch { - return; + return undefined; } const { storyId } = messageAttributes; if (!storyId) { - return; + return undefined; } const { storyReplyContext: context } = messageAttributes; @@ -42,7 +42,7 @@ export async function hydrateStoryContext( context && (context.attachment?.url || !context.messageId) ) { - return; + return undefined; } let storyMessage: MessageAttributesType | undefined; @@ -88,7 +88,7 @@ export async function hydrateStoryContext( }); } - return; + return newMessageAttributes; } const attachments = getAttachmentsForMessage({ ...storyMessage }); @@ -119,4 +119,5 @@ export async function hydrateStoryContext( skipSaveToDatabase: true, }); } + return newMessageAttributes; } diff --git a/ts/util/modifyTargetMessage.ts b/ts/util/modifyTargetMessage.ts index 124fdf752d..c880533e0a 100644 --- a/ts/util/modifyTargetMessage.ts +++ b/ts/util/modifyTargetMessage.ts @@ -102,7 +102,7 @@ export async function modifyTargetMessage( } if (type === 'outgoing' || (type === 'story' && ourAci === sourceServiceId)) { - const receipts = await MessageReceipts.forMessage(message); + const receipts = await MessageReceipts.forMessage(message.attributes); const sendActions = receipts.map(({ receiptSync }) => { let sendActionType: SendActionType; const receiptType = receiptSync.type; @@ -164,10 +164,10 @@ export async function modifyTargetMessage( if (type === 'incoming') { // In a followup (see DESKTOP-2100), we want to make `ReadSyncs#forMessage` return // an array, not an object. This array wrapping makes that future a bit easier. - const maybeSingleReadSync = await ReadSyncs.forMessage(message); + const maybeSingleReadSync = await ReadSyncs.forMessage(message.attributes); const readSyncs = maybeSingleReadSync ? [maybeSingleReadSync] : []; - const viewSyncs = await ViewSyncs.forMessage(message); + const viewSyncs = await ViewSyncs.forMessage(message.attributes); const isGroupStoryReply = isGroup(conversation.attributes) && message.get('storyId'); @@ -233,13 +233,13 @@ export async function modifyTargetMessage( drop( message .getConversation() - ?.onReadMessage(message, markReadAt, newestSentAt) + ?.onReadMessage(message.attributes, markReadAt, newestSentAt) ); } // Check for out-of-order view once open syncs if (isTapToView(message.attributes)) { - const viewOnceOpenSync = ViewOnceOpenSyncs.forMessage(message); + const viewOnceOpenSync = ViewOnceOpenSyncs.forMessage(message.attributes); if (viewOnceOpenSync) { await message.markViewOnceMessageViewed({ fromSync: true }); changed = true; @@ -248,7 +248,7 @@ export async function modifyTargetMessage( } if (isStory(message.attributes)) { - const viewSyncs = await ViewSyncs.forMessage(message); + const viewSyncs = await ViewSyncs.forMessage(message.attributes); if (viewSyncs.length !== 0) { message.set({ @@ -277,7 +277,7 @@ export async function modifyTargetMessage( } // Does message message have any pending, previously-received associated reactions? - const reactions = Reactions.findReactionsForMessage(message); + const reactions = Reactions.findReactionsForMessage(message.attributes); log.info( `${logId}: Found ${reactions.length} early reaction(s) for ${message.attributes.type} message` diff --git a/ts/util/sendEditedMessage.ts b/ts/util/sendEditedMessage.ts index ed24a161a6..7dcdc940e8 100644 --- a/ts/util/sendEditedMessage.ts +++ b/ts/util/sendEditedMessage.ts @@ -239,7 +239,7 @@ export async function sendEditedMessage( SEND_REPORT_THRESHOLD_MS, async () => { conversation.beforeMessageSend({ - message: targetMessage, + message: targetMessage.attributes, dontClearDraft: false, dontAddMessage: true, now: timestamp, diff --git a/ts/util/sendStoryMessage.ts b/ts/util/sendStoryMessage.ts index 7787d97413..bc324bca2f 100644 --- a/ts/util/sendStoryMessage.ts +++ b/ts/util/sendStoryMessage.ts @@ -307,20 +307,17 @@ export async function sendStoryMessage( // * Save the message model // * Add the message to the conversation await Promise.all( - distributionListMessages.map(messageAttributes => { - const model = new window.Whisper.Message(messageAttributes); - const message = window.MessageCache.__DEPRECATED$register( - model.id, - model, + distributionListMessages.map(message => { + window.MessageCache.__DEPRECATED$register( + message.id, + new window.Whisper.Message(message), 'sendStoryMessage' ); - void ourConversation.addSingleMessage(model, { isJustSent: true }); + void ourConversation.addSingleMessage(message, { isJustSent: true }); - log.info( - `stories.sendStoryMessage: saving message ${messageAttributes.timestamp}` - ); - return DataWriter.saveMessage(message.attributes, { + log.info(`stories.sendStoryMessage: saving message ${message.timestamp}`); + return DataWriter.saveMessage(message, { forceSave: true, ourAci: window.textsecure.storage.user.getCheckedAci(), }); @@ -362,20 +359,21 @@ export async function sendStoryMessage( timestamp: messageAttributes.timestamp, }, async jobToInsert => { - const model = new window.Whisper.Message(messageAttributes); - const message = window.MessageCache.__DEPRECATED$register( - model.id, - model, + window.MessageCache.__DEPRECATED$register( + messageAttributes.id, + new window.Whisper.Message(messageAttributes), 'sendStoryMessage' ); - - const conversation = message.getConversation(); - void conversation?.addSingleMessage(model, { isJustSent: true }); + const conversation = + window.ConversationController.get(conversationId); + void conversation?.addSingleMessage(messageAttributes, { + isJustSent: true, + }); log.info( `stories.sendStoryMessage: saving message ${messageAttributes.timestamp}` ); - await DataWriter.saveMessage(message.attributes, { + await DataWriter.saveMessage(messageAttributes, { forceSave: true, jobToInsert, ourAci: window.textsecure.storage.user.getCheckedAci(),