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