Support for local deletes synced to all your devices
This commit is contained in:
parent
06f71a7ef8
commit
11eb1782a7
39 changed files with 2094 additions and 72 deletions
|
@ -165,6 +165,12 @@ import OS from '../util/os/osMain';
|
|||
import { getMessageAuthorText } from '../util/getMessageAuthorText';
|
||||
import { downscaleOutgoingAttachment } from '../util/attachments';
|
||||
import { MessageRequestResponseEvent } from '../types/MessageRequestResponseEvent';
|
||||
import type { MessageToDelete } from '../textsecure/messageReceiverEvents';
|
||||
import {
|
||||
getConversationToDelete,
|
||||
getMessageToDelete,
|
||||
} from '../util/deleteForMe';
|
||||
import { isEnabled } from '../RemoteConfig';
|
||||
import { getCallHistorySelector } from '../state/selectors/callHistory';
|
||||
|
||||
/* eslint-disable more/no-then */
|
||||
|
@ -186,6 +192,7 @@ const {
|
|||
getOlderMessagesByConversation,
|
||||
getMessageMetricsForConversation,
|
||||
getMessageById,
|
||||
getMostRecentAddressableMessages,
|
||||
getNewerMessagesByConversation,
|
||||
} = window.Signal.Data;
|
||||
|
||||
|
@ -2234,7 +2241,7 @@ export class ConversationModel extends window.Backbone
|
|||
}
|
||||
|
||||
if (isDelete) {
|
||||
await this.destroyMessages();
|
||||
await this.destroyMessages({ source: 'message-request' });
|
||||
void this.updateLastMessage();
|
||||
}
|
||||
|
||||
|
@ -4449,7 +4456,6 @@ export class ConversationModel extends window.Backbone
|
|||
source: providedSource,
|
||||
fromSync = false,
|
||||
isInitialSync = false,
|
||||
fromGroupUpdate = false,
|
||||
}: {
|
||||
reason: string;
|
||||
receivedAt?: number;
|
||||
|
@ -4458,7 +4464,6 @@ export class ConversationModel extends window.Backbone
|
|||
source?: string;
|
||||
fromSync?: boolean;
|
||||
isInitialSync?: boolean;
|
||||
fromGroupUpdate?: boolean;
|
||||
}
|
||||
): Promise<boolean | null | MessageModel | void> {
|
||||
const isSetByOther = providedSource || providedSentAt !== undefined;
|
||||
|
@ -4554,7 +4559,7 @@ export class ConversationModel extends window.Backbone
|
|||
(isInitialSync && isFromSyncOperation) || isFromMe || isNoteToSelf;
|
||||
|
||||
const id = generateGuid();
|
||||
const model = new window.Whisper.Message({
|
||||
const attributes = {
|
||||
id,
|
||||
conversationId: this.id,
|
||||
expirationTimerUpdate: {
|
||||
|
@ -4562,7 +4567,6 @@ export class ConversationModel extends window.Backbone
|
|||
source,
|
||||
sourceServiceId,
|
||||
fromSync,
|
||||
fromGroupUpdate,
|
||||
},
|
||||
flags: Proto.DataMessage.Flags.EXPIRATION_TIMER_UPDATE,
|
||||
readStatus: shouldBeRead ? ReadStatus.Read : ReadStatus.Unread,
|
||||
|
@ -4570,18 +4574,18 @@ export class ConversationModel extends window.Backbone
|
|||
received_at: receivedAt ?? incrementMessageCounter(),
|
||||
seenStatus: shouldBeRead ? SeenStatus.Seen : SeenStatus.Unseen,
|
||||
sent_at: sentAt,
|
||||
type: 'timer-notification',
|
||||
// TODO: DESKTOP-722
|
||||
} as unknown as MessageAttributesType);
|
||||
timestamp: sentAt,
|
||||
type: 'timer-notification' as const,
|
||||
};
|
||||
|
||||
await window.Signal.Data.saveMessage(model.attributes, {
|
||||
await window.Signal.Data.saveMessage(attributes, {
|
||||
ourAci: window.textsecure.storage.user.getCheckedAci(),
|
||||
forceSave: true,
|
||||
});
|
||||
|
||||
const message = window.MessageCache.__DEPRECATED$register(
|
||||
id,
|
||||
model,
|
||||
new window.Whisper.Message(attributes),
|
||||
'updateExpirationTimer'
|
||||
);
|
||||
|
||||
|
@ -4589,7 +4593,7 @@ export class ConversationModel extends window.Backbone
|
|||
void this.updateUnread();
|
||||
|
||||
log.info(
|
||||
`${logId}: added a notification received_at=${model.get('received_at')}`
|
||||
`${logId}: added a notification received_at=${message.get('received_at')}`
|
||||
);
|
||||
|
||||
return message;
|
||||
|
@ -4978,7 +4982,29 @@ export class ConversationModel extends window.Backbone
|
|||
this.contactCollection!.reset(members);
|
||||
}
|
||||
|
||||
async destroyMessages(): Promise<void> {
|
||||
async destroyMessages({
|
||||
source,
|
||||
}: {
|
||||
source: 'message-request' | 'local-delete-sync' | 'local-delete';
|
||||
}): Promise<void> {
|
||||
const logId = `destroyMessages(${this.idForLogging()})/${source}`;
|
||||
|
||||
log.info(`${logId}: Queuing job on conversation`);
|
||||
|
||||
await this.queueJob(logId, async () => {
|
||||
log.info(`${logId}: Starting...`);
|
||||
|
||||
await this.destroyMessagesInner({ logId, source });
|
||||
});
|
||||
}
|
||||
|
||||
async destroyMessagesInner({
|
||||
logId,
|
||||
source,
|
||||
}: {
|
||||
logId: string;
|
||||
source: 'message-request' | 'local-delete-sync' | 'local-delete';
|
||||
}): Promise<void> {
|
||||
this.set({
|
||||
lastMessage: null,
|
||||
lastMessageAuthor: null,
|
||||
|
@ -4988,9 +5014,50 @@ export class ConversationModel extends window.Backbone
|
|||
});
|
||||
window.Signal.Data.updateConversation(this.attributes);
|
||||
|
||||
await window.Signal.Data.removeAllMessagesInConversation(this.id, {
|
||||
if (source === 'local-delete' && isEnabled('desktop.deleteSync.send')) {
|
||||
log.info(`${logId}: Preparing sync message`);
|
||||
const timestamp = Date.now();
|
||||
|
||||
const addressableMessages = await getMostRecentAddressableMessages(
|
||||
this.id
|
||||
);
|
||||
const mostRecentMessages: Array<MessageToDelete> = addressableMessages
|
||||
.map(getMessageToDelete)
|
||||
.filter(isNotNil)
|
||||
.slice(0, 5);
|
||||
|
||||
if (mostRecentMessages.length > 0) {
|
||||
await singleProtoJobQueue.add(
|
||||
MessageSender.getDeleteForMeSyncMessage([
|
||||
{
|
||||
type: 'delete-conversation',
|
||||
conversation: getConversationToDelete(this.attributes),
|
||||
isFullDelete: true,
|
||||
mostRecentMessages,
|
||||
timestamp,
|
||||
},
|
||||
])
|
||||
);
|
||||
} else {
|
||||
await singleProtoJobQueue.add(
|
||||
MessageSender.getDeleteForMeSyncMessage([
|
||||
{
|
||||
type: 'delete-local-conversation',
|
||||
conversation: getConversationToDelete(this.attributes),
|
||||
timestamp,
|
||||
},
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
log.info(`${logId}: Sync message queue complete`);
|
||||
}
|
||||
|
||||
log.info(`${logId}: Starting delete`);
|
||||
await window.Signal.Data.removeMessagesInConversation(this.id, {
|
||||
logId: this.idForLogging(),
|
||||
});
|
||||
log.info(`${logId}: Delete complete`);
|
||||
}
|
||||
|
||||
getTitle(options?: { isShort?: boolean }): string {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue