Signal-Desktop/js/reactions.js

142 lines
4.4 KiB
JavaScript
Raw Normal View History

2020-10-30 20:34:04 +00:00
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
2020-01-17 22:23:19 +00:00
/* global
Backbone,
Whisper,
2020-03-20 19:07:44 +00:00
MessageController,
ConversationController
2020-01-17 22:23:19 +00:00
*/
/* eslint-disable more/no-then */
// eslint-disable-next-line func-names
(function () {
2020-01-17 22:23:19 +00:00
window.Whisper = window.Whisper || {};
Whisper.Reactions = new (Backbone.Collection.extend({
forMessage(message) {
if (message.isOutgoing()) {
2020-03-20 19:07:44 +00:00
const outgoingReactions = this.filter({
2020-01-17 22:23:19 +00:00
targetTimestamp: message.get('sent_at'),
});
2020-03-20 19:07:44 +00:00
if (outgoingReactions.length > 0) {
2020-01-17 22:23:19 +00:00
window.log.info('Found early reaction for outgoing message');
2020-03-20 19:07:44 +00:00
this.remove(outgoingReactions);
return outgoingReactions;
2020-01-17 22:23:19 +00:00
}
}
const senderId = message.getContactId();
const sentAt = message.get('sent_at');
2020-03-20 19:07:44 +00:00
const reactionsBySource = this.filter(re => {
const targetSenderId = ConversationController.ensureContactIds({
e164: re.get('targetAuthorE164'),
uuid: re.get('targetAuthorUuid'),
});
const targetTimestamp = re.get('targetTimestamp');
return targetSenderId === senderId && targetTimestamp === sentAt;
2020-01-17 22:23:19 +00:00
});
2020-03-20 19:07:44 +00:00
if (reactionsBySource.length > 0) {
2020-01-17 22:23:19 +00:00
window.log.info('Found early reaction for message');
2020-03-20 19:07:44 +00:00
this.remove(reactionsBySource);
return reactionsBySource;
2020-01-17 22:23:19 +00:00
}
2020-03-20 19:07:44 +00:00
return [];
2020-01-17 22:23:19 +00:00
},
async onReaction(reaction) {
try {
// The conversation the target message was in; we have to find it in the database
// to to figure that out.
const targetConversation = await ConversationController.getConversationForTargetMessage(
ConversationController.ensureContactIds({
e164: reaction.get('targetAuthorE164'),
uuid: reaction.get('targetAuthorUuid'),
}),
reaction.get('targetTimestamp')
2020-01-17 22:23:19 +00:00
);
if (!targetConversation) {
window.log.info(
'No target conversation for reaction',
reaction.get('targetAuthorE164'),
reaction.get('targetAuthorUuid'),
reaction.get('targetTimestamp')
);
return;
}
2020-01-17 22:23:19 +00:00
// awaiting is safe since `onReaction` is never called from inside the queue
await targetConversation.queueJob(async () => {
window.log.info(
'Handling reaction for',
reaction.get('targetTimestamp')
);
const messages = await window.Signal.Data.getMessagesBySentAt(
reaction.get('targetTimestamp'),
{
MessageCollection: Whisper.MessageCollection,
}
2020-01-17 22:23:19 +00:00
);
// Message is fetched inside the conversation queue so we have the
// most recent data
const targetMessage = messages.find(m => {
const contact = m.getContact();
if (!contact) {
return false;
}
const mcid = contact.get('id');
const recid = ConversationController.ensureContactIds({
e164: reaction.get('targetAuthorE164'),
uuid: reaction.get('targetAuthorUuid'),
});
return mcid === recid;
});
if (!targetMessage) {
window.log.info(
'No message for reaction',
reaction.get('targetAuthorE164'),
reaction.get('targetAuthorUuid'),
reaction.get('targetTimestamp')
);
// Since we haven't received the message for which we are removing a
// reaction, we can just remove those pending reactions
if (reaction.get('remove')) {
this.remove(reaction);
const oldReaction = this.where({
targetAuthorE164: reaction.get('targetAuthorE164'),
targetAuthorUuid: reaction.get('targetAuthorUuid'),
targetTimestamp: reaction.get('targetTimestamp'),
emoji: reaction.get('emoji'),
});
oldReaction.forEach(r => this.remove(r));
}
return;
2020-01-17 22:23:19 +00:00
}
const message = MessageController.register(
targetMessage.id,
targetMessage
);
2020-01-17 22:23:19 +00:00
await message.handleReaction(reaction);
2020-01-17 22:23:19 +00:00
this.remove(reaction);
});
2020-01-17 22:23:19 +00:00
} catch (error) {
window.log.error(
'Reactions.onReaction error:',
error && error.stack ? error.stack : error
);
}
},
}))();
})();