New 'unseenStatus' field for certain secondary message types
This commit is contained in:
parent
ed9f54d7d6
commit
3a1df01c9e
23 changed files with 610 additions and 143 deletions
|
@ -50,8 +50,8 @@ export type MessageMetricsType = {
|
|||
export type ConversationMetricsType = {
|
||||
oldest?: MessageMetricsType;
|
||||
newest?: MessageMetricsType;
|
||||
oldestUnread?: MessageMetricsType;
|
||||
totalUnread: number;
|
||||
oldestUnseen?: MessageMetricsType;
|
||||
totalUnseen: number;
|
||||
};
|
||||
export type ConversationType = ConversationAttributesType;
|
||||
export type EmojiType = {
|
||||
|
|
|
@ -110,6 +110,7 @@ import type {
|
|||
UnprocessedType,
|
||||
UnprocessedUpdateType,
|
||||
} from './Interface';
|
||||
import { SeenStatus } from '../MessageSeenStatus';
|
||||
|
||||
type ConversationRow = Readonly<{
|
||||
json: string;
|
||||
|
@ -1737,6 +1738,20 @@ function saveMessageSync(
|
|||
expireTimer,
|
||||
expirationStartTimestamp,
|
||||
} = data;
|
||||
let { seenStatus } = data;
|
||||
|
||||
if (readStatus === ReadStatus.Unread && seenStatus !== SeenStatus.Unseen) {
|
||||
log.warn(
|
||||
`saveMessage: Message ${id}/${type} is unread but had seenStatus=${seenStatus}. Forcing to UnseenStatus.Unseen.`
|
||||
);
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
data = {
|
||||
...data,
|
||||
seenStatus: SeenStatus.Unseen,
|
||||
};
|
||||
seenStatus = SeenStatus.Unseen;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
id,
|
||||
|
@ -1762,6 +1777,7 @@ function saveMessageSync(
|
|||
storyId: storyId || null,
|
||||
type: type || null,
|
||||
readStatus: readStatus ?? null,
|
||||
seenStatus: seenStatus ?? SeenStatus.NotApplicable,
|
||||
};
|
||||
|
||||
if (id && !forceSave) {
|
||||
|
@ -1791,7 +1807,8 @@ function saveMessageSync(
|
|||
sourceDevice = $sourceDevice,
|
||||
storyId = $storyId,
|
||||
type = $type,
|
||||
readStatus = $readStatus
|
||||
readStatus = $readStatus,
|
||||
seenStatus = $seenStatus
|
||||
WHERE id = $id;
|
||||
`
|
||||
).run(payload);
|
||||
|
@ -1834,7 +1851,8 @@ function saveMessageSync(
|
|||
sourceDevice,
|
||||
storyId,
|
||||
type,
|
||||
readStatus
|
||||
readStatus,
|
||||
seenStatus
|
||||
) values (
|
||||
$id,
|
||||
$json,
|
||||
|
@ -1858,7 +1876,8 @@ function saveMessageSync(
|
|||
$sourceDevice,
|
||||
$storyId,
|
||||
$type,
|
||||
$readStatus
|
||||
$readStatus,
|
||||
$seenStatus
|
||||
);
|
||||
`
|
||||
).run({
|
||||
|
@ -2110,16 +2129,21 @@ async function getUnreadByConversationAndMarkRead({
|
|||
UPDATE messages
|
||||
SET
|
||||
readStatus = ${ReadStatus.Read},
|
||||
seenStatus = ${SeenStatus.Seen},
|
||||
json = json_patch(json, $jsonPatch)
|
||||
WHERE
|
||||
readStatus = ${ReadStatus.Unread} AND
|
||||
conversationId = $conversationId AND
|
||||
seenStatus = ${SeenStatus.Unseen} AND
|
||||
isStory = 0 AND
|
||||
(${_storyIdPredicate(storyId, isGroup)}) AND
|
||||
received_at <= $newestUnreadAt;
|
||||
`
|
||||
).run({
|
||||
conversationId,
|
||||
jsonPatch: JSON.stringify({ readStatus: ReadStatus.Read }),
|
||||
jsonPatch: JSON.stringify({
|
||||
readStatus: ReadStatus.Read,
|
||||
seenStatus: SeenStatus.Seen,
|
||||
}),
|
||||
newestUnreadAt,
|
||||
storyId: storyId || null,
|
||||
});
|
||||
|
@ -2644,7 +2668,7 @@ async function getLastConversationMessage({
|
|||
return jsonToObject(row.json);
|
||||
}
|
||||
|
||||
function getOldestUnreadMessageForConversation(
|
||||
function getOldestUnseenMessageForConversation(
|
||||
conversationId: string,
|
||||
storyId?: UUIDStringType,
|
||||
isGroup?: boolean
|
||||
|
@ -2655,7 +2679,7 @@ function getOldestUnreadMessageForConversation(
|
|||
`
|
||||
SELECT * FROM messages WHERE
|
||||
conversationId = $conversationId AND
|
||||
readStatus = ${ReadStatus.Unread} AND
|
||||
seenStatus = ${SeenStatus.Unseen} AND
|
||||
isStory IS 0 AND
|
||||
(${_storyIdPredicate(storyId, isGroup)})
|
||||
ORDER BY received_at ASC, sent_at ASC
|
||||
|
@ -2709,6 +2733,35 @@ function getTotalUnreadForConversationSync(
|
|||
|
||||
return row['count(id)'];
|
||||
}
|
||||
function getTotalUnseenForConversationSync(
|
||||
conversationId: string,
|
||||
storyId?: UUIDStringType,
|
||||
isGroup?: boolean
|
||||
): number {
|
||||
const db = getInstance();
|
||||
const row = db
|
||||
.prepare<Query>(
|
||||
`
|
||||
SELECT count(id)
|
||||
FROM messages
|
||||
WHERE
|
||||
conversationId = $conversationId AND
|
||||
seenStatus = ${SeenStatus.Unseen} AND
|
||||
isStory IS 0 AND
|
||||
(${_storyIdPredicate(storyId, isGroup)})
|
||||
`
|
||||
)
|
||||
.get({
|
||||
conversationId,
|
||||
storyId: storyId || null,
|
||||
});
|
||||
|
||||
if (!row) {
|
||||
throw new Error('getTotalUnseenForConversationSync: Unable to get count');
|
||||
}
|
||||
|
||||
return row['count(id)'];
|
||||
}
|
||||
|
||||
async function getMessageMetricsForConversation(
|
||||
conversationId: string,
|
||||
|
@ -2732,12 +2785,12 @@ function getMessageMetricsForConversationSync(
|
|||
storyId,
|
||||
isGroup
|
||||
);
|
||||
const oldestUnread = getOldestUnreadMessageForConversation(
|
||||
const oldestUnseen = getOldestUnseenMessageForConversation(
|
||||
conversationId,
|
||||
storyId,
|
||||
isGroup
|
||||
);
|
||||
const totalUnread = getTotalUnreadForConversationSync(
|
||||
const totalUnseen = getTotalUnseenForConversationSync(
|
||||
conversationId,
|
||||
storyId,
|
||||
isGroup
|
||||
|
@ -2746,10 +2799,10 @@ function getMessageMetricsForConversationSync(
|
|||
return {
|
||||
oldest: oldest ? pick(oldest, ['received_at', 'sent_at', 'id']) : undefined,
|
||||
newest: newest ? pick(newest, ['received_at', 'sent_at', 'id']) : undefined,
|
||||
oldestUnread: oldestUnread
|
||||
? pick(oldestUnread, ['received_at', 'sent_at', 'id'])
|
||||
oldestUnseen: oldestUnseen
|
||||
? pick(oldestUnseen, ['received_at', 'sent_at', 'id'])
|
||||
: undefined,
|
||||
totalUnread,
|
||||
totalUnseen,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
88
ts/sql/migrations/56-add-unseen-to-message.ts
Normal file
88
ts/sql/migrations/56-add-unseen-to-message.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { Database } from 'better-sqlite3';
|
||||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
import { SeenStatus } from '../../MessageSeenStatus';
|
||||
|
||||
import type { LoggerType } from '../../types/Logging';
|
||||
|
||||
export default function updateToSchemaVersion56(
|
||||
currentVersion: number,
|
||||
db: Database,
|
||||
logger: LoggerType
|
||||
): void {
|
||||
if (currentVersion >= 56) {
|
||||
return;
|
||||
}
|
||||
|
||||
db.transaction(() => {
|
||||
db.exec(
|
||||
`
|
||||
--- Add column to messages table
|
||||
|
||||
ALTER TABLE messages ADD COLUMN seenStatus NUMBER default 0;
|
||||
|
||||
--- Add index to make searching on this field easy
|
||||
|
||||
CREATE INDEX messages_unseen_no_story ON messages
|
||||
(conversationId, seenStatus, isStory, received_at, sent_at)
|
||||
WHERE
|
||||
seenStatus IS NOT NULL;
|
||||
|
||||
CREATE INDEX messages_unseen_with_story ON messages
|
||||
(conversationId, seenStatus, isStory, storyId, received_at, sent_at)
|
||||
WHERE
|
||||
seenStatus IS NOT NULL;
|
||||
|
||||
--- Update seenStatus to UnseenStatus.Unseen for certain messages
|
||||
--- (NULL included because 'timer-notification' in 1:1 convos had type = NULL)
|
||||
|
||||
UPDATE messages
|
||||
SET
|
||||
seenStatus = ${SeenStatus.Unseen}
|
||||
WHERE
|
||||
readStatus = ${ReadStatus.Unread} AND
|
||||
(
|
||||
type IS NULL
|
||||
OR
|
||||
type IN (
|
||||
'call-history',
|
||||
'change-number-notification',
|
||||
'chat-session-refreshed',
|
||||
'delivery-issue',
|
||||
'group',
|
||||
'incoming',
|
||||
'keychange',
|
||||
'timer-notification',
|
||||
'verified-change'
|
||||
)
|
||||
);
|
||||
|
||||
--- Set readStatus to ReadStatus.Read for all other message types
|
||||
|
||||
UPDATE messages
|
||||
SET
|
||||
readStatus = ${ReadStatus.Read}
|
||||
WHERE
|
||||
readStatus = ${ReadStatus.Unread} AND
|
||||
type IS NOT NULL AND
|
||||
type NOT IN (
|
||||
'call-history',
|
||||
'change-number-notification',
|
||||
'chat-session-refreshed',
|
||||
'delivery-issue',
|
||||
'group',
|
||||
'incoming',
|
||||
'keychange',
|
||||
'timer-notification',
|
||||
'verified-change'
|
||||
);
|
||||
`
|
||||
);
|
||||
|
||||
db.pragma('user_version = 56');
|
||||
})();
|
||||
|
||||
logger.info('updateToSchemaVersion56: success!');
|
||||
}
|
|
@ -31,6 +31,7 @@ import updateToSchemaVersion52 from './52-optimize-stories';
|
|||
import updateToSchemaVersion53 from './53-gv2-banned-members';
|
||||
import updateToSchemaVersion54 from './54-unprocessed-received-at-counter';
|
||||
import updateToSchemaVersion55 from './55-report-message-aci';
|
||||
import updateToSchemaVersion56 from './56-add-unseen-to-message';
|
||||
|
||||
function updateToSchemaVersion1(
|
||||
currentVersion: number,
|
||||
|
@ -1925,6 +1926,7 @@ export const SCHEMA_VERSIONS = [
|
|||
updateToSchemaVersion53,
|
||||
updateToSchemaVersion54,
|
||||
updateToSchemaVersion55,
|
||||
updateToSchemaVersion56,
|
||||
];
|
||||
|
||||
export function updateSchema(db: Database, logger: LoggerType): void {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue