Clean up group story replies

This commit is contained in:
Josh Perez 2022-11-01 14:58:07 -04:00 committed by GitHub
parent 50c48315e3
commit 6700f6fa15
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 94 additions and 28 deletions

View file

@ -3938,9 +3938,20 @@ export class ConversationModel extends window.Backbone
'desktop.mandatoryProfileSharing'
);
await this.maybeApplyUniversalTimer();
let expirationStartTimestamp: number | undefined;
let expireTimer: number | undefined;
const expireTimer = this.get('expireTimer');
// If it's a group story reply then let's match the expiration timers
// with the parent story's expiration.
if (storyId && isGroup(this.attributes)) {
const parentStory = await getMessageById(storyId);
expirationStartTimestamp =
parentStory?.expirationStartTimestamp || Date.now();
expireTimer = parentStory?.expireTimer || durations.DAY;
} else {
await this.maybeApplyUniversalTimer();
expireTimer = this.get('expireTimer');
}
const recipientMaybeConversations = map(
this.getRecipients({
@ -3983,6 +3994,7 @@ export class ConversationModel extends window.Backbone
sent_at: now,
received_at: window.Signal.Util.incrementMessageCounter(),
received_at_ms: now,
expirationStartTimestamp,
expireTimer,
readStatus: ReadStatus.Read,
seenStatus: SeenStatus.NotApplicable,

View file

@ -291,6 +291,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
INITIAL_PROTOCOL_VERSION?: number;
deletingForEveryone?: boolean;
isSelected?: boolean;
private pendingMarkRead?: number;
@ -1694,9 +1696,12 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
attributesToUpdate.sendStateByConversationId = sendStateByConversationId;
attributesToUpdate.expirationStartTimestamp = sentToAtLeastOneRecipient
? Date.now()
: undefined;
// Only update the expirationStartTimestamp if we don't already have one set
if (!this.get('expirationStartTimestamp')) {
attributesToUpdate.expirationStartTimestamp = sentToAtLeastOneRecipient
? Date.now()
: undefined;
}
attributesToUpdate.unidentifiedDeliveries = union(
previousUnidentifiedDeliveries,
newUnidentifiedDeliveries
@ -2525,6 +2530,9 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
const dataMessage = await upgradeMessageSchema(withQuoteReference);
const isGroupStoryReply =
isGroup(conversation.attributes) && dataMessage.storyId;
try {
const now = new Date().getTime();
@ -2747,6 +2755,17 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
conversation.set(attributes);
// Sync group story reply expiration timers with the parent story's
// expiration timer
if (isGroupStoryReply && storyQuote) {
message.set({
expireTimer: storyQuote.get('expireTimer'),
expirationStartTimestamp: storyQuote.get(
'expirationStartTimestamp'
),
});
}
if (
dataMessage.expireTimer &&
!isExpirationTimerUpdate(dataMessage)
@ -2848,8 +2867,6 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
const conversationTimestamp = conversation.get('timestamp');
const isGroupStoryReply =
isGroup(conversation.attributes) && message.get('storyId');
if (
!isStory(message.attributes) &&
!isGroupStoryReply &&
@ -3401,17 +3418,23 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
deleteServerTimestamp: del.get('serverTimestamp'),
});
// Remove any notifications for this message
notificationService.removeBy({ messageId: this.get('id') });
try {
this.deletingForEveryone = true;
// Erase the contents of this message
await this.eraseContents(
{ deletedForEveryone: true, reactions: [] },
shouldPersist
);
// Remove any notifications for this message
notificationService.removeBy({ messageId: this.get('id') });
// Update the conversation's last message in case this was the last message
this.getConversation()?.updateLastMessage();
// Erase the contents of this message
await this.eraseContents(
{ deletedForEveryone: true, reactions: [] },
shouldPersist
);
// Update the conversation's last message in case this was the last message
this.getConversation()?.updateLastMessage();
} finally {
this.deletingForEveryone = undefined;
}
}
clearNotifications(reaction: Partial<ReactionType> = {}): void {

View file

@ -20,17 +20,19 @@ export async function cleanupMessage(
await deleteMessageData(message);
if (
isStory(message) &&
isDirectConversation(parentConversation?.attributes)
) {
await fixupStoryReplies(conversationId, id);
const isGroupConversation = Boolean(
parentConversation && !isDirectConversation(parentConversation.attributes)
);
if (isStory(message)) {
await cleanupStoryReplies(conversationId, id, isGroupConversation);
}
}
async function fixupStoryReplies(
async function cleanupStoryReplies(
conversationId: string,
storyId: string,
isGroupConversation: boolean,
pagination?: {
messageId: string;
receivedAt: number;
@ -42,6 +44,7 @@ async function fixupStoryReplies(
conversationId,
{
includeStoryReplies: false,
messageId,
receivedAt,
storyId,
}
@ -59,13 +62,27 @@ async function fixupStoryReplies(
return;
}
replies.forEach(reply => {
const model = window.MessageController.register(reply.id, reply);
model.unset('storyReplyContext');
model.hydrateStoryContext(null);
});
if (isGroupConversation) {
// Cleanup all group replies
await Promise.all(
replies.map(reply => {
const replyMessageModel = window.MessageController.register(
reply.id,
reply
);
return replyMessageModel.eraseContents();
})
);
} else {
// Refresh the storyReplyContext data for 1:1 conversations
replies.forEach(reply => {
const model = window.MessageController.register(reply.id, reply);
model.unset('storyReplyContext');
model.hydrateStoryContext(null);
});
}
return fixupStoryReplies(conversationId, storyId, {
return cleanupStoryReplies(conversationId, storyId, isGroupConversation, {
messageId: lastMessageId,
receivedAt: lastReceivedAt,
});
@ -76,6 +93,16 @@ export async function deleteMessageData(
): Promise<void> {
await window.Signal.Migrations.deleteExternalMessageFiles(message);
if (isStory(message)) {
const { id, conversationId } = message;
const parentConversation =
window.ConversationController.get(conversationId);
const isGroupConversation = Boolean(
parentConversation && !isDirectConversation(parentConversation.attributes)
);
await cleanupStoryReplies(conversationId, id, isGroupConversation);
}
const { sticker } = message;
if (!sticker) {
return;

View file

@ -12,6 +12,10 @@ export async function deleteForEveryone(
doe: DeleteModel,
shouldPersist = true
): Promise<void> {
if (message.deletingForEveryone || message.get('deletedForEveryone')) {
return;
}
if (isDeletionByMe(message, doe)) {
await message.handleDeleteForEveryone(doe, shouldPersist);
return;