|
|
|
@ -19,28 +19,23 @@ const latestReactionTimestamps: Array<number> = [];
|
|
|
|
|
* Retrieves the original message of a reaction
|
|
|
|
|
*/
|
|
|
|
|
const getMessageByReaction = async (
|
|
|
|
|
reaction: SignalService.DataMessage.IReaction,
|
|
|
|
|
isOpenGroup: boolean
|
|
|
|
|
reaction: SignalService.DataMessage.IReaction
|
|
|
|
|
): Promise<MessageModel | null> => {
|
|
|
|
|
let originalMessage = null;
|
|
|
|
|
const originalMessageId = Number(reaction.id);
|
|
|
|
|
const originalMessageAuthor = reaction.author;
|
|
|
|
|
|
|
|
|
|
if (isOpenGroup) {
|
|
|
|
|
originalMessage = await Data.getMessageByServerId(originalMessageId);
|
|
|
|
|
} else {
|
|
|
|
|
const collection = await Data.getMessagesBySentAt(originalMessageId);
|
|
|
|
|
originalMessage = collection.find((item: MessageModel) => {
|
|
|
|
|
const messageTimestamp = item.get('sent_at');
|
|
|
|
|
const author = item.get('source');
|
|
|
|
|
return Boolean(
|
|
|
|
|
messageTimestamp &&
|
|
|
|
|
messageTimestamp === originalMessageId &&
|
|
|
|
|
author &&
|
|
|
|
|
author === originalMessageAuthor
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
const collection = await Data.getMessagesBySentAt(originalMessageId);
|
|
|
|
|
originalMessage = collection.find((item: MessageModel) => {
|
|
|
|
|
const messageTimestamp = item.get('sent_at');
|
|
|
|
|
const author = item.get('source');
|
|
|
|
|
return Boolean(
|
|
|
|
|
messageTimestamp &&
|
|
|
|
|
messageTimestamp === originalMessageId &&
|
|
|
|
|
author &&
|
|
|
|
|
author === originalMessageAuthor
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!originalMessage) {
|
|
|
|
|
window?.log?.warn(`Cannot find the original reacted message ${originalMessageId}.`);
|
|
|
|
@ -67,6 +62,7 @@ export const sendMessageReaction = async (messageId: string, emoji: string) => {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO need to add rate limiting to SOGS function
|
|
|
|
|
const timestamp = Date.now();
|
|
|
|
|
latestReactionTimestamps.push(timestamp);
|
|
|
|
|
|
|
|
|
@ -80,21 +76,19 @@ export const sendMessageReaction = async (messageId: string, emoji: string) => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const isOpenGroup = Boolean(found?.get('isPublic'));
|
|
|
|
|
const id = (isOpenGroup && found.get('serverId')) || Number(found.get('sent_at'));
|
|
|
|
|
const me =
|
|
|
|
|
(isOpenGroup && getUsBlindedInThatServer(conversationModel)) ||
|
|
|
|
|
UserUtils.getOurPubKeyStrFromCache();
|
|
|
|
|
if (found?.get('isPublic')) {
|
|
|
|
|
window.log.warn("sendMessageReaction() shouldn't be used in opengroups");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const id = Number(found.get('sent_at'));
|
|
|
|
|
const me = UserUtils.getOurPubKeyStrFromCache();
|
|
|
|
|
const author = found.get('source');
|
|
|
|
|
let action: Action = Action.REACT;
|
|
|
|
|
|
|
|
|
|
const reacts = found.get('reacts');
|
|
|
|
|
if (
|
|
|
|
|
reacts &&
|
|
|
|
|
Object.keys(reacts).includes(emoji) &&
|
|
|
|
|
Object.keys(reacts[emoji].senders).includes(me)
|
|
|
|
|
) {
|
|
|
|
|
window.log.info('found matching reaction removing it');
|
|
|
|
|
if (reacts && Object.keys(reacts).includes(emoji) && reacts[emoji].senders.includes(me)) {
|
|
|
|
|
window.log.info('Found matching reaction removing it');
|
|
|
|
|
action = Action.REMOVE;
|
|
|
|
|
} else {
|
|
|
|
|
const reactions = getRecentReactions();
|
|
|
|
@ -127,27 +121,32 @@ export const sendMessageReaction = async (messageId: string, emoji: string) => {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle reactions on the client by updating the state of the source message
|
|
|
|
|
* Do not use for Open Groups
|
|
|
|
|
*/
|
|
|
|
|
export const handleMessageReaction = async (
|
|
|
|
|
reaction: SignalService.DataMessage.IReaction,
|
|
|
|
|
sender: string,
|
|
|
|
|
isOpenGroup: boolean,
|
|
|
|
|
messageId?: string
|
|
|
|
|
sender: string
|
|
|
|
|
) => {
|
|
|
|
|
if (!reaction.emoji) {
|
|
|
|
|
window?.log?.warn(`There is no emoji for the reaction ${messageId}.`);
|
|
|
|
|
window?.log?.warn(`There is no emoji for the reaction ${reaction}.`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const originalMessage = await getMessageByReaction(reaction, isOpenGroup);
|
|
|
|
|
const originalMessage = await getMessageByReaction(reaction);
|
|
|
|
|
if (!originalMessage) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (originalMessage.get('isPublic')) {
|
|
|
|
|
window.log.warn("handleMessageReaction() shouldn't be used in opengroups");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const reacts: ReactionList = originalMessage.get('reacts') ?? {};
|
|
|
|
|
reacts[reaction.emoji] = reacts[reaction.emoji] || { count: null, senders: {} };
|
|
|
|
|
reacts[reaction.emoji] = reacts[reaction.emoji] || { count: null, senders: [] };
|
|
|
|
|
const details = reacts[reaction.emoji] ?? {};
|
|
|
|
|
const senders = Object.keys(details.senders);
|
|
|
|
|
const senders = details.senders;
|
|
|
|
|
let count = details.count || 0;
|
|
|
|
|
|
|
|
|
|
window.log.info(
|
|
|
|
|
`${sender} ${reaction.action === Action.REACT ? 'added' : 'removed'} a ${
|
|
|
|
@ -156,33 +155,30 @@ export const handleMessageReaction = async (
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
switch (reaction.action) {
|
|
|
|
|
case SignalService.DataMessage.Reaction.Action.REACT:
|
|
|
|
|
if (senders.includes(sender) && details.senders[sender] !== '') {
|
|
|
|
|
window?.log?.info(
|
|
|
|
|
'Received duplicate message reaction. Dropping it. id:',
|
|
|
|
|
details.senders[sender]
|
|
|
|
|
);
|
|
|
|
|
case Action.REACT:
|
|
|
|
|
if (senders.includes(sender)) {
|
|
|
|
|
window.log.warn('Received duplicate reaction message. Ignoring it', reaction, sender);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
details.senders[sender] = messageId ?? '';
|
|
|
|
|
details.senders.push(sender);
|
|
|
|
|
count += 1;
|
|
|
|
|
break;
|
|
|
|
|
case SignalService.DataMessage.Reaction.Action.REMOVE:
|
|
|
|
|
case Action.REMOVE:
|
|
|
|
|
default:
|
|
|
|
|
if (senders.length > 0) {
|
|
|
|
|
if (senders.indexOf(sender) >= 0) {
|
|
|
|
|
// tslint:disable-next-line: no-dynamic-delete
|
|
|
|
|
delete details.senders[sender];
|
|
|
|
|
if (senders && senders.length > 0) {
|
|
|
|
|
const sendersIndex = senders.indexOf(sender);
|
|
|
|
|
if (sendersIndex >= 0) {
|
|
|
|
|
details.senders.splice(sendersIndex, 1);
|
|
|
|
|
count -= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const count = Object.keys(details.senders).length;
|
|
|
|
|
if (count > 0) {
|
|
|
|
|
reacts[reaction.emoji].count = count;
|
|
|
|
|
reacts[reaction.emoji].senders = details.senders;
|
|
|
|
|
|
|
|
|
|
// sorting for open groups convos is handled by SOGS
|
|
|
|
|
if (!isOpenGroup && details && details.index === undefined) {
|
|
|
|
|
if (details && details.index === undefined) {
|
|
|
|
|
reacts[reaction.emoji].index = originalMessage.get('reactsIndex') ?? 0;
|
|
|
|
|
originalMessage.set('reactsIndex', (originalMessage.get('reactsIndex') ?? 0) + 1);
|
|
|
|
|
}
|
|
|
|
@ -200,7 +196,7 @@ export const handleMessageReaction = async (
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle all updates to messages reactions from the SOGS API
|
|
|
|
|
* Handles all message reaction updates for opengroups
|
|
|
|
|
*/
|
|
|
|
|
export const handleOpenGroupMessageReactions = async (
|
|
|
|
|
reactions: OpenGroupReactionList,
|
|
|
|
@ -212,6 +208,11 @@ export const handleOpenGroupMessageReactions = async (
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!originalMessage.get('isPublic')) {
|
|
|
|
|
window.log.warn('handleOpenGroupMessageReactions() should only be used in opengroups');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isEmpty(reactions)) {
|
|
|
|
|
if (originalMessage.get('reacts')) {
|
|
|
|
|
originalMessage.set({
|
|
|
|
@ -239,9 +240,9 @@ export const handleOpenGroupMessageReactions = async (
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const senders: Record<string, string> = {};
|
|
|
|
|
const senders: Array<string> = [];
|
|
|
|
|
reactions[key].reactors.forEach(reactor => {
|
|
|
|
|
senders[reactor] = String(serverId);
|
|
|
|
|
senders.push(reactor);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
reacts[emoji] = {
|
|
|
|
|