Update CallLogEvent to latest spec

This commit is contained in:
Jamie Kyle 2024-06-25 17:58:38 -07:00 committed by GitHub
parent 815fd77849
commit fc08e70c0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 366 additions and 142 deletions

View file

@ -157,6 +157,7 @@ import type {
CallHistoryFilter,
CallHistoryGroup,
CallHistoryPagination,
CallLogEventTarget,
} from '../types/CallDisposition';
import {
DirectCallStatus,
@ -166,6 +167,7 @@ import {
CallDirection,
GroupCallStatus,
CallType,
CallStatusValue,
} from '../types/CallDisposition';
import {
callLinkExists,
@ -352,6 +354,7 @@ const dataInterface: ServerInterface = {
getCallHistoryUnreadCount,
markCallHistoryRead,
markAllCallHistoryRead,
markAllCallHistoryReadInConversation,
getCallHistoryMessageByCallId,
getCallHistory,
getCallHistoryGroupsCount,
@ -3631,34 +3634,56 @@ async function getAllCallHistory(): Promise<ReadonlyArray<CallHistoryDetails>> {
}
async function clearCallHistory(
beforeTimestamp: number
): Promise<Array<string>> {
target: CallLogEventTarget
): Promise<ReadonlyArray<string>> {
const db = await getWritableInstance();
return db.transaction(() => {
const whereMessages = sqlFragment`
WHERE messages.type IS 'call-history'
AND messages.sent_at <= ${beforeTimestamp};
const timestamp = getTimestampForCallLogEventTarget(db, target);
const [selectCallIdsQuery, selectCallIdsParams] = sql`
SELECT callsHistory.callId
FROM callsHistory
WHERE
-- Prior calls
(callsHistory.timestamp <= ${timestamp})
-- Unused call links
OR (
callsHistory.mode IS ${CALL_MODE_ADHOC} AND
callsHistory.status IS ${CALL_STATUS_PENDING}
);
`;
const [selectMessagesQuery, selectMessagesParams] = sql`
SELECT id FROM messages ${whereMessages}
`;
const [clearMessagesQuery, clearMessagesParams] = sql`
DELETE FROM messages ${whereMessages}
`;
const callIds = db
.prepare(selectCallIdsQuery)
.pluck()
.all(selectCallIdsParams);
let deletedMessageIds: ReadonlyArray<string> = [];
batchMultiVarQuery(db, callIds, (ids: ReadonlyArray<string>): void => {
const [deleteMessagesQuery, deleteMessagesParams] = sql`
DELETE FROM messages
WHERE messages.type IS 'call-history'
AND messages.callId IN (${sqlJoin(ids)})
RETURNING id;
`;
const batchDeletedMessageIds = db
.prepare(deleteMessagesQuery)
.pluck()
.all(deleteMessagesParams);
deletedMessageIds = deletedMessageIds.concat(batchDeletedMessageIds);
});
const [clearCallsHistoryQuery, clearCallsHistoryParams] = sql`
UPDATE callsHistory
SET
status = ${DirectCallStatus.Deleted},
timestamp = ${Date.now()}
WHERE callsHistory.timestamp <= ${beforeTimestamp};
WHERE callsHistory.timestamp <= ${timestamp};
`;
const messageIds = db
.prepare(selectMessagesQuery)
.pluck()
.all(selectMessagesParams);
db.prepare(clearMessagesQuery).run(clearMessagesParams);
try {
db.prepare(clearCallsHistoryQuery).run(clearCallsHistoryParams);
} catch (error) {
@ -3666,7 +3691,7 @@ async function clearCallHistory(
throw error;
}
return messageIds;
return deletedMessageIds;
})();
}
@ -3743,8 +3768,9 @@ async function getCallHistory(
const SEEN_STATUS_UNSEEN = sqlConstant(SeenStatus.Unseen);
const SEEN_STATUS_SEEN = sqlConstant(SeenStatus.Seen);
const CALL_STATUS_MISSED = sqlConstant(DirectCallStatus.Missed);
const CALL_STATUS_DELETED = sqlConstant(DirectCallStatus.Deleted);
const CALL_STATUS_MISSED = sqlConstant(CallStatusValue.Missed);
const CALL_STATUS_DELETED = sqlConstant(CallStatusValue.Deleted);
const CALL_STATUS_PENDING = sqlConstant(CallStatusValue.Pending);
const CALL_STATUS_INCOMING = sqlConstant(CallDirection.Incoming);
const CALL_MODE_ADHOC = sqlConstant(CallMode.Adhoc);
const FOUR_HOURS_IN_MS = sqlConstant(4 * 60 * 60 * 1000);
@ -3781,44 +3807,88 @@ async function markCallHistoryRead(callId: string): Promise<void> {
db.prepare(query).run(params);
}
async function markAllCallHistoryRead(
beforeTimestamp: number
): Promise<ReadonlyArray<string>> {
const db = await getWritableInstance();
return db.transaction(() => {
const where = sqlFragment`
WHERE messages.type IS 'call-history'
AND messages.seenStatus IS ${SEEN_STATUS_UNSEEN}
AND messages.sent_at <= ${beforeTimestamp};
`;
function getTimestampForCallLogEventTarget(
db: Database,
target: CallLogEventTarget
): number {
let { timestamp } = target;
if (target.peerId != null && target.callId != null) {
const [selectQuery, selectParams] = sql`
SELECT DISTINCT conversationId
FROM messages
${where};
SELECT callsHistory.timestamp
FROM callsHistory
WHERE callsHistory.callId IS ${target.callId}
AND callsHistory.peerId IS ${target.peerId}
`;
const value = db.prepare(selectQuery).pluck().get(selectParams);
const conversationIds = db.prepare(selectQuery).pluck().all(selectParams);
if (value != null) {
timestamp = value;
} else {
log.warn(
'getTimestampForCallLogEventTarget: Target call not found',
target.callId
);
}
}
return timestamp;
}
async function markAllCallHistoryReadWithPredicate(
target: CallLogEventTarget,
inConversation: boolean
) {
const db = await getWritableInstance();
db.transaction(() => {
const jsonPatch = JSON.stringify({
seenStatus: SeenStatus.Seen,
});
const [updateQuery, updateParams] = sql`
UPDATE messages
SET
seenStatus = ${SEEN_STATUS_SEEN},
json = json_patch(json, ${jsonPatch})
${where};
const timestamp = getTimestampForCallLogEventTarget(db, target);
const predicate = inConversation
? sqlFragment`callsHistory.peerId IS ${target.peerId}`
: sqlFragment`TRUE`;
const [selectQuery, selectParams] = sql`
SELECT callsHistory.callId
FROM callsHistory
WHERE ${predicate}
AND callsHistory.timestamp <= ${timestamp}
`;
db.prepare(updateQuery).run(updateParams);
const callIds = db.prepare(selectQuery).pluck().all(selectParams);
return conversationIds;
batchMultiVarQuery(db, callIds, ids => {
const idList = sqlJoin(ids.map(id => sqlFragment`${id}`));
const [updateQuery, updateParams] = sql`
UPDATE messages
SET
seenStatus = ${SEEN_STATUS_SEEN},
json = json_patch(json, ${jsonPatch})
WHERE callId IN (${idList});
`;
db.prepare(updateQuery).run(updateParams);
});
})();
}
async function markAllCallHistoryRead(
target: CallLogEventTarget
): Promise<void> {
await markAllCallHistoryReadWithPredicate(target, false);
}
async function markAllCallHistoryReadInConversation(
target: CallLogEventTarget
): Promise<void> {
strictAssert(target.peerId, 'peerId is required');
await markAllCallHistoryReadWithPredicate(target, true);
}
function getCallHistoryGroupDataSync(
db: Database,
isCount: boolean,
@ -4932,7 +5002,7 @@ async function saveAttachmentBackupJob(
attempts,
data,
lastAttemptTimestamp,
mediaName,
mediaName,
receivedAt,
retryAfter,
type
@ -5003,7 +5073,7 @@ function removeAttachmentBackupJobSync(
): void {
const [query, params] = sql`
DELETE FROM attachment_backup_jobs
WHERE
WHERE
mediaName = ${job.mediaName};
`;