diff options
Diffstat (limited to 'slixmpp/plugins/xep_0444')
-rw-r--r-- | slixmpp/plugins/xep_0444/__init__.py | 11 | ||||
-rw-r--r-- | slixmpp/plugins/xep_0444/reactions.py | 63 | ||||
-rw-r--r-- | slixmpp/plugins/xep_0444/stanza.py | 60 |
3 files changed, 134 insertions, 0 deletions
diff --git a/slixmpp/plugins/xep_0444/__init__.py b/slixmpp/plugins/xep_0444/__init__.py new file mode 100644 index 00000000..dff4287c --- /dev/null +++ b/slixmpp/plugins/xep_0444/__init__.py @@ -0,0 +1,11 @@ +""" + Slixmpp: The Slick XMPP Library + Copyright (C) 2020 Mathieu Pasquet + This file is part of Slixmpp. + + See the file LICENSE for copying permission. +""" +from slixmpp.plugins.base import register_plugin +from slixmpp.plugins.xep_0444.reactions import XEP_0444 + +register_plugin(XEP_0444) diff --git a/slixmpp/plugins/xep_0444/reactions.py b/slixmpp/plugins/xep_0444/reactions.py new file mode 100644 index 00000000..bfd12499 --- /dev/null +++ b/slixmpp/plugins/xep_0444/reactions.py @@ -0,0 +1,63 @@ +""" + Slixmpp: The Slick XMPP Library + Copyright (C) 2020 Mathieu Pasquet + This file is part of Slixmpp. + + See the file LICENSE for copying permission. +""" +from typing import Iterable + +from slixmpp import JID +from slixmpp.plugins import BasePlugin +from slixmpp.stanza import Message +from slixmpp.xmlstream import register_stanza_plugin +from slixmpp.xmlstream.matcher import MatchXMLMask +from slixmpp.xmlstream.handler import Callback + +from slixmpp.plugins.xep_0444 import stanza + + +class XEP_0444(BasePlugin): + name = 'xep_0444' + description = 'XEP-0444: Message Reactions' + dependencies = {'xep_0030', 'xep_0334'} + stanza = stanza + namespace = stanza.NS + + def plugin_init(self): + self.xmpp.register_handler( + Callback( + 'Reaction received', + MatchXMLMask('<message><reactions xmlns="urn:xmpp:reactions:0"/></message>'), + self._handle_reactions, + ) + ) + register_stanza_plugin(Message, stanza.Reactions) + register_stanza_plugin(stanza.Reactions, stanza.Reaction, iterable=True) + + def session_bind(self, event): + self.xmpp['xep_0030'].add_feature(stanza.NS) + + def plugin_end(self): + self.xmpp.remove_handler('Reaction received') + self.xmpp['xep_0030'].remove_feature(stanza.NS) + + def _handle_reactions(self, message: Message): + self.xmpp.event('reactions', message) + + def send_reactions(self, to: JID, to_id: str, reactions: Iterable[str], *, store=True): + """Send reactions related to a message""" + msg = self.xmpp.make_message(mto=to) + self.set_reactions(msg, to_id, reactions) + if store: + msg.enable('store') + msg.send() + + @staticmethod + def set_reactions(message: Message, to_id: str, reactions: Iterable[str]): + """Add reactions to a Message object.""" + message['reactions']['id'] = to_id + for reaction in reactions: + reaction_stanza = stanza.Reaction() + reaction_stanza['value'] = reaction + message['reactions'].append(reaction_stanza) diff --git a/slixmpp/plugins/xep_0444/stanza.py b/slixmpp/plugins/xep_0444/stanza.py new file mode 100644 index 00000000..338a244e --- /dev/null +++ b/slixmpp/plugins/xep_0444/stanza.py @@ -0,0 +1,60 @@ +""" + Slixmpp: The Slick XMPP Library + Copyright (C) 2020 Mathieu Pasquet + This file is part of Slixmpp. + + See the file LICENSE for copying permission. +""" + +from typing import Set, Iterable +from slixmpp.xmlstream import ElementBase +try: + from emoji import UNICODE_EMOJI +except ImportError: + UNICODE_EMOJI = None + + +NS = 'urn:xmpp:reactions:0' + +class Reactions(ElementBase): + name = 'reactions' + plugin_attrib = 'reactions' + namespace = NS + interfaces = {'id', 'values'} + + def get_values(self, *, all_chars=False) -> Set[str]: + """"Get all reactions as str""" + reactions = set() + for reaction in self: + value = reaction['value'] + if UNICODE_EMOJI and not all_chars: + if value in UNICODE_EMOJI: + reactions.add(reaction['value']) + else: + reactions.add(reaction['value']) + return reactions + + def set_values(self, values: Iterable[str], *, all_chars=False): + """"Set all reactions as str""" + for element in self.xml.findall('reaction'): + self.xml.remove(element) + for reaction_txt in values: + reaction = Reaction() + reaction.set_value(reaction_txt, all_chars=all_chars) + self.append(reaction) + + +class Reaction(ElementBase): + name = 'reaction' + namespace = NS + interfaces = {'value'} + + def get_value(self) -> str: + return self.xml.text + + def set_value(self, value: str, *, all_chars=False): + if UNICODE_EMOJI and not all_chars: + if not value in UNICODE_EMOJI: + raise ValueError("%s is not a valid emoji" % value) + self.xml.text = value + |