Fix call history deletion from sync messages

This commit is contained in:
Jamie Kyle 2023-09-27 12:42:30 -07:00 committed by GitHub
parent 20ddca9684
commit 1cc478180e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 84 additions and 11 deletions

View file

@ -8,6 +8,7 @@ import { strictAssert } from '../util/assert';
let callsHistoryData: ReadonlyArray<CallHistoryDetails>;
export async function loadCallsHistory(): Promise<void> {
await dataInterface.cleanupCallHistoryMessages();
callsHistoryData = await dataInterface.getAllCallHistory();
}

View file

@ -630,6 +630,7 @@ export type DataInterface = {
}): Promise<MessageType | undefined>;
getAllCallHistory: () => Promise<ReadonlyArray<CallHistoryDetails>>;
clearCallHistory: (beforeTimestamp: number) => Promise<Array<string>>;
cleanupCallHistoryMessages: () => Promise<void>;
getCallHistoryUnreadCount(): Promise<number>;
markCallHistoryRead(callId: string): Promise<void>;
markAllCallHistoryRead(): Promise<ReadonlyArray<string>>;

View file

@ -305,6 +305,7 @@ const dataInterface: ServerInterface = {
getLastConversationMessage,
getAllCallHistory,
clearCallHistory,
cleanupCallHistoryMessages,
getCallHistoryUnreadCount,
markCallHistoryRead,
markAllCallHistoryRead,
@ -3294,6 +3295,24 @@ async function clearCallHistory(
})();
}
async function cleanupCallHistoryMessages(): Promise<void> {
const db = getInstance();
return db
.transaction(() => {
const [query, params] = sql`
DELETE FROM messages
WHERE messages.id IN (
SELECT messages.id FROM messages
LEFT JOIN callsHistory ON callsHistory.callId IS messages.callId
WHERE messages.type IS 'call-history'
AND callsHistory.status IS ${CALL_STATUS_DELETED}
)
`;
db.prepare(query).run(params);
})
.immediate();
}
async function getCallHistoryMessageByCallId(options: {
conversationId: string;
callId: string;

View file

@ -3,6 +3,7 @@
import type { ReadonlyDeep } from 'type-fest';
import type { ThunkAction } from 'redux-thunk';
import { omit } from 'lodash';
import type { StateType as RootStateType } from '../reducer';
import { clearCallHistoryDataAndSync } from '../../util/callDisposition';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
@ -22,15 +23,21 @@ export type CallHistoryState = ReadonlyDeep<{
callHistoryByCallId: Record<string, CallHistoryDetails>;
}>;
const CALL_HISTORY_CACHE = 'callHistory/CACHE';
const CALL_HISTORY_ADD = 'callHistory/ADD';
const CALL_HISTORY_REMOVE = 'callHistory/REMOVE';
const CALL_HISTORY_RESET = 'callHistory/RESET';
const CALL_HISTORY_UPDATE_UNREAD = 'callHistory/UPDATE_UNREAD';
export type CallHistoryCache = ReadonlyDeep<{
type: typeof CALL_HISTORY_CACHE;
export type CallHistoryAdd = ReadonlyDeep<{
type: typeof CALL_HISTORY_ADD;
payload: CallHistoryDetails;
}>;
export type CallHistoryRemove = ReadonlyDeep<{
type: typeof CALL_HISTORY_REMOVE;
payload: CallHistoryDetails['callId'];
}>;
export type CallHistoryReset = ReadonlyDeep<{
type: typeof CALL_HISTORY_RESET;
}>;
@ -41,7 +48,10 @@ export type CallHistoryUpdateUnread = ReadonlyDeep<{
}>;
export type CallHistoryAction = ReadonlyDeep<
CallHistoryCache | CallHistoryReset | CallHistoryUpdateUnread
| CallHistoryAdd
| CallHistoryRemove
| CallHistoryReset
| CallHistoryUpdateUnread
>;
export function getEmptyState(): CallHistoryState {
@ -113,13 +123,26 @@ function markCallsTabViewed(): ThunkAction<
};
}
function cacheCallHistory(callHistory: CallHistoryDetails): CallHistoryCache {
function addCallHistory(callHistory: CallHistoryDetails): CallHistoryAdd {
return {
type: CALL_HISTORY_CACHE,
type: CALL_HISTORY_ADD,
payload: callHistory,
};
}
function removeCallHistory(
callId: CallHistoryDetails['callId']
): CallHistoryRemove {
return {
type: CALL_HISTORY_REMOVE,
payload: callId,
};
}
function resetCallHistory(): CallHistoryReset {
return { type: CALL_HISTORY_RESET };
}
function clearAllCallHistory(): ThunkAction<
void,
RootStateType,
@ -134,14 +157,16 @@ function clearAllCallHistory(): ThunkAction<
log.error('Error clearing call history', Errors.toLogFormat(error));
} finally {
// Just force a reset, even if the clear failed.
dispatch({ type: CALL_HISTORY_RESET });
dispatch(resetCallHistory());
dispatch(updateCallHistoryUnreadCount());
}
};
}
export const actions = {
cacheCallHistory,
addCallHistory,
removeCallHistory,
resetCallHistory,
clearAllCallHistory,
updateCallHistoryUnreadCount,
markCallHistoryRead,
@ -159,7 +184,7 @@ export function reducer(
switch (action.type) {
case CALL_HISTORY_RESET:
return { ...state, edition: state.edition + 1, callHistoryByCallId: {} };
case CALL_HISTORY_CACHE:
case CALL_HISTORY_ADD:
return {
...state,
callHistoryByCallId: {
@ -167,6 +192,11 @@ export function reducer(
[action.payload.callId]: action.payload,
},
};
case CALL_HISTORY_REMOVE:
return {
...state,
callHistoryByCallId: omit(state.callHistoryByCallId, action.payload),
};
case CALL_HISTORY_UPDATE_UNREAD:
return {
...state,

View file

@ -785,8 +785,18 @@ async function updateLocalCallHistory(
'updateLocalCallHistory: Saving call history:',
formatCallHistory(callHistory)
);
const isDeleted =
callHistory.status === DirectCallStatus.Deleted ||
callHistory.status === GroupCallStatus.Deleted;
await window.Signal.Data.saveCallHistory(callHistory);
window.reduxActions.callHistory.cacheCallHistory(callHistory);
if (isDeleted) {
window.reduxActions.callHistory.removeCallHistory(callHistory.callId);
} else {
window.reduxActions.callHistory.addCallHistory(callHistory);
}
const prevMessage =
await window.Signal.Data.getCallHistoryMessageByCallId({
@ -806,6 +816,13 @@ async function updateLocalCallHistory(
);
}
if (isDeleted) {
if (prevMessage != null) {
await window.Signal.Data.removeMessage(prevMessage.id);
}
return callHistory;
}
let unread = false;
if (callHistory.mode === CallMode.Direct) {
unread =

View file

@ -18,7 +18,12 @@ export async function onCallLogEventSync(
if (event === CallLogEvent.Clear) {
log.info(`onCallLogEventSync: Clearing call history before ${timestamp}`);
await window.Signal.Data.clearCallHistory(timestamp);
try {
await window.Signal.Data.clearCallHistory(timestamp);
} finally {
// We want to reset the call history even if the clear fails.
window.reduxActions.callHistory.resetCallHistory();
}
confirm();
} else {
throw missingCaseError(event);