Re-enable reaction notifications and improve message modifier typing

This commit is contained in:
Scott Nonnenberg 2022-01-04 07:27:16 -08:00 committed by GitHub
parent 14861aff50
commit 54e252ecc2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 120 additions and 40 deletions

View file

@ -20,6 +20,7 @@ import {
import type { import type {
MessageAttributesType, MessageAttributesType,
ConversationAttributesType, ConversationAttributesType,
ReactionAttributesType,
} from './model-types.d'; } from './model-types.d';
import * as Bytes from './Bytes'; import * as Bytes from './Bytes';
import * as Timers from './Timers'; import * as Timers from './Timers';
@ -107,6 +108,12 @@ import { Reactions } from './messageModifiers/Reactions';
import { ReadSyncs } from './messageModifiers/ReadSyncs'; import { ReadSyncs } from './messageModifiers/ReadSyncs';
import { ViewSyncs } from './messageModifiers/ViewSyncs'; import { ViewSyncs } from './messageModifiers/ViewSyncs';
import { ViewOnceOpenSyncs } from './messageModifiers/ViewOnceOpenSyncs'; import { ViewOnceOpenSyncs } from './messageModifiers/ViewOnceOpenSyncs';
import type { DeleteAttributesType } from './messageModifiers/Deletes';
import type { MessageReceiptAttributesType } from './messageModifiers/MessageReceipts';
import type { MessageRequestAttributesType } from './messageModifiers/MessageRequests';
import type { ReadSyncAttributesType } from './messageModifiers/ReadSyncs';
import type { ViewSyncAttributesType } from './messageModifiers/ViewSyncs';
import type { ViewOnceOpenSyncAttributesType } from './messageModifiers/ViewOnceOpenSyncs';
import { ReadStatus } from './messages/MessageReadStatus'; import { ReadStatus } from './messages/MessageReadStatus';
import type { SendStateByConversationId } from './messages/MessageSendState'; import type { SendStateByConversationId } from './messages/MessageSendState';
import { SendStatus } from './messages/MessageSendState'; import { SendStatus } from './messages/MessageSendState';
@ -120,8 +127,8 @@ import { onRetryRequest, onDecryptionError } from './util/handleRetry';
import { themeChanged } from './shims/themeChanged'; import { themeChanged } from './shims/themeChanged';
import { createIPCEvents } from './util/createIPCEvents'; import { createIPCEvents } from './util/createIPCEvents';
import { RemoveAllConfiguration } from './types/RemoveAllConfiguration'; import { RemoveAllConfiguration } from './types/RemoveAllConfiguration';
import { isValidUuid, UUIDKind } from './types/UUID';
import type { UUID } from './types/UUID'; import type { UUID } from './types/UUID';
import { UUIDKind } from './types/UUID';
import * as log from './logging/log'; import * as log from './logging/log';
import { import {
loadRecentEmojis, loadRecentEmojis,
@ -136,6 +143,7 @@ import { showToast } from './util/showToast';
import { startInteractionMode } from './windows/startInteractionMode'; import { startInteractionMode } from './windows/startInteractionMode';
import { deliveryReceiptsJobQueue } from './jobs/deliveryReceiptsJobQueue'; import { deliveryReceiptsJobQueue } from './jobs/deliveryReceiptsJobQueue';
import { updateOurUsername } from './util/updateOurUsername'; import { updateOurUsername } from './util/updateOurUsername';
import { ReactionSource } from './reactions/ReactionSource';
const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000; const MAX_ATTACHMENT_DOWNLOAD_AGE = 3600 * 72 * 1000;
@ -2878,18 +2886,27 @@ export async function startApp(): Promise<void> {
return Promise.resolve(); return Promise.resolve();
} }
strictAssert(
reaction.targetTimestamp,
'Reaction without targetTimestamp'
);
const fromId = window.ConversationController.ensureContactIds({
e164: data.source,
uuid: data.sourceUuid,
});
strictAssert(fromId, 'Reaction without fromId');
log.info('Queuing incoming reaction for', reaction.targetTimestamp); log.info('Queuing incoming reaction for', reaction.targetTimestamp);
const reactionModel = Reactions.getSingleton().add({ const attributes: ReactionAttributesType = {
emoji: reaction.emoji, emoji: reaction.emoji,
remove: reaction.remove, remove: reaction.remove,
targetAuthorUuid, targetAuthorUuid,
targetTimestamp: reaction.targetTimestamp, targetTimestamp: reaction.targetTimestamp,
timestamp, timestamp,
fromId: window.ConversationController.ensureContactIds({ fromId,
e164: data.source, source: ReactionSource.FromSomeoneElse,
uuid: data.sourceUuid, };
}), const reactionModel = Reactions.getSingleton().add(attributes);
});
// Note: We do not wait for completion here // Note: We do not wait for completion here
Reactions.getSingleton().onReaction(reactionModel); Reactions.getSingleton().onReaction(reactionModel);
confirm(); confirm();
@ -2899,16 +2916,28 @@ export async function startApp(): Promise<void> {
if (data.message.delete) { if (data.message.delete) {
const { delete: del } = data.message; const { delete: del } = data.message;
log.info('Queuing incoming DOE for', del.targetSentTimestamp); log.info('Queuing incoming DOE for', del.targetSentTimestamp);
const deleteModel = Deletes.getSingleton().add({
strictAssert(
del.targetSentTimestamp,
'Delete missing targetSentTimestamp'
);
strictAssert(data.serverTimestamp, 'Delete missing serverTimestamp');
const fromId = window.ConversationController.ensureContactIds({
e164: data.source,
uuid: data.sourceUuid,
});
strictAssert(fromId, 'Delete missing fromId');
const attributes: DeleteAttributesType = {
targetSentTimestamp: del.targetSentTimestamp, targetSentTimestamp: del.targetSentTimestamp,
serverTimestamp: data.serverTimestamp, serverTimestamp: data.serverTimestamp,
fromId: window.ConversationController.ensureContactIds({ fromId,
e164: data.source, };
uuid: data.sourceUuid, const deleteModel = Deletes.getSingleton().add(attributes);
}),
});
// Note: We do not wait for completion here // Note: We do not wait for completion here
Deletes.getSingleton().onDelete(deleteModel); Deletes.getSingleton().onDelete(deleteModel);
confirm(); confirm();
return Promise.resolve(); return Promise.resolve();
} }
@ -3218,6 +3247,10 @@ export async function startApp(): Promise<void> {
); );
const { reaction, timestamp } = data.message; const { reaction, timestamp } = data.message;
strictAssert(
reaction.targetTimestamp,
'Reaction without targetAuthorUuid'
);
if (!isValidReactionEmoji(reaction.emoji)) { if (!isValidReactionEmoji(reaction.emoji)) {
log.warn('Received an invalid reaction emoji. Dropping it'); log.warn('Received an invalid reaction emoji. Dropping it');
@ -3226,15 +3259,16 @@ export async function startApp(): Promise<void> {
} }
log.info('Queuing sent reaction for', reaction.targetTimestamp); log.info('Queuing sent reaction for', reaction.targetTimestamp);
const reactionModel = Reactions.getSingleton().add({ const attributes: ReactionAttributesType = {
emoji: reaction.emoji, emoji: reaction.emoji,
remove: reaction.remove, remove: reaction.remove,
targetAuthorUuid, targetAuthorUuid,
targetTimestamp: reaction.targetTimestamp, targetTimestamp: reaction.targetTimestamp,
timestamp, timestamp,
fromId: window.ConversationController.getOurConversationId(), fromId: window.ConversationController.getOurConversationIdOrThrow(),
fromSync: true, source: ReactionSource.FromSync,
}); };
const reactionModel = Reactions.getSingleton().add(attributes);
// Note: We do not wait for completion here // Note: We do not wait for completion here
Reactions.getSingleton().onReaction(reactionModel); Reactions.getSingleton().onReaction(reactionModel);
@ -3244,12 +3278,20 @@ export async function startApp(): Promise<void> {
if (data.message.delete) { if (data.message.delete) {
const { delete: del } = data.message; const { delete: del } = data.message;
strictAssert(
del.targetSentTimestamp,
'Delete without targetSentTimestamp'
);
strictAssert(data.serverTimestamp, 'Data has no serverTimestamp');
log.info('Queuing sent DOE for', del.targetSentTimestamp); log.info('Queuing sent DOE for', del.targetSentTimestamp);
const deleteModel = Deletes.getSingleton().add({
const attributes: DeleteAttributesType = {
targetSentTimestamp: del.targetSentTimestamp, targetSentTimestamp: del.targetSentTimestamp,
serverTimestamp: data.serverTimestamp, serverTimestamp: data.serverTimestamp,
fromId: window.ConversationController.getOurConversationId(), fromId: window.ConversationController.getOurConversationIdOrThrow(),
}); };
const deleteModel = Deletes.getSingleton().add(attributes);
// Note: We do not wait for completion here // Note: We do not wait for completion here
Deletes.getSingleton().onDelete(deleteModel); Deletes.getSingleton().onDelete(deleteModel);
confirm(); confirm();
@ -3425,12 +3467,16 @@ export async function startApp(): Promise<void> {
const { source, sourceUuid, timestamp } = ev; const { source, sourceUuid, timestamp } = ev;
log.info(`view once open sync ${source} ${timestamp}`); log.info(`view once open sync ${source} ${timestamp}`);
strictAssert(source, 'ViewOnceOpen without source');
strictAssert(sourceUuid, 'ViewOnceOpen without sourceUuid');
strictAssert(timestamp, 'ViewOnceOpen without timestamp');
const sync = ViewOnceOpenSyncs.getSingleton().add({ const attributes: ViewOnceOpenSyncAttributesType = {
source, source,
sourceUuid, sourceUuid,
timestamp, timestamp,
}); };
const sync = ViewOnceOpenSyncs.getSingleton().add(attributes);
ViewOnceOpenSyncs.getSingleton().onSync(sync); ViewOnceOpenSyncs.getSingleton().onSync(sync);
} }
@ -3501,13 +3547,19 @@ export async function startApp(): Promise<void> {
messageRequestResponseType, messageRequestResponseType,
}); });
const sync = MessageRequests.getSingleton().add({ strictAssert(
messageRequestResponseType,
'onMessageRequestResponse: missing type'
);
const attributes: MessageRequestAttributesType = {
threadE164, threadE164,
threadUuid, threadUuid,
groupId, groupId,
groupV2Id, groupV2Id,
type: messageRequestResponseType, type: messageRequestResponseType,
}); };
const sync = MessageRequests.getSingleton().add(attributes);
MessageRequests.getSingleton().onResponse(sync); MessageRequests.getSingleton().onResponse(sync);
} }
@ -3563,14 +3615,21 @@ export async function startApp(): Promise<void> {
return; return;
} }
const receipt = MessageReceipts.getSingleton().add({ strictAssert(
isValidUuid(sourceUuid),
'onReadOrViewReceipt: Missing sourceUuid'
);
strictAssert(sourceDevice, 'onReadOrViewReceipt: Missing sourceDevice');
const attributes: MessageReceiptAttributesType = {
messageSentAt: timestamp, messageSentAt: timestamp,
receiptTimestamp: envelopeTimestamp, receiptTimestamp: envelopeTimestamp,
sourceConversationId, sourceConversationId,
sourceUuid, sourceUuid,
sourceDevice, sourceDevice,
type, type,
}); };
const receipt = MessageReceipts.getSingleton().add(attributes);
// Note: We do not wait for completion here // Note: We do not wait for completion here
MessageReceipts.getSingleton().onReceipt(receipt); MessageReceipts.getSingleton().onReceipt(receipt);
@ -3594,13 +3653,18 @@ export async function startApp(): Promise<void> {
timestamp timestamp
); );
const receipt = ReadSyncs.getSingleton().add({ strictAssert(senderId, 'onReadSync missing senderId');
strictAssert(senderUuid, 'onReadSync missing senderUuid');
strictAssert(timestamp, 'onReadSync missing timestamp');
const attributes: ReadSyncAttributesType = {
senderId, senderId,
sender, sender,
senderUuid, senderUuid,
timestamp, timestamp,
readAt, readAt,
}); };
const receipt = ReadSyncs.getSingleton().add(attributes);
receipt.on('remove', ev.confirm); receipt.on('remove', ev.confirm);
@ -3626,13 +3690,18 @@ export async function startApp(): Promise<void> {
timestamp timestamp
); );
const receipt = ViewSyncs.getSingleton().add({ strictAssert(senderId, 'onViewSync missing senderId');
strictAssert(senderUuid, 'onViewSync missing senderUuid');
strictAssert(timestamp, 'onViewSync missing timestamp');
const attributes: ViewSyncAttributesType = {
senderId, senderId,
senderE164, senderE164,
senderUuid, senderUuid,
timestamp, timestamp,
viewedAt: envelopeTimestamp, viewedAt: envelopeTimestamp,
}); };
const receipt = ViewSyncs.getSingleton().add(attributes);
receipt.on('remove', ev.confirm); receipt.on('remove', ev.confirm);
@ -3742,14 +3811,25 @@ export async function startApp(): Promise<void> {
return; return;
} }
const receipt = MessageReceipts.getSingleton().add({ strictAssert(
envelopeTimestamp,
'onDeliveryReceipt: missing envelopeTimestamp'
);
strictAssert(
isValidUuid(sourceUuid),
'onDeliveryReceipt: missing valid sourceUuid'
);
strictAssert(sourceDevice, 'onDeliveryReceipt: missing sourceDevice');
const attributes: MessageReceiptAttributesType = {
messageSentAt: timestamp, messageSentAt: timestamp,
receiptTimestamp: envelopeTimestamp, receiptTimestamp: envelopeTimestamp,
sourceConversationId, sourceConversationId,
sourceUuid, sourceUuid,
sourceDevice, sourceDevice,
type: MessageReceiptType.Delivery, type: MessageReceiptType.Delivery,
}); };
const receipt = MessageReceipts.getSingleton().add(attributes);
// Note: We don't wait for completion here // Note: We don't wait for completion here
MessageReceipts.getSingleton().onReceipt(receipt); MessageReceipts.getSingleton().onReceipt(receipt);

View file

@ -8,7 +8,7 @@ import type { MessageModel } from '../models/messages';
import { getContactId } from '../messages/helpers'; import { getContactId } from '../messages/helpers';
import * as log from '../logging/log'; import * as log from '../logging/log';
type DeleteAttributesType = { export type DeleteAttributesType = {
targetSentTimestamp: number; targetSentTimestamp: number;
serverTimestamp: number; serverTimestamp: number;
fromId: string; fromId: string;

View file

@ -32,7 +32,7 @@ export enum MessageReceiptType {
View = 'View', View = 'View',
} }
type MessageReceiptAttributesType = { export type MessageReceiptAttributesType = {
messageSentAt: number; messageSentAt: number;
receiptTimestamp: number; receiptTimestamp: number;
sourceUuid: UUIDStringType; sourceUuid: UUIDStringType;

View file

@ -7,7 +7,7 @@ import { Collection, Model } from 'backbone';
import type { ConversationModel } from '../models/conversations'; import type { ConversationModel } from '../models/conversations';
import * as log from '../logging/log'; import * as log from '../logging/log';
type MessageRequestAttributesType = { export type MessageRequestAttributesType = {
threadE164?: string; threadE164?: string;
threadUuid?: string; threadUuid?: string;
groupId?: string; groupId?: string;

View file

@ -11,9 +11,9 @@ import { isMessageUnread } from '../util/isMessageUnread';
import { notificationService } from '../services/notifications'; import { notificationService } from '../services/notifications';
import * as log from '../logging/log'; import * as log from '../logging/log';
type ReadSyncAttributesType = { export type ReadSyncAttributesType = {
senderId: string; senderId: string;
sender: string; sender?: string;
senderUuid: string; senderUuid: string;
timestamp: number; timestamp: number;
readAt: number; readAt: number;

View file

@ -7,7 +7,7 @@ import { Collection, Model } from 'backbone';
import type { MessageModel } from '../models/messages'; import type { MessageModel } from '../models/messages';
import * as log from '../logging/log'; import * as log from '../logging/log';
type ViewOnceOpenSyncAttributesType = { export type ViewOnceOpenSyncAttributesType = {
source?: string; source?: string;
sourceUuid: string; sourceUuid: string;
timestamp: number; timestamp: number;

View file

@ -12,9 +12,9 @@ import { isIncoming } from '../state/selectors/message';
import { notificationService } from '../services/notifications'; import { notificationService } from '../services/notifications';
import * as log from '../logging/log'; import * as log from '../logging/log';
type ViewSyncAttributesType = { export type ViewSyncAttributesType = {
senderId: string; senderId: string;
senderE164: string; senderE164?: string;
senderUuid: string; senderUuid: string;
timestamp: number; timestamp: number;
viewedAt: number; viewedAt: number;