-
-
Notifications
You must be signed in to change notification settings - Fork 810
Feature: Add support for XEP-0444 Message Reactions #3906
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| /** | ||
| * XEP-0444: Message Reactions - Headless core | ||
| */ | ||
|
|
||
| import './plugin.js'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| /** | ||
| * @typedef {import('../../shared/types').MessageAttributes} MessageAttributes | ||
| * @typedef {import('../../plugins/muc/types').MUCMessageAttributes} MUCMessageAttributes | ||
| */ | ||
|
|
||
| import converse from '../../shared/api/public.js'; | ||
|
|
||
| const { Strophe } = converse.env; | ||
|
|
||
| /** | ||
| * Parse reactions from a message stanza and return updated attributes | ||
| * @param {Element} stanza - The XMPP message stanza | ||
| * @param {MessageAttributes|MUCMessageAttributes} attrs - Current message attributes | ||
| * @returns {Promise<import('./types').MessageAttrsWithReactions|import('./types').MUCMessageAttrsWithReactions>} | ||
| */ | ||
| export async function parseReactionsMessage(stanza, attrs) { | ||
| const reactions_element = stanza.querySelector( | ||
| `reactions[xmlns="${Strophe.NS.REACTIONS}"]` | ||
| ); | ||
|
|
||
| if (!reactions_element) { | ||
| return attrs; | ||
| } | ||
|
|
||
| const id = reactions_element.getAttribute('id'); | ||
| if (!id) { | ||
| return attrs; | ||
| } | ||
|
|
||
| const reaction_elements = reactions_element.getElementsByTagName('reaction'); | ||
| const emojis = Array.from(reaction_elements) | ||
| .map(el => el.textContent) | ||
| .filter(e => e); | ||
|
|
||
| if (emojis.length === 0) { | ||
| return attrs; | ||
| } | ||
|
|
||
| const reactions = { ...(/** @type {any} */(attrs).reactions || {}) }; | ||
| const reacting_jid = attrs.from; | ||
|
|
||
| emojis.forEach(emoji => { | ||
| if (!reactions[emoji]) { | ||
| reactions[emoji] = []; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't look like you implemented the recommendations in this comment? The I even gave a code suggestion which you ignored. You can choose to not accept a code suggestion and do something else, but then please explain to me what you did and why. Looks like you also didn't create a listener for getUpdatedMessageAttributes. The fact that the tests don't highlight this issue also shows that they're not written properly. The tests should mock incoming |
||
| } | ||
| if (!reactions[emoji].includes(reacting_jid)) { | ||
| reactions[emoji].push(reacting_jid); | ||
| } | ||
| }); | ||
|
|
||
| // Remove user's reactions that aren't in the new emoji list | ||
| for (const emoji in reactions) { | ||
| if (!emojis.includes(emoji)) { | ||
| reactions[emoji] = reactions[emoji].filter(jid => jid !== reacting_jid); | ||
| if (reactions[emoji].length === 0) { | ||
| delete reactions[emoji]; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return Object.assign(attrs, { reactions }); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| /** | ||
| * @module converse-headless-reactions | ||
| * @copyright The Converse.js contributors | ||
| * @license Mozilla Public License (MPLv2) | ||
| * @description XEP-0444: Message Reactions - Headless core logic | ||
| */ | ||
|
|
||
| import converse from '../../shared/api/public.js'; | ||
| import api from '../../shared/api/index.js'; | ||
| import { parseReactionsMessage } from './parsers.js'; | ||
|
|
||
| const { Strophe } = converse.env; | ||
|
|
||
| Strophe.addNamespace('REACTIONS', 'urn:xmpp:reactions:0'); | ||
|
|
||
| converse.plugins.add('converse-headless-reactions', { | ||
| dependencies: ['converse-chat', 'converse-muc'], | ||
|
|
||
| /** | ||
| * Initializes the headless reactions plugin | ||
| * Hooks into message parsing to extract and store reactions | ||
| */ | ||
| initialize() { | ||
| // Hook into message parsing for 1:1 chats and MUCs | ||
| // This runs when messages are received/parsed | ||
| api.listen.on('parseMessage', parseReactionsMessage); | ||
| api.listen.on('parseMUCMessage', parseReactionsMessage); | ||
| } | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { MUCMessageAttributes } from '../../plugins/muc/types'; | ||
| import { MessageAttributes } from '../../shared/types'; | ||
|
|
||
| export type ReactionsAttributes = { | ||
| reactions?: Record<string, string[]>; | ||
| }; | ||
|
|
||
| export type MUCMessageAttrsWithReactions = MUCMessageAttributes & ReactionsAttributes; | ||
| export type MessageAttrsWithReactions = MessageAttributes & ReactionsAttributes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're exiting too quickly here and thereby preventing previously added emojis from being removed again.