From 36991b5c8ac9fbde73e787eb7429b6051d03e22e Mon Sep 17 00:00:00 2001 From: iequidoo Date: Mon, 21 Nov 2022 09:05:33 -0300 Subject: [PATCH] Add Python API to send reactions (#3762) --- python/src/deltachat/events.py | 10 +++++++ python/src/deltachat/hookspec.py | 4 +++ python/src/deltachat/message.py | 12 +++++++++ python/src/deltachat/reactions.py | 43 +++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+) create mode 100644 python/src/deltachat/reactions.py diff --git a/python/src/deltachat/events.py b/python/src/deltachat/events.py index ccb9f877f..72b84a44a 100644 --- a/python/src/deltachat/events.py +++ b/python/src/deltachat/events.py @@ -192,6 +192,12 @@ class FFIEventTracker: return self.account.get_message_by_id(ev.data2) return None + def wait_next_reactions_changed(self): + """wait for and return next reactions-changed message""" + ev = self.get_matching("DC_EVENT_REACTIONS_CHANGED") + assert ev.data1 > 0 + return self.account.get_message_by_id(ev.data2) + def wait_msg_delivered(self, msg): ev = self.get_matching("DC_EVENT_MSG_DELIVERED") assert ev.data1 == msg.chat.id @@ -296,6 +302,10 @@ class EventThread(threading.Thread): "ac_incoming_message", dict(message=msg), ) + elif name == "DC_EVENT_REACTIONS_CHANGED": + assert ffi_event.data1 > 0 + msg = account.get_message_by_id(ffi_event.data2) + yield "ac_reactions_changed", dict(message=msg) elif name == "DC_EVENT_MSG_DELIVERED": msg = account.get_message_by_id(ffi_event.data2) yield "ac_message_delivered", dict(message=msg) diff --git a/python/src/deltachat/hookspec.py b/python/src/deltachat/hookspec.py index 2a76dafb8..4d2fe6960 100644 --- a/python/src/deltachat/hookspec.py +++ b/python/src/deltachat/hookspec.py @@ -49,6 +49,10 @@ class PerAccount: def ac_outgoing_message(self, message): """Called on each outgoing message (both system and "normal").""" + @account_hookspec + def ac_reactions_changed(self, message): + """Called when message reactions changed.""" + @account_hookspec def ac_message_delivered(self, message): """Called when an outgoing message has been delivered to SMTP. diff --git a/python/src/deltachat/message.py b/python/src/deltachat/message.py index 9ed5b132f..e0b4d468f 100644 --- a/python/src/deltachat/message.py +++ b/python/src/deltachat/message.py @@ -9,6 +9,7 @@ from typing import Optional, Union from . import const, props from .capi import ffi, lib from .cutil import as_dc_charpointer, from_dc_charpointer, from_optional_dc_charpointer +from .reactions import Reactions class Message(object): @@ -161,6 +162,17 @@ class Message(object): ) ) + def send_reaction(self, reaction: str): + """Send a reaction to message and return the resulting Message instance.""" + msg_id = lib.dc_send_reaction(self.account._dc_context, self.id, as_dc_charpointer(reaction)) + if msg_id == 0: + raise ValueError("reaction could not be send") + return Message.from_db(self.account, msg_id) + + def get_reactions(self) -> Reactions: + """Get :class:`deltachat.reactions.Reactions` to the message.""" + return Reactions.from_msg(self) + def is_system_message(self): """return True if this message is a system/info message.""" return bool(lib.dc_msg_is_info(self._dc_msg)) diff --git a/python/src/deltachat/reactions.py b/python/src/deltachat/reactions.py new file mode 100644 index 000000000..9e9ed9555 --- /dev/null +++ b/python/src/deltachat/reactions.py @@ -0,0 +1,43 @@ +""" The Reactions object. """ + +from .capi import ffi, lib +from .cutil import from_dc_charpointer, iter_array + + +class Reactions(object): + """Reactions object. + + You obtain instances of it through :class:`deltachat.message.Message`. + """ + + def __init__(self, account, dc_reactions): + assert isinstance(account._dc_context, ffi.CData) + assert isinstance(dc_reactions, ffi.CData) + assert dc_reactions != ffi.NULL + self.account = account + self._dc_reactions = dc_reactions + + def __repr__(self): + return "".format(self._dc_reactions) + + @classmethod + def from_msg(cls, msg): + assert msg.id > 0 + return cls( + msg.account, + ffi.gc(lib.dc_get_msg_reactions(msg.account._dc_context, msg.id), lib.dc_reactions_unref), + ) + + def get_contacts(self) -> list: + """Get list of contacts reacted to the message. + + :returns: list of :class:`deltachat.contact.Contact` objects for this reaction. + """ + from .contact import Contact + + dc_array = ffi.gc(lib.dc_reactions_get_contacts(self._dc_reactions), lib.dc_array_unref) + return list(iter_array(dc_array, lambda x: Contact(self.account, x))) + + def get_by_contact(self, contact) -> str: + """Get a string containing space-separated reactions of a single :class:`deltachat.contact.Contact`.""" + return from_dc_charpointer(lib.dc_reactions_get_by_contact_id(self._dc_reactions, contact.id))