Merge pull request #3416 from deltachat/adb/add-missing-message-api

add missing Message API
This commit is contained in:
Asiel Díaz Benítez
2022-06-10 22:35:41 -04:00
committed by GitHub
4 changed files with 116 additions and 3 deletions

View File

@@ -8,6 +8,13 @@
- set a default error if NDN does not provide an error - set a default error if NDN does not provide an error
- python: avoid exceptions when messages/contacts/chats are compared with `None` - python: avoid exceptions when messages/contacts/chats are compared with `None`
### API-Changes
- python: added `Message.get_status_updates()` #3416
- python: added `Message.send_status_update()` #3416
- python: added `Message.is_webxdc()` #3416
- python: added `Message.is_videochat_invitation()` #3416
- python: added support for "videochat" and "webxdc" view types to `Message.new_empty()` #3416
## 1.86.0 ## 1.86.0
### API-Changes ### API-Changes

View File

@@ -1,9 +1,10 @@
""" The Message object. """ """ The Message object. """
import json
import os import os
import re import re
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Optional from typing import Optional, Union
from . import const, props from . import const, props
from .capi import ffi, lib from .capi import ffi, lib
@@ -54,8 +55,8 @@ class Message(object):
def new_empty(cls, account, view_type): def new_empty(cls, account, view_type):
"""create a non-persistent message. """create a non-persistent message.
:param: view_type is the message type code or one of the strings: :param view_type: the message type code or one of the strings:
"text", "audio", "video", "file", "sticker" "text", "audio", "video", "file", "sticker", "videochat", "webxdc"
""" """
if isinstance(view_type, int): if isinstance(view_type, int):
view_type_code = view_type view_type_code = view_type
@@ -130,6 +131,36 @@ class Message(object):
"""mime type of the file (if it exists)""" """mime type of the file (if it exists)"""
return from_dc_charpointer(lib.dc_msg_get_filemime(self._dc_msg)) return from_dc_charpointer(lib.dc_msg_get_filemime(self._dc_msg))
def get_status_updates(self, serial: int = 0) -> list:
"""Get the status updates of this webxdc message.
The status updates may be sent by yourself or by other members.
If this message doesn't have a webxdc instance, an empty list is returned.
:param serial: The last known serial. Pass 0 if there are no known serials to receive all updates.
"""
return json.loads(
from_dc_charpointer(lib.dc_get_webxdc_status_updates(self.account._dc_context, self.id, serial))
)
def send_status_update(self, json_data: Union[str, dict], description: str) -> bool:
"""Send an status update for the webxdc instance of this message.
If the webxdc instance is a draft, the update is not sent immediately.
Instead, the updates are collected and sent out in a batch when the instance is actually sent.
:param json_data: program-readable data, the actual payload.
:param description: The user-visible description of JSON data
:returns: True on success, False otherwise
"""
if isinstance(json_data, dict):
json_data = json.dumps(json_data, default=str)
return bool(
lib.dc_send_webxdc_status_update(
self.account._dc_context, self.id, as_dc_charpointer(json_data), as_dc_charpointer(description)
)
)
def is_system_message(self): def is_system_message(self):
"""return True if this message is a system/info message.""" """return True if this message is a system/info message."""
return bool(lib.dc_msg_is_info(self._dc_msg)) return bool(lib.dc_msg_is_info(self._dc_msg))
@@ -402,6 +433,14 @@ class Message(object):
"""return True if it's a video message.""" """return True if it's a video message."""
return self._view_type == const.DC_MSG_VIDEO return self._view_type == const.DC_MSG_VIDEO
def is_videochat_invitation(self):
"""return True if it's a videochat invitation message."""
return self._view_type == const.DC_MSG_VIDEOCHAT_INVITATION
def is_webxdc(self):
"""return True if it's a Webxdc message."""
return self._view_type == const.DC_MSG_WEBXDC
def is_file(self): def is_file(self):
"""return True if it's a file message.""" """return True if it's a file message."""
return self._view_type == const.DC_MSG_FILE return self._view_type == const.DC_MSG_FILE
@@ -421,6 +460,8 @@ _view_type_mapping = {
"video": const.DC_MSG_VIDEO, "video": const.DC_MSG_VIDEO,
"file": const.DC_MSG_FILE, "file": const.DC_MSG_FILE,
"sticker": const.DC_MSG_STICKER, "sticker": const.DC_MSG_STICKER,
"videochat": const.DC_MSG_VIDEOCHAT_INVITATION,
"webxdc": const.DC_MSG_WEBXDC,
} }

