1
0
Fork 0
mirror of https://github.com/deltachat/deltachat-core.git synced 2025-10-04 10:19:16 +02:00

add chat.delete(), chat.send_image, msg.filename, msg.filemime and msg.type.is_*

This commit is contained in:
holger krekel 2018-10-06 18:40:52 +02:00
parent 60240ce507
commit b6355176de
5 changed files with 181 additions and 3 deletions

View file

@ -11,6 +11,7 @@ high level API reference
- :class:`deltachat.chatting.Contact` - :class:`deltachat.chatting.Contact`
- :class:`deltachat.chatting.Chat` - :class:`deltachat.chatting.Chat`
- :class:`deltachat.chatting.Message` - :class:`deltachat.chatting.Message`
- :class:`deltachat.chatting.MessageType`
- :class:`deltachat.chatting.MessageState` - :class:`deltachat.chatting.MessageState`
Account Account
@ -38,6 +39,11 @@ Message
.. autoclass:: deltachat.chatting.Message .. autoclass:: deltachat.chatting.Message
:members: :members:
MessageType
------------
.. autoclass:: deltachat.chatting.MessageType
:members:
MessageState MessageState
------------ ------------

View file

@ -1,5 +1,6 @@
""" chatting related objects: Contact, Chat, Message. """ """ chatting related objects: Contact, Chat, Message. """
import os
from .cutil import as_dc_charpointer, from_dc_charpointer, iter_array from .cutil import as_dc_charpointer, from_dc_charpointer, iter_array
from .capi import lib, ffi from .capi import lib, ffi
from .types import property_with_doc from .types import property_with_doc
@ -60,6 +61,16 @@ class Chat(object):
lib.dc_chat_unref lib.dc_chat_unref
) )
def delete(self):
"""Delete this chat and all its messages.
Note:
- does not delete messages on server
- the chat or contact is not blocked, new message will arrive
"""
lib.dc_delete_chat(self._dc_context, self.id)
# ------ chat status/metadata API ------------------------------ # ------ chat status/metadata API ------------------------------
def is_deaddrop(self): def is_deaddrop(self):
@ -100,10 +111,28 @@ class Chat(object):
""" send a text message and return the resulting Message instance. """ send a text message and return the resulting Message instance.
:param msg: unicode text :param msg: unicode text
:raises: ValueError if message can not be send/chat does not exist.
:returns: the resulting :class:`deltachat.chatting.Message` instance :returns: the resulting :class:`deltachat.chatting.Message` instance
""" """
msg = as_dc_charpointer(msg) msg = as_dc_charpointer(msg)
msg_id = lib.dc_send_text_msg(self._dc_context, self.id, msg) msg_id = lib.dc_send_text_msg(self._dc_context, self.id, msg)
if msg_id == 0:
raise ValueError("message could not be send, does chat exist?")
return Message(self._dc_context, msg_id)
def send_image(self, path):
""" send an image message and return the resulting Message instance.
:param path: path to an image file.
:raises: ValueError if message can not be send/chat does not exist.
:returns: the resulting :class:`deltachat.chatting.Message` instance
"""
if not os.path.exists(path):
raise ValueError("path does not exist: {!r}".format(path))
path = as_dc_charpointer(path)
msg_id = lib.dc_send_image_msg(self._dc_context, self.id, path, ffi.NULL, 0, 0)
if msg_id == 0:
raise ValueError("chat does not exist")
return Message(self._dc_context, msg_id) return Message(self._dc_context, msg_id)
def get_messages(self): def get_messages(self):
@ -186,9 +215,27 @@ class Message(object):
@property_with_doc @property_with_doc
def text(self): def text(self):
"""unicode text of this messages. """ """unicode text of this messages (might be empty if not a text message). """
return from_dc_charpointer(lib.dc_msg_get_text(self._dc_msg)) return from_dc_charpointer(lib.dc_msg_get_text(self._dc_msg))
@property_with_doc
def filename(self):
"""filename if there was an attachment, otherwise empty string. """
return from_dc_charpointer(lib.dc_msg_get_file(self._dc_msg))
@property_with_doc
def filemime(self):
"""mime type of the file (if it exists)"""
return from_dc_charpointer(lib.dc_msg_get_filemime(self._dc_msg))
@property_with_doc
def type(self):
"""the media type of this message.
:returns: a :class:`deltachat.chatting.MessageType` instance.
"""
return MessageType(lib.dc_msg_get_type(self._dc_msg))
@property_with_doc @property_with_doc
def time_sent(self): def time_sent(self):
"""time when the message was sent. """time when the message was sent.
@ -210,12 +257,55 @@ class Message(object):
def get_sender_contact(self): def get_sender_contact(self):
"""return the contact of who wrote the message. """return the contact of who wrote the message.
:returns: :class:`deltachat.chatting.Contact`` instance :returns: :class:`deltachat.chatting.Contact` instance
""" """
contact_id = lib.dc_msg_get_from_id(self._dc_msg) contact_id = lib.dc_msg_get_from_id(self._dc_msg)
return Contact(self._dc_context, contact_id) return Contact(self._dc_context, contact_id)
@attr.s
class MessageType(object):
""" DeltaChat message type, with is_* methods. """
_type = attr.ib(validator=v.instance_of(int))
_mapping = {
const.DC_MSG_TEXT: 'text',
const.DC_MSG_IMAGE: 'image',
const.DC_MSG_GIF: 'gif',
const.DC_MSG_AUDIO: 'audio',
const.DC_MSG_VIDEO: 'video',
const.DC_MSG_FILE: 'file'
}
@property_with_doc
def name(self):
""" human readable type name. """
return self._mapping[self._type]
def is_text(self):
""" return True if it's a text message. """
return self._type == const.DC_MSG_TEXT
def is_image(self):
""" return True if it's an image message. """
return self._type == const.DC_MSG_IMAGE
def is_gif(self):
""" return True if it's a gif message. """
return self._type == const.DC_MSG_GIF
def is_audio(self):
""" return True if it's an audio message. """
return self._type == const.DC_MSG_AUDIO
def is_video(self):
""" return True if it's a video message. """
return self._type == const.DC_MSG_VIDEO
def is_file(self):
""" return True if it's a file message. """
return self._type == const.DC_MSG_FILE
@attr.s @attr.s
class MessageState(object): class MessageState(object):
""" Current Message In/Out state, updated on each call of is_* methods. """ Current Message In/Out state, updated on each call of is_* methods.

View file

@ -24,6 +24,9 @@ DC_CHAT_TYPE_UNDEFINED = 0
DC_CHAT_TYPE_SINGLE = 100 DC_CHAT_TYPE_SINGLE = 100
DC_CHAT_TYPE_GROUP = 120 DC_CHAT_TYPE_GROUP = 120
DC_CHAT_TYPE_VERIFIED_GROUP = 130 DC_CHAT_TYPE_VERIFIED_GROUP = 130
DC_MSG_ID_MARKER1 = 1
DC_MSG_ID_DAYMARKER = 9
DC_MSG_ID_LAST_SPECIAL = 9
DC_STATE_UNDEFINED = 0 DC_STATE_UNDEFINED = 0
DC_STATE_IN_FRESH = 10 DC_STATE_IN_FRESH = 10
DC_STATE_IN_NOTICED = 13 DC_STATE_IN_NOTICED = 13
@ -35,6 +38,14 @@ DC_STATE_OUT_MDN_RCVD = 28
DC_CONTACT_ID_SELF = 1 DC_CONTACT_ID_SELF = 1
DC_CONTACT_ID_DEVICE = 2 DC_CONTACT_ID_DEVICE = 2
DC_CONTACT_ID_LAST_SPECIAL = 9 DC_CONTACT_ID_LAST_SPECIAL = 9
DC_MSG_UNDEFINED = 0
DC_MSG_TEXT = 10
DC_MSG_IMAGE = 20
DC_MSG_GIF = 21
DC_MSG_AUDIO = 40
DC_MSG_VOICE = 41
DC_MSG_VIDEO = 50
DC_MSG_FILE = 60
DC_EVENT_INFO = 100 DC_EVENT_INFO = 100
DC_EVENT_SMTP_CONNECTED = 101 DC_EVENT_SMTP_CONNECTED = 101
DC_EVENT_IMAP_CONNECTED = 102 DC_EVENT_IMAP_CONNECTED = 102
@ -62,7 +73,7 @@ DC_EVENT_HTTP_GET = 2100
def read_event_defines(f): def read_event_defines(f):
rex = re.compile(r'#define\s+((?:DC_EVENT_|DC_STATE_|DC_CONTACT_ID_|DC_GCL|DC_CHAT)\S+)\s+([x\d]+).*') rex = re.compile(r'#define\s+((?:DC_EVENT_|DC_MSG|DC_STATE_|DC_CONTACT_ID_|DC_GCL|DC_CHAT)\S+)\s+([x\d]+).*')
for line in f: for line in f:
m = rex.match(line) m = rex.match(line)
if m: if m:

View file

@ -1,4 +1,5 @@
from __future__ import print_function from __future__ import print_function
import os
import pytest import pytest
from deltachat import Account from deltachat import Account
from deltachat.types import cached_property from deltachat.types import cached_property
@ -13,6 +14,19 @@ def pytest_addoption(parser):
) )
@pytest.fixture(scope="session")
def data():
class Data:
def __init__(self):
self.path = os.path.join(os.path.dirname(__file__), "data")
def get_path(self, bn):
fn = os.path.join(self.path, bn)
assert os.path.exists(fn)
return fn
return Data()
@pytest.fixture @pytest.fixture
def acfactory(pytestconfig, tmpdir, request): def acfactory(pytestconfig, tmpdir, request):
fn = pytestconfig.getoption("--liveconfig") fn = pytestconfig.getoption("--liveconfig")

View file

@ -1,5 +1,6 @@
from __future__ import print_function from __future__ import print_function
import pytest import pytest
import os
from deltachat import const from deltachat import const
from datetime import datetime, timedelta from datetime import datetime, timedelta
from conftest import wait_configuration_progress, wait_successful_IMAP_SMTP_connection from conftest import wait_configuration_progress, wait_successful_IMAP_SMTP_connection
@ -82,12 +83,28 @@ class TestOfflineAccount:
chat.set_name("title2") chat.set_name("title2")
assert chat.get_name() == "title2" assert chat.get_name() == "title2"
def test_delete_and_send_fails(self, acfactory):
ac1 = acfactory.get_configured_offline_account()
contact1 = ac1.create_contact("some1@hello.com", name="some1")
chat = ac1.create_chat_by_contact(contact1)
chat.delete()
ac1._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
with pytest.raises(ValueError):
chat.send_text_message("msg1")
def test_message(self, acfactory): def test_message(self, acfactory):
ac1 = acfactory.get_configured_offline_account() ac1 = acfactory.get_configured_offline_account()
contact1 = ac1.create_contact("some1@hello.com", name="some1") contact1 = ac1.create_contact("some1@hello.com", name="some1")
chat = ac1.create_chat_by_contact(contact1) chat = ac1.create_chat_by_contact(contact1)
msg = chat.send_text_message("msg1") msg = chat.send_text_message("msg1")
assert msg assert msg
assert msg.type.is_text()
assert msg.type.name == "text"
assert not msg.type.is_audio()
assert not msg.type.is_video()
assert not msg.type.is_gif()
assert not msg.type.is_file()
assert not msg.type.is_image()
msg_state = msg.get_state() msg_state = msg.get_state()
assert not msg_state.is_in_fresh() assert not msg_state.is_in_fresh()
assert not msg_state.is_in_noticed() assert not msg_state.is_in_noticed()
@ -97,6 +114,20 @@ class TestOfflineAccount:
assert not msg_state.is_out_delivered() assert not msg_state.is_out_delivered()
assert not msg_state.is_out_mdn_received() assert not msg_state.is_out_mdn_received()
def test_message_image(self, acfactory, data):
ac1 = acfactory.get_configured_offline_account()
contact1 = ac1.create_contact("some1@hello.com", name="some1")
chat = ac1.create_chat_by_contact(contact1)
with pytest.raises(ValueError):
chat.send_image(path="notexists")
fn = data.get_path("d.png")
msg = chat.send_image(fn)
assert msg.type.name == "image"
assert msg
assert msg.id > 0
assert os.path.exists(msg.filename)
assert msg.filemime == "image/png"
def test_chat_message_distinctions(self, acfactory): def test_chat_message_distinctions(self, acfactory):
ac1 = acfactory.get_configured_offline_account() ac1 = acfactory.get_configured_offline_account()
contact1 = ac1.create_contact("some1@hello.com", name="some1") contact1 = ac1.create_contact("some1@hello.com", name="some1")
@ -199,3 +230,29 @@ class TestOnlineAccount:
lp.step("2") lp.step("2")
ac1._evlogger.get_info_matching("Message marked as seen") ac1._evlogger.get_info_matching("Message marked as seen")
assert msg_out.get_state().is_out_mdn_received() assert msg_out.get_state().is_out_mdn_received()
def test_send_and_receive_image(self, acfactory, lp, data):
lp.sec("starting accounts, waiting for configuration")
ac1 = acfactory.get_online_configuring_account()
ac2 = acfactory.get_online_configuring_account()
c2 = ac1.create_contact(email=ac2.get_config("addr"))
chat = ac1.create_chat_by_contact(c2)
wait_configuration_progress(ac1, 1000)
wait_configuration_progress(ac2, 1000)
lp.sec("sending image message from ac1 to ac2")
path = data.get_path("d.png")
msg_out = chat.send_image(path)
ev = ac1._evlogger.get_matching("DC_EVENT_MSG_DELIVERED")
evt_name, data1, data2 = ev
assert data1 == chat.id
assert data2 == msg_out.id
assert msg_out.get_state().is_out_delivered()
lp.sec("wait for ac2 to receive message")
ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
assert ev[2] == msg_out.id
msg_in = ac2.get_message_by_id(msg_out.id)
assert os.path.exists(msg_in.filename)
assert os.stat(msg_in.filename).st_size == os.stat(path).st_size