Quotes: Check message's conversationId
This commit is contained in:
parent
97a4361c6f
commit
7d55421d8f
3 changed files with 111 additions and 58 deletions
24
ts/model-types.d.ts
vendored
24
ts/model-types.d.ts
vendored
|
@ -52,6 +52,18 @@ export type GroupMigrationType = {
|
||||||
invitedMembers: Array<GroupV2PendingMemberType>;
|
invitedMembers: Array<GroupV2PendingMemberType>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type QuotedMessageType = {
|
||||||
|
attachments: Array<typeof window.WhatIsThis>;
|
||||||
|
// `author` is an old attribute that holds the author's E164. We shouldn't use it for
|
||||||
|
// new messages, but old messages might have this attribute.
|
||||||
|
author?: string;
|
||||||
|
authorUuid: string;
|
||||||
|
bodyRanges: BodyRangesType;
|
||||||
|
id: string;
|
||||||
|
referencedMessageNotFound: boolean;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type MessageAttributesType = {
|
export type MessageAttributesType = {
|
||||||
bodyPending: boolean;
|
bodyPending: boolean;
|
||||||
bodyRanges: BodyRangesType;
|
bodyRanges: BodyRangesType;
|
||||||
|
@ -86,17 +98,7 @@ export type MessageAttributesType = {
|
||||||
message: unknown;
|
message: unknown;
|
||||||
messageTimer: unknown;
|
messageTimer: unknown;
|
||||||
profileChange: ProfileNameChangeType;
|
profileChange: ProfileNameChangeType;
|
||||||
quote?: {
|
quote?: QuotedMessageType;
|
||||||
attachments: Array<typeof window.WhatIsThis>;
|
|
||||||
// `author` is an old attribute that holds the author's E164. We shouldn't use it for
|
|
||||||
// new messages, but old messages might have this attribute.
|
|
||||||
author?: string;
|
|
||||||
authorUuid: string;
|
|
||||||
bodyRanges: BodyRangesType;
|
|
||||||
id: string;
|
|
||||||
referencedMessageNotFound: boolean;
|
|
||||||
text: string;
|
|
||||||
};
|
|
||||||
reactions?: Array<{
|
reactions?: Array<{
|
||||||
emoji: string;
|
emoji: string;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import {
|
import {
|
||||||
WhatIsThis,
|
|
||||||
MessageAttributesType,
|
|
||||||
CustomError,
|
CustomError,
|
||||||
|
MessageAttributesType,
|
||||||
|
QuotedMessageType,
|
||||||
|
WhatIsThis,
|
||||||
} from '../model-types.d';
|
} from '../model-types.d';
|
||||||
import { DataMessageClass } from '../textsecure.d';
|
import { DataMessageClass } from '../textsecure.d';
|
||||||
import { ConversationModel } from './conversations';
|
import { ConversationModel } from './conversations';
|
||||||
|
@ -44,6 +45,7 @@ import {
|
||||||
} from '../util/callingNotification';
|
} from '../util/callingNotification';
|
||||||
import { PropsType as ProfileChangeNotificationPropsType } from '../components/conversation/ProfileChangeNotification';
|
import { PropsType as ProfileChangeNotificationPropsType } from '../components/conversation/ProfileChangeNotification';
|
||||||
import { AttachmentType, isImage, isVideo } from '../types/Attachment';
|
import { AttachmentType, isImage, isVideo } from '../types/Attachment';
|
||||||
|
import { MIMEType } from '../types/MIME';
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
/* eslint-disable more/no-then */
|
/* eslint-disable more/no-then */
|
||||||
|
@ -1114,10 +1116,10 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
||||||
)
|
)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
let reallyNotFound = referencedMessageNotFound;
|
let foundReference = !referencedMessageNotFound;
|
||||||
// Is the quote really without a reference? Check with our in memory store
|
// Is the quote really without a reference? Check with our in memory store
|
||||||
// first to make sure it's not there.
|
// first to make sure it's not there.
|
||||||
if (referencedMessageNotFound) {
|
if (referencedMessageNotFound && contact) {
|
||||||
const messageId = this.get('sent_at');
|
const messageId = this.get('sent_at');
|
||||||
window.log.info(
|
window.log.info(
|
||||||
`getPropsForQuote: Verifying that ${messageId} referencing ${sentAt} is really not found`
|
`getPropsForQuote: Verifying that ${messageId} referencing ${sentAt} is really not found`
|
||||||
|
@ -1125,11 +1127,20 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
||||||
const inMemoryMessage = window.MessageController.findBySentAt(
|
const inMemoryMessage = window.MessageController.findBySentAt(
|
||||||
Number(sentAt)
|
Number(sentAt)
|
||||||
);
|
);
|
||||||
reallyNotFound = !inMemoryMessage;
|
if (
|
||||||
|
this.isQuoteAMatch(inMemoryMessage, this.get('conversationId'), quote)
|
||||||
|
) {
|
||||||
|
foundReference = true;
|
||||||
|
this.set({
|
||||||
|
quote: {
|
||||||
|
...quote,
|
||||||
|
referencedMessageNotFound: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchDataAndUpdate = async () => {
|
||||||
|
await this.copyQuoteContentFromOriginal(inMemoryMessage, quote);
|
||||||
|
|
||||||
// We found the quote in memory so update the message in the database
|
|
||||||
// so we don't have to do this check again
|
|
||||||
if (!reallyNotFound) {
|
|
||||||
window.log.info(
|
window.log.info(
|
||||||
`getPropsForQuote: Found ${sentAt}, scheduling an update to ${messageId}`
|
`getPropsForQuote: Found ${sentAt}, scheduling an update to ${messageId}`
|
||||||
);
|
);
|
||||||
|
@ -1140,6 +1151,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
window.Signal.Util.queueUpdateMessage(this.attributes);
|
window.Signal.Util.queueUpdateMessage(this.attributes);
|
||||||
|
};
|
||||||
|
fetchDataAndUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,7 +1203,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
||||||
rawAttachment: firstAttachment
|
rawAttachment: firstAttachment
|
||||||
? this.processQuoteAttachment(firstAttachment)
|
? this.processQuoteAttachment(firstAttachment)
|
||||||
: undefined,
|
: undefined,
|
||||||
referencedMessageNotFound: reallyNotFound,
|
referencedMessageNotFound: !foundReference,
|
||||||
sentAt: Number(sentAt),
|
sentAt: Number(sentAt),
|
||||||
text: this.createNonBreakingLastSeparator(text),
|
text: this.createNonBreakingLastSeparator(text),
|
||||||
};
|
};
|
||||||
|
@ -2999,37 +3012,30 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
async copyFromQuotedMessage(message: WhatIsThis): Promise<boolean> {
|
async copyFromQuotedMessage(
|
||||||
|
message: DataMessageClass,
|
||||||
|
conversationId: string
|
||||||
|
): Promise<DataMessageClass> {
|
||||||
const { quote } = message;
|
const { quote } = message;
|
||||||
if (!quote) {
|
if (!quote) {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { attachments, id, author, authorUuid } = quote;
|
const { id } = quote;
|
||||||
const firstAttachment = attachments[0];
|
|
||||||
const authorConversationId = window.ConversationController.ensureContactIds(
|
|
||||||
{
|
|
||||||
e164: author,
|
|
||||||
uuid: authorUuid,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const inMemoryMessage = window.MessageController.findBySentAt(id);
|
const inMemoryMessage = window.MessageController.findBySentAt(id);
|
||||||
|
|
||||||
let queryMessage;
|
let queryMessage;
|
||||||
|
|
||||||
if (inMemoryMessage) {
|
if (this.isQuoteAMatch(inMemoryMessage, conversationId, quote)) {
|
||||||
queryMessage = inMemoryMessage;
|
queryMessage = inMemoryMessage;
|
||||||
} else {
|
} else {
|
||||||
window.log.info('copyFromQuotedMessage: db lookup needed', id);
|
window.log.info('copyFromQuotedMessage: db lookup needed', id);
|
||||||
const collection = await window.Signal.Data.getMessagesBySentAt(id, {
|
const collection = await window.Signal.Data.getMessagesBySentAt(id, {
|
||||||
MessageCollection: window.Whisper.MessageCollection,
|
MessageCollection: window.Whisper.MessageCollection,
|
||||||
});
|
});
|
||||||
const found = collection.find(item => {
|
const found = collection.find(item =>
|
||||||
const messageAuthorId = item.getContactId();
|
this.isQuoteAMatch(item, conversationId, quote)
|
||||||
|
);
|
||||||
return authorConversationId === messageAuthorId;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
quote.referencedMessageNotFound = true;
|
quote.referencedMessageNotFound = true;
|
||||||
|
@ -3039,39 +3045,82 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
||||||
queryMessage = window.MessageController.register(found.id, found);
|
queryMessage = window.MessageController.register(found.id, found);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queryMessage.isTapToView()) {
|
await this.copyQuoteContentFromOriginal(queryMessage, quote);
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
isQuoteAMatch(
|
||||||
|
message: MessageModel | null | undefined,
|
||||||
|
conversationId: string,
|
||||||
|
quote: QuotedMessageType | DataMessageClass.Quote
|
||||||
|
): message is MessageModel {
|
||||||
|
const { authorUuid, id } = quote;
|
||||||
|
const authorConversationId = window.ConversationController.ensureContactIds(
|
||||||
|
{
|
||||||
|
e164: 'author' in quote ? quote.author : undefined,
|
||||||
|
uuid: authorUuid,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return Boolean(
|
||||||
|
message &&
|
||||||
|
message.get('sent_at') === id &&
|
||||||
|
message.get('conversationId') === conversationId &&
|
||||||
|
message.getContactId() === authorConversationId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
async copyQuoteContentFromOriginal(
|
||||||
|
originalMessage: MessageModel,
|
||||||
|
quote: QuotedMessageType | DataMessageClass.Quote
|
||||||
|
): Promise<void> {
|
||||||
|
const { attachments } = quote;
|
||||||
|
const firstAttachment = attachments ? attachments[0] : undefined;
|
||||||
|
|
||||||
|
if (originalMessage.isTapToView()) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
quote.text = null;
|
quote.text = null;
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
quote.attachments = [
|
quote.attachments = [
|
||||||
{
|
{
|
||||||
contentType: 'image/jpeg',
|
contentType: 'image/jpeg',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return message;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
quote.text = queryMessage.get('body');
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
quote.text = originalMessage.get('body');
|
||||||
if (firstAttachment) {
|
if (firstAttachment) {
|
||||||
firstAttachment.thumbnail = null;
|
firstAttachment.thumbnail = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!firstAttachment ||
|
!firstAttachment ||
|
||||||
(!GoogleChrome.isImageTypeSupported(firstAttachment.contentType) &&
|
!firstAttachment.contentType ||
|
||||||
!GoogleChrome.isVideoTypeSupported(firstAttachment.contentType))
|
(!GoogleChrome.isImageTypeSupported(
|
||||||
|
firstAttachment.contentType as MIMEType
|
||||||
|
) &&
|
||||||
|
!GoogleChrome.isVideoTypeSupported(
|
||||||
|
firstAttachment.contentType as MIMEType
|
||||||
|
))
|
||||||
) {
|
) {
|
||||||
return message;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (
|
if (
|
||||||
queryMessage.get('schemaVersion') <
|
originalMessage.get('schemaVersion') <
|
||||||
TypedMessage.VERSION_NEEDED_FOR_DISPLAY
|
TypedMessage.VERSION_NEEDED_FOR_DISPLAY
|
||||||
) {
|
) {
|
||||||
const upgradedMessage = await upgradeMessageSchema(
|
const upgradedMessage = await upgradeMessageSchema(
|
||||||
queryMessage.attributes
|
originalMessage.attributes
|
||||||
);
|
);
|
||||||
queryMessage.set(upgradedMessage);
|
originalMessage.set(upgradedMessage);
|
||||||
await window.Signal.Data.saveMessage(upgradedMessage, {
|
await window.Signal.Data.saveMessage(upgradedMessage, {
|
||||||
Message: window.Whisper.Message,
|
Message: window.Whisper.Message,
|
||||||
});
|
});
|
||||||
|
@ -3081,10 +3130,10 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
||||||
'Problem upgrading message quoted message from database',
|
'Problem upgrading message quoted message from database',
|
||||||
Errors.toLogFormat(error)
|
Errors.toLogFormat(error)
|
||||||
);
|
);
|
||||||
return message;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryAttachments = queryMessage.get('attachments') || [];
|
const queryAttachments = originalMessage.get('attachments') || [];
|
||||||
if (queryAttachments.length > 0) {
|
if (queryAttachments.length > 0) {
|
||||||
const queryFirst = queryAttachments[0];
|
const queryFirst = queryAttachments[0];
|
||||||
const { thumbnail } = queryFirst;
|
const { thumbnail } = queryFirst;
|
||||||
|
@ -3097,7 +3146,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const queryPreview = queryMessage.get('preview') || [];
|
const queryPreview = originalMessage.get('preview') || [];
|
||||||
if (queryPreview.length > 0) {
|
if (queryPreview.length > 0) {
|
||||||
const queryFirst = queryPreview[0];
|
const queryFirst = queryPreview[0];
|
||||||
const { image } = queryFirst;
|
const { image } = queryFirst;
|
||||||
|
@ -3110,15 +3159,13 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sticker = queryMessage.get('sticker');
|
const sticker = originalMessage.get('sticker');
|
||||||
if (sticker && sticker.data && sticker.data.path) {
|
if (sticker && sticker.data && sticker.data.path) {
|
||||||
firstAttachment.thumbnail = {
|
firstAttachment.thumbnail = {
|
||||||
...sticker.data,
|
...sticker.data,
|
||||||
copied: true,
|
copied: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDataMessage(
|
handleDataMessage(
|
||||||
|
@ -3366,7 +3413,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const withQuoteReference = await this.copyFromQuotedMessage(
|
const withQuoteReference = await this.copyFromQuotedMessage(
|
||||||
initialMessage
|
initialMessage,
|
||||||
|
conversation.id
|
||||||
);
|
);
|
||||||
const dataMessage = await upgradeMessageSchema(withQuoteReference);
|
const dataMessage = await upgradeMessageSchema(withQuoteReference);
|
||||||
|
|
||||||
|
|
3
ts/textsecure.d.ts
vendored
3
ts/textsecure.d.ts
vendored
|
@ -725,6 +725,9 @@ export declare namespace DataMessageClass {
|
||||||
text: string | null;
|
text: string | null;
|
||||||
attachments?: Array<DataMessageClass.Quote.QuotedAttachment>;
|
attachments?: Array<DataMessageClass.Quote.QuotedAttachment>;
|
||||||
bodyRanges?: Array<DataMessageClass.BodyRange>;
|
bodyRanges?: Array<DataMessageClass.BodyRange>;
|
||||||
|
|
||||||
|
// Added later during processing
|
||||||
|
referencedMessageNotFound?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BodyRange {
|
class BodyRange {
|
||||||
|
|
Loading…
Reference in a new issue