View File

@@ -241,6 +241,7 @@ def data(request):
os.path.normpath(x) os.path.normpath(x)
for x in [ for x in [
os.path.join(os.path.dirname(request.fspath.strpath), "data"), os.path.join(os.path.dirname(request.fspath.strpath), "data"),
os.path.join(os.path.dirname(request.fspath.strpath), "..", "..", "test-data"),
os.path.join(os.path.dirname(__file__), "..", "..", "..", "test-data"), os.path.join(os.path.dirname(__file__), "..", "..", "..", "test-data"),
] ]
] ]

View File

@@ -238,6 +238,70 @@ def test_html_message(acfactory, lp):
assert html_text in msg2.html assert html_text in msg2.html
def test_videochat_invitation_message(acfactory, lp):
ac1, ac2 = acfactory.get_online_accounts(2)
chat = acfactory.get_accepted_chat(ac1, ac2)
text = "You are invited to a video chat, click https://meet.jit.si/WxEGad0gGzX to join."
lp.sec("ac1: prepare and send text message to ac2")
msg1 = chat.send_text("message0")
assert not msg1.is_videochat_invitation()
lp.sec("wait for ac2 to receive message")
msg2 = ac2._evtracker.wait_next_incoming_message()
assert msg2.text == "message0"
assert not msg2.is_videochat_invitation()
lp.sec("ac1: prepare and send videochat invitation to ac2")
msg1 = Message.new_empty(ac1, "videochat")
msg1.set_text(text)
msg1 = chat.send_msg(msg1)
assert msg1.is_videochat_invitation()
lp.sec("wait for ac2 to receive message")
msg2 = ac2._evtracker.wait_next_incoming_message()
assert msg2.text == text
assert msg2.is_videochat_invitation()
def test_webxdc_message(acfactory, data, lp):
ac1, ac2 = acfactory.get_online_accounts(2)
chat = acfactory.get_accepted_chat(ac1, ac2)
lp.sec("ac1: prepare and send text message to ac2")
msg1 = chat.send_text("message0")
assert not msg1.is_webxdc()
assert not msg1.send_status_update({"payload": "not an webxdc"}, "invalid")
assert not msg1.get_status_updates()
lp.sec("wait for ac2 to receive message")
msg2 = ac2._evtracker.wait_next_incoming_message()
assert msg2.text == "message0"
assert not msg2.is_webxdc()
assert not msg1.get_status_updates()
lp.sec("ac1: prepare and send webxdc instance to ac2")
msg1 = Message.new_empty(ac1, "webxdc")
msg1.set_text("message1")
msg1.set_file(data.get_path("webxdc/minimal.xdc"))
msg1 = chat.send_msg(msg1)
assert msg1.is_webxdc()
assert msg1.filename
assert msg1.send_status_update({"payload": "test1"}, "some test data")
assert msg1.send_status_update({"payload": "test2"}, "more test data")
assert len(msg1.get_status_updates()) == 2
update1 = msg1.get_status_updates()[0]
assert update1["payload"] == "test1"
assert len(msg1.get_status_updates(update1["serial"])) == 1
lp.sec("wait for ac2 to receive message")
msg2 = ac2._evtracker.wait_next_incoming_message()
assert msg2.text == "message1"
assert msg2.is_webxdc()
assert msg2.filename
def test_mvbox_sentbox_threads(acfactory, lp): def test_mvbox_sentbox_threads(acfactory, lp):
lp.sec("ac1: start with mvbox thread") lp.sec("ac1: start with mvbox thread")
ac1 = acfactory.new_online_configuring_account(mvbox_move=True, sentbox_watch=True) ac1 = acfactory.new_online_configuring_account(mvbox_move=True, sentbox_watch=True)