Fix call log sync when call isnt latest message

This commit is contained in:
Jamie
2026-06-25 11:59:48 -07:00
committed by GitHub
parent bb958be177
commit 1da25e6ddd
5 changed files with 54 additions and 56 deletions
+4 -5
View File
@@ -1003,6 +1003,10 @@ type ReadableInterface = {
conversationId: string,
eraId: string
) => boolean;
getPrevUnreadCallIdInConversation: (
conversationId: string,
receivedAt: number
) => string | null;
callLinkExists: (roomId: string) => boolean;
defunctCallLinkExists: (roomId: string) => boolean;
getAllCallLinks: () => ReadonlyArray<CallLinkType>;
@@ -1232,11 +1236,6 @@ type WritableInterface = {
readAt?: number;
storyId?: string;
}) => GetUnreadByConversationAndMarkReadResultType;
getUnreadCallMessagesAndMarkRead: (options: {
conversationId: string;
readMessageReceivedAt: number;
activeCallIds: Set<string>;
}) => GetUnreadByConversationAndMarkReadResultType;
getUnreadEditedMessagesAndMarkRead: (options: {
conversationId: string;
readMessageReceivedAt: number;
+22 -35
View File
@@ -493,6 +493,7 @@ export const DataReader: ServerReadableInterface = {
getCallHistoryGroupsCount,
getCallHistoryGroups,
hasGroupCallHistoryMessage,
getPrevUnreadCallIdInConversation,
hasMedia,
getSortedMedia,
@@ -647,7 +648,6 @@ export const DataWriter: ServerWritableInterface = {
updateAllConversationColors,
removeAllProfileKeyCredentials,
getUnreadByConversationAndMarkRead,
getUnreadCallMessagesAndMarkRead,
getUnreadEditedMessagesAndMarkRead,
getUnreadReactionsAndMarkRead,
getUnreadPollVotesAndMarkRead,
@@ -5496,6 +5496,27 @@ function hasGroupCallHistoryMessage(
return exists === 1;
}
function getPrevUnreadCallIdInConversation(
db: ReadableDB,
conversationId: string,
receivedAt: number
): string | null {
const [query, params] = sql`
SELECT messages.callId FROM messages
INNER JOIN callsHistory ON callsHistory.callId = messages.callId
WHERE messages.conversationId = ${conversationId}
AND messages.type IS 'call-history'
AND messages.seenStatus IS ${SEEN_STATUS_UNSEEN}
AND callsHistory.direction IS ${CALL_STATUS_INCOMING}
AND messages.received_at <= ${receivedAt}
ORDER BY messages.received_at DESC, messages.sent_at DESC
LIMIT 1
`;
const callId = db.prepare(query, { pluck: true }).get<string>(params);
return callId ?? null;
}
function hasMedia(db: ReadableDB, conversationId: string): boolean {
return db.transaction(() => {
let hasAttachments: boolean;
@@ -9513,40 +9534,6 @@ function _getAllEditedMessages(
.all({});
}
function getUnreadCallMessagesAndMarkRead(
db: WritableDB,
{
conversationId,
readMessageReceivedAt,
activeCallIds,
}: {
conversationId: string;
readMessageReceivedAt: number;
activeCallIds: Set<string>;
}
): GetUnreadByConversationAndMarkReadResultType {
const [query, params] = sql`
UPDATE messages
SET
expirationStartTimestamp = ${readMessageReceivedAt}
WHERE type IS 'call-history'
AND messages.conversationId IS ${conversationId}
AND messages.seenStatus IS ${SEEN_STATUS_SEEN}
AND messages.received_at <= ${readMessageReceivedAt}
AND messages.hasExpireTimer IS 1
AND messages.expirationStartTimestamp IS NULL
AND messages.callId NOT IN (${sqlJoin(Array.from(activeCallIds))})
RETURNING *
`;
const rows = db.prepare(query).all<MessageTypeUnhydrated>(params);
const messages = hydrateMessages(db, rows);
return messages.map(message => {
return { ...message, originalReadStatus: undefined };
});
}
function getUnreadEditedMessagesAndMarkRead(
db: WritableDB,
{
+1
View File
@@ -292,6 +292,7 @@ export const actions = {
clearAllCallHistory,
updateCallHistoryUnreadCount,
markCallHistoryRead,
markCallHistoryReadInConversation,
markCallsTabViewed,
};
@@ -274,6 +274,7 @@ describe('calling/callHistoryExpiration', function (this: Mocha.Suite) {
describe('1:1 calls', () => {
it('expire missed call: read by opening chat', async () => {
const { phone } = bootstrap;
const page = await app.getWindow();
const chatListItem = $chatListItem(page, contact.device.aci);
const unreadBadge = $unreadBadge(page, contact.device.aci);
@@ -312,6 +313,17 @@ describe('calling/callHistoryExpiration', function (this: Mocha.Suite) {
await expect($navTabUnreadBadge(page, 'Calls')).not.toBeVisible();
await expect($missedCall(page)).toBeVisible();
debug('waiting for sync message');
const syncMessage = await phone.waitForSyncMessage(entry => {
return (
entry.syncMessage.content?.callLogEvent?.type ===
Proto.SyncMessage.CallLogEvent.Type.MARKED_AS_READ_IN_CONVERSATION
);
});
expect(syncMessage.syncMessage.content?.callLogEvent?.callId).toBe(
BigInt(callTimestamp)
);
debug('waiting for message to expire');
await delay(EXPIRE_TIMER_MS);
await expect($missedCall(page)).not.toBeVisible();
+15 -16
View File
@@ -4,7 +4,7 @@
import lodash from 'lodash';
import type { ConversationAttributesType } from '../model-types.d.ts';
import { DataWriter } from '../sql/Client.preload.ts';
import { DataReader, DataWriter } from '../sql/Client.preload.ts';
import { hasErrors } from '../state/selectors/message.preload.ts';
import { readSyncJobQueue } from '../jobs/readSyncJobQueue.preload.ts';
import { notificationService } from '../services/notifications.preload.ts';
@@ -28,7 +28,6 @@ import { isAciString } from './isAciString.std.ts';
import type { MessageModel } from '../models/messages.preload.ts';
import { postSaveUpdates } from './cleanup.preload.ts';
import { itemStorage } from '../textsecure/Storage.preload.ts';
import { calling } from '../services/calling.preload.ts';
const { isNumber, pick } = lodash;
@@ -48,10 +47,10 @@ export async function markConversationRead(
const [
unreadMessages,
unreadCallMessages,
unreadEditedMessages,
unreadReactions,
unreadPollVotes,
lastUnreadCallId,
] = await Promise.all([
DataWriter.getUnreadByConversationAndMarkRead({
conversationId,
@@ -59,11 +58,6 @@ export async function markConversationRead(
readAt: options.readAt,
includeStoryReplies: !isGroup(conversationAttrs),
}),
DataWriter.getUnreadCallMessagesAndMarkRead({
conversationId,
readMessageReceivedAt: readMessage.received_at,
activeCallIds: calling.getActiveCallIds(),
}),
DataWriter.getUnreadEditedMessagesAndMarkRead({
conversationId,
readMessageReceivedAt: readMessage.received_at,
@@ -76,6 +70,10 @@ export async function markConversationRead(
conversationId,
readMessageReceivedAt: readMessage.received_at,
}),
DataReader.getPrevUnreadCallIdInConversation(
conversationId,
readMessage.received_at
),
]);
const convoId = getConversationIdForLogging(conversationAttrs);
@@ -87,7 +85,6 @@ export async function markConversationRead(
receivedAt: readMessage.received_at,
},
unreadMessages: unreadMessages.length,
unreadCallMessages: unreadCallMessages.length,
unreadEditedMessages: unreadEditedMessages.length,
unreadReactions: unreadReactions.length,
unreadPollVotes: unreadPollVotes.length,
@@ -95,10 +92,10 @@ export async function markConversationRead(
if (
!unreadMessages.length &&
!unreadCallMessages.length &&
!unreadEditedMessages.length &&
!unreadReactions.length &&
!unreadPollVotes.length
!unreadPollVotes.length &&
lastUnreadCallId == null
) {
return false;
}
@@ -148,11 +145,7 @@ export async function markConversationRead(
});
});
const allUnreadMessages = [
...unreadMessages,
...unreadCallMessages,
...unreadEditedMessages,
];
const allUnreadMessages = [...unreadMessages, ...unreadEditedMessages];
const updatedMessages: Array<MessageModel> = [];
@@ -274,6 +267,12 @@ export async function markConversationRead(
}
}
if (lastUnreadCallId != null) {
window.reduxActions.callHistory.markCallHistoryReadInConversation(
lastUnreadCallId
);
}
updateExpiringMessagesService();
tapToViewMessagesDeletionService.update();