mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
- properly support prepare-msg API and implement get_message_info()
- remove usage of "attr.s" across the code - make msg.set_file() copy a file into blobdir if it isn't already - regroup tests - add set_draft/get_draft API
This commit is contained in:
@@ -288,10 +288,6 @@ intersphinx_mapping = {'http://docs.python.org/': None}
|
|||||||
autodoc_member_order = "bysource"
|
autodoc_member_order = "bysource"
|
||||||
# always document __init__ functions
|
# always document __init__ functions
|
||||||
def skip(app, what, name, obj, skip, options):
|
def skip(app, what, name, obj, skip, options):
|
||||||
import attr
|
|
||||||
if name == "__init__":
|
|
||||||
if not hasattr(obj.im_class, "__attrs_attrs__"):
|
|
||||||
return False
|
|
||||||
return skip
|
return skip
|
||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ def main():
|
|||||||
description='Python bindings for the Delta Chat Core library using CFFI against the Rust-implemented libdeltachat',
|
description='Python bindings for the Delta Chat Core library using CFFI against the Rust-implemented libdeltachat',
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
author='holger krekel, Floris Bruynooghe, Bjoern Petersen and contributors',
|
author='holger krekel, Floris Bruynooghe, Bjoern Petersen and contributors',
|
||||||
install_requires=['cffi>=1.0.0', 'attrs', 'six'],
|
install_requires=['cffi>=1.0.0', 'six'],
|
||||||
packages=setuptools.find_packages('src'),
|
packages=setuptools.find_packages('src'),
|
||||||
package_dir={'': 'src'},
|
package_dir={'': 'src'},
|
||||||
cffi_modules=['src/deltachat/_build.py:ffibuilder'],
|
cffi_modules=['src/deltachat/_build.py:ffibuilder'],
|
||||||
|
|||||||
@@ -69,6 +69,10 @@ class Account(object):
|
|||||||
d[key.lower()] = value
|
d[key.lower()] = value
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def get_blob_dir(self):
|
||||||
|
""" return blob directory for this account. """
|
||||||
|
return from_dc_charpointer(lib.dc_get_blobdir(self._dc_context))
|
||||||
|
|
||||||
def set_config(self, name, value):
|
def set_config(self, name, value):
|
||||||
""" set configuration values.
|
""" set configuration values.
|
||||||
|
|
||||||
@@ -142,15 +146,6 @@ class Account(object):
|
|||||||
self.check_is_configured()
|
self.check_is_configured()
|
||||||
return Contact(self._dc_context, const.DC_CONTACT_ID_SELF)
|
return Contact(self._dc_context, const.DC_CONTACT_ID_SELF)
|
||||||
|
|
||||||
def create_message(self, view_type):
|
|
||||||
""" create a new non persistent message.
|
|
||||||
|
|
||||||
:param view_type: a string specifying "text", "video",
|
|
||||||
"image", "audio" or "file".
|
|
||||||
:returns: :class:`deltachat.message.Message` instance.
|
|
||||||
"""
|
|
||||||
return Message.new(self._dc_context, view_type)
|
|
||||||
|
|
||||||
def create_contact(self, email, name=None):
|
def create_contact(self, email, name=None):
|
||||||
""" create a (new) Contact. If there already is a Contact
|
""" create a (new) Contact. If there already is a Contact
|
||||||
with that e-mail address, it is unblocked and its name is
|
with that e-mail address, it is unblocked and its name is
|
||||||
@@ -212,7 +207,7 @@ class Account(object):
|
|||||||
assert isinstance(contact, int)
|
assert isinstance(contact, int)
|
||||||
contact_id = contact
|
contact_id = contact
|
||||||
chat_id = lib.dc_create_chat_by_contact_id(self._dc_context, contact_id)
|
chat_id = lib.dc_create_chat_by_contact_id(self._dc_context, contact_id)
|
||||||
return Chat(self._dc_context, chat_id)
|
return Chat(self, chat_id)
|
||||||
|
|
||||||
def create_chat_by_message(self, message):
|
def create_chat_by_message(self, message):
|
||||||
""" create or get an existing chat object for the
|
""" create or get an existing chat object for the
|
||||||
@@ -229,7 +224,7 @@ class Account(object):
|
|||||||
assert isinstance(message, int)
|
assert isinstance(message, int)
|
||||||
msg_id = message
|
msg_id = message
|
||||||
chat_id = lib.dc_create_chat_by_msg_id(self._dc_context, msg_id)
|
chat_id = lib.dc_create_chat_by_msg_id(self._dc_context, msg_id)
|
||||||
return Chat(self._dc_context, chat_id)
|
return Chat(self, chat_id)
|
||||||
|
|
||||||
def create_group_chat(self, name, verified=False):
|
def create_group_chat(self, name, verified=False):
|
||||||
""" create a new group chat object.
|
""" create a new group chat object.
|
||||||
@@ -241,7 +236,7 @@ class Account(object):
|
|||||||
"""
|
"""
|
||||||
bytes_name = name.encode("utf8")
|
bytes_name = name.encode("utf8")
|
||||||
chat_id = lib.dc_create_group_chat(self._dc_context, verified, bytes_name)
|
chat_id = lib.dc_create_group_chat(self._dc_context, verified, bytes_name)
|
||||||
return Chat(self._dc_context, chat_id)
|
return Chat(self, chat_id)
|
||||||
|
|
||||||
def get_chats(self):
|
def get_chats(self):
|
||||||
""" return list of chats.
|
""" return list of chats.
|
||||||
@@ -257,15 +252,15 @@ class Account(object):
|
|||||||
chatlist = []
|
chatlist = []
|
||||||
for i in range(0, lib.dc_chatlist_get_cnt(dc_chatlist)):
|
for i in range(0, lib.dc_chatlist_get_cnt(dc_chatlist)):
|
||||||
chat_id = lib.dc_chatlist_get_chat_id(dc_chatlist, i)
|
chat_id = lib.dc_chatlist_get_chat_id(dc_chatlist, i)
|
||||||
chatlist.append(Chat(self._dc_context, chat_id))
|
chatlist.append(Chat(self, chat_id))
|
||||||
return chatlist
|
return chatlist
|
||||||
|
|
||||||
def get_deaddrop_chat(self):
|
def get_deaddrop_chat(self):
|
||||||
return Chat(self._dc_context, const.DC_CHAT_ID_DEADDROP)
|
return Chat(self, const.DC_CHAT_ID_DEADDROP)
|
||||||
|
|
||||||
def get_message_by_id(self, msg_id):
|
def get_message_by_id(self, msg_id):
|
||||||
""" return Message instance. """
|
""" return Message instance. """
|
||||||
return Message.from_db(self._dc_context, msg_id)
|
return Message.from_db(self, msg_id)
|
||||||
|
|
||||||
def mark_seen_messages(self, messages):
|
def mark_seen_messages(self, messages):
|
||||||
""" mark the given set of messages as seen.
|
""" mark the given set of messages as seen.
|
||||||
|
|||||||
@@ -1,24 +1,30 @@
|
|||||||
""" chatting related objects: Contact, Chat, Message. """
|
""" chatting related objects: Contact, Chat, Message. """
|
||||||
|
|
||||||
import os
|
import mimetypes
|
||||||
|
|
||||||
from . import props
|
from . import props
|
||||||
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 . import const
|
from . import const
|
||||||
import attr
|
|
||||||
from attr import validators as v
|
|
||||||
from .message import Message
|
from .message import Message
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
|
||||||
class Contact(object):
|
class Contact(object):
|
||||||
""" Delta-Chat Contact.
|
""" Delta-Chat Contact.
|
||||||
|
|
||||||
You obtain instances of it through :class:`deltachat.account.Account`.
|
You obtain instances of it through :class:`deltachat.account.Account`.
|
||||||
"""
|
"""
|
||||||
_dc_context = attr.ib(validator=v.instance_of(ffi.CData))
|
def __init__(self, dc_context, id):
|
||||||
id = attr.ib(validator=v.instance_of(int))
|
self._dc_context = dc_context
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self._dc_context == other._dc_context and self.id == other.id
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not (self == other)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Contact id={} addr={} dc_context={}>".format(self.id, self.addr, self._dc_context)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _dc_contact(self):
|
def _dc_contact(self):
|
||||||
@@ -46,14 +52,26 @@ class Contact(object):
|
|||||||
return lib.dc_contact_is_verified(self._dc_contact)
|
return lib.dc_contact_is_verified(self._dc_contact)
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
|
||||||
class Chat(object):
|
class Chat(object):
|
||||||
""" Chat object which manages members and through which you can send and retrieve messages.
|
""" Chat object which manages members and through which you can send and retrieve messages.
|
||||||
|
|
||||||
You obtain instances of it through :class:`deltachat.account.Account`.
|
You obtain instances of it through :class:`deltachat.account.Account`.
|
||||||
"""
|
"""
|
||||||
_dc_context = attr.ib(validator=v.instance_of(ffi.CData))
|
|
||||||
id = attr.ib(validator=v.instance_of(int))
|
def __init__(self, account, id):
|
||||||
|
self.account = account
|
||||||
|
self._dc_context = account._dc_context
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.id == getattr(other, "id", None) and \
|
||||||
|
self._dc_context == getattr(other, "_dc_context", None)
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not (self == other)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Chat id={} name={} dc_context={}>".format(self.id, self.get_name(), self._dc_context)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _dc_chat(self):
|
def _dc_chat(self):
|
||||||
@@ -126,7 +144,7 @@ class Chat(object):
|
|||||||
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:
|
if msg_id == 0:
|
||||||
raise ValueError("message could not be send, does chat exist?")
|
raise ValueError("message could not be send, does chat exist?")
|
||||||
return Message.from_db(self._dc_context, msg_id)
|
return Message.from_db(self.account, msg_id)
|
||||||
|
|
||||||
def send_file(self, path, mime_type="application/octet-stream"):
|
def send_file(self, path, mime_type="application/octet-stream"):
|
||||||
""" send a file and return the resulting Message instance.
|
""" send a file and return the resulting Message instance.
|
||||||
@@ -136,14 +154,8 @@ class Chat(object):
|
|||||||
:raises ValueError: if message can not be send/chat does not exist.
|
:raises ValueError: if message can not be send/chat does not exist.
|
||||||
:returns: the resulting :class:`deltachat.message.Message` instance
|
:returns: the resulting :class:`deltachat.message.Message` instance
|
||||||
"""
|
"""
|
||||||
path = as_dc_charpointer(path)
|
msg = self.prepare_message_file(path=path, mime_type=mime_type)
|
||||||
mtype = as_dc_charpointer(mime_type)
|
return self.send_prepared(msg)
|
||||||
msg = Message.new(self._dc_context, "file")
|
|
||||||
msg.set_file(path, mtype)
|
|
||||||
msg_id = lib.dc_send_msg(self._dc_context, self.id, msg._dc_msg)
|
|
||||||
if msg_id == 0:
|
|
||||||
raise ValueError("message could not be send, does chat exist?")
|
|
||||||
return Message.from_db(self._dc_context, msg_id)
|
|
||||||
|
|
||||||
def send_image(self, path):
|
def send_image(self, path):
|
||||||
""" send an image message and return the resulting Message instance.
|
""" send an image message and return the resulting Message instance.
|
||||||
@@ -152,14 +164,22 @@ class Chat(object):
|
|||||||
:raises ValueError: if message can not be send/chat does not exist.
|
:raises ValueError: if message can not be send/chat does not exist.
|
||||||
:returns: the resulting :class:`deltachat.message.Message` instance
|
:returns: the resulting :class:`deltachat.message.Message` instance
|
||||||
"""
|
"""
|
||||||
if not os.path.exists(path):
|
mime_type = mimetypes.guess_type(path)[0]
|
||||||
raise ValueError("path does not exist: {!r}".format(path))
|
msg = self.prepare_message_file(path=path, mime_type=mime_type, view_type="image")
|
||||||
msg = Message.new(self._dc_context, "image")
|
return self.send_prepared(msg)
|
||||||
msg.set_file(path)
|
|
||||||
msg_id = lib.dc_send_msg(self._dc_context, self.id, msg._dc_msg)
|
|
||||||
return Message.from_db(self._dc_context, msg_id)
|
|
||||||
|
|
||||||
def prepare_file(self, path, mime_type=None, view_type="file"):
|
def prepare_message(self, msg):
|
||||||
|
""" create a new message.
|
||||||
|
|
||||||
|
:param msg: the message to be prepared.
|
||||||
|
:returns: :class:`deltachat.message.Message` instance.
|
||||||
|
"""
|
||||||
|
msg_id = lib.dc_prepare_msg(self._dc_context, self.id, msg._dc_msg)
|
||||||
|
if msg_id == 0:
|
||||||
|
raise ValueError("message could not be prepared")
|
||||||
|
return Message.from_db(self.account, msg_id)
|
||||||
|
|
||||||
|
def prepare_message_file(self, path, mime_type=None, view_type="file"):
|
||||||
""" prepare a message for sending and return the resulting Message instance.
|
""" prepare a message for sending and return the resulting Message instance.
|
||||||
|
|
||||||
To actually send the message, call :meth:`send_prepared`.
|
To actually send the message, call :meth:`send_prepared`.
|
||||||
@@ -171,14 +191,9 @@ class Chat(object):
|
|||||||
:raises ValueError: if message can not be prepared/chat does not exist.
|
:raises ValueError: if message can not be prepared/chat does not exist.
|
||||||
:returns: the resulting :class:`Message` instance
|
:returns: the resulting :class:`Message` instance
|
||||||
"""
|
"""
|
||||||
path = as_dc_charpointer(path)
|
msg = Message.new(self.account, view_type)
|
||||||
mtype = as_dc_charpointer(mime_type)
|
msg.set_file(path, mime_type)
|
||||||
msg = Message.new(self._dc_context, view_type)
|
return self.prepare_message(msg)
|
||||||
msg.set_file(path, mtype)
|
|
||||||
msg_id = lib.dc_prepare_msg(self._dc_context, self.id, msg._dc_msg)
|
|
||||||
if msg_id == 0:
|
|
||||||
raise ValueError("message could not be prepared, does chat exist?")
|
|
||||||
return Message.from_db(self._dc_context, msg_id)
|
|
||||||
|
|
||||||
def send_prepared(self, message):
|
def send_prepared(self, message):
|
||||||
""" send a previously prepared message.
|
""" send a previously prepared message.
|
||||||
@@ -191,7 +206,30 @@ class Chat(object):
|
|||||||
msg_id = lib.dc_send_msg(self._dc_context, 0, message._dc_msg)
|
msg_id = lib.dc_send_msg(self._dc_context, 0, message._dc_msg)
|
||||||
if msg_id == 0:
|
if msg_id == 0:
|
||||||
raise ValueError("message could not be sent")
|
raise ValueError("message could not be sent")
|
||||||
return Message.from_db(self._dc_context, msg_id)
|
return Message.from_db(self.account, msg_id)
|
||||||
|
|
||||||
|
def set_draft(self, message):
|
||||||
|
""" set message as draft.
|
||||||
|
|
||||||
|
:param message: a :class:`Message` instance
|
||||||
|
:returns: None
|
||||||
|
"""
|
||||||
|
if message is None:
|
||||||
|
lib.dc_set_draft(self._dc_context, self.id, ffi.NULL)
|
||||||
|
else:
|
||||||
|
lib.dc_set_draft(self._dc_context, self.id, message._dc_msg)
|
||||||
|
|
||||||
|
def get_draft(self):
|
||||||
|
""" get draft message for this chat.
|
||||||
|
|
||||||
|
:param message: a :class:`Message` instance
|
||||||
|
:returns: Message object or None (if no draft available)
|
||||||
|
"""
|
||||||
|
x = lib.dc_get_draft(self._dc_context, self.id)
|
||||||
|
if x == ffi.NULL:
|
||||||
|
return None
|
||||||
|
dc_msg = ffi.gc(x, lib.dc_msg_unref)
|
||||||
|
return Message.from_dc_msg(self.account, dc_msg)
|
||||||
|
|
||||||
def get_messages(self):
|
def get_messages(self):
|
||||||
""" return list of messages in this chat.
|
""" return list of messages in this chat.
|
||||||
@@ -202,7 +240,7 @@ class Chat(object):
|
|||||||
lib.dc_get_chat_msgs(self._dc_context, self.id, 0, 0),
|
lib.dc_get_chat_msgs(self._dc_context, self.id, 0, 0),
|
||||||
lib.dc_array_unref
|
lib.dc_array_unref
|
||||||
)
|
)
|
||||||
return list(iter_array(dc_array, lambda x: Message.from_db(self._dc_context, x)))
|
return list(iter_array(dc_array, lambda x: Message.from_db(self.account, x)))
|
||||||
|
|
||||||
def count_fresh_messages(self):
|
def count_fresh_messages(self):
|
||||||
""" return number of fresh messages in this chat.
|
""" return number of fresh messages in this chat.
|
||||||
|
|||||||
@@ -1,46 +1,64 @@
|
|||||||
""" chatting related objects: Contact, Chat, Message. """
|
""" chatting related objects: Contact, Chat, Message. """
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
from . import props
|
from . import props
|
||||||
from .cutil import from_dc_charpointer, as_dc_charpointer
|
from .cutil import from_dc_charpointer, as_dc_charpointer
|
||||||
from .capi import lib, ffi
|
from .capi import lib, ffi
|
||||||
from . import const
|
from . import const
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import attr
|
|
||||||
from attr import validators as v
|
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
|
||||||
class Message(object):
|
class Message(object):
|
||||||
""" Message object.
|
""" Message object.
|
||||||
|
|
||||||
You obtain instances of it through :class:`deltachat.account.Account` or
|
You obtain instances of it through :class:`deltachat.account.Account` or
|
||||||
:class:`deltachat.chatting.Chat`.
|
:class:`deltachat.chatting.Chat`.
|
||||||
"""
|
"""
|
||||||
_dc_context = attr.ib(validator=v.instance_of(ffi.CData))
|
def __init__(self, account, id=None, dc_msg=None):
|
||||||
try:
|
self.account = account
|
||||||
id = attr.ib(validator=v.instance_of((int, long)))
|
self._dc_context = account._dc_context
|
||||||
except NameError: # py35
|
if dc_msg is not None:
|
||||||
id = attr.ib(validator=v.instance_of(int))
|
self._cache_dc_msg = self._dc_msg_volatile = dc_msg
|
||||||
|
id = lib.dc_msg_get_id(dc_msg)
|
||||||
|
assert id is not None
|
||||||
|
self.id = id
|
||||||
|
assert isinstance(self._dc_context, ffi.CData)
|
||||||
|
assert int(id) >= 0
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.account == other.account and self.id == other.id
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<Message id={} dc_context={}>".format(self.id, self._dc_context)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _dc_msg(self):
|
def _dc_msg(self):
|
||||||
if self.id > 0:
|
if self.id > 0:
|
||||||
return ffi.gc(
|
if not hasattr(self, "_cache_dc_msg"):
|
||||||
lib.dc_get_msg(self._dc_context, self.id),
|
self._cache_dc_msg = ffi.gc(
|
||||||
lib.dc_msg_unref
|
lib.dc_get_msg(self._dc_context, self.id),
|
||||||
)
|
lib.dc_msg_unref
|
||||||
|
)
|
||||||
|
return self._cache_dc_msg
|
||||||
return self._dc_msg_volatile
|
return self._dc_msg_volatile
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_db(cls, _dc_context, id):
|
def from_db(cls, account, id):
|
||||||
|
assert hasattr(account, "_dc_context")
|
||||||
assert id > 0
|
assert id > 0
|
||||||
return cls(_dc_context, id)
|
return cls(account, id)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new(cls, dc_context, view_type):
|
def from_dc_msg(cls, account, dc_msg):
|
||||||
""" create a non-persistent method. """
|
assert hasattr(account, "_dc_context")
|
||||||
msg = cls(dc_context, 0)
|
return cls(account, dc_msg=dc_msg)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def new(cls, account, view_type):
|
||||||
|
""" create a non-persistent message. """
|
||||||
|
dc_context = account._dc_context
|
||||||
|
msg = cls(account=account, id=0)
|
||||||
view_type_code = MessageType.get_typecode(view_type)
|
view_type_code = MessageType.get_typecode(view_type)
|
||||||
msg._dc_msg_volatile = ffi.gc(
|
msg._dc_msg_volatile = ffi.gc(
|
||||||
lib.dc_msg_new(dc_context, view_type_code),
|
lib.dc_msg_new(dc_context, view_type_code),
|
||||||
@@ -62,7 +80,9 @@ class Message(object):
|
|||||||
|
|
||||||
def set_text(self, text):
|
def set_text(self, text):
|
||||||
"""set text of this message. """
|
"""set text of this message. """
|
||||||
return lib.dc_msg_set_text(self._dc_msg, as_dc_charpointer(text))
|
assert self.id > 0, "message not prepared"
|
||||||
|
assert self.get_state().is_out_preparing()
|
||||||
|
lib.dc_msg_set_text(self._dc_msg, as_dc_charpointer(text))
|
||||||
|
|
||||||
@props.with_doc
|
@props.with_doc
|
||||||
def filename(self):
|
def filename(self):
|
||||||
@@ -70,9 +90,23 @@ class Message(object):
|
|||||||
return from_dc_charpointer(lib.dc_msg_get_file(self._dc_msg))
|
return from_dc_charpointer(lib.dc_msg_get_file(self._dc_msg))
|
||||||
|
|
||||||
def set_file(self, path, mime_type=None):
|
def set_file(self, path, mime_type=None):
|
||||||
"""set file for this message. """
|
"""set file for this message from path and mime_type. """
|
||||||
mtype = ffi.NULL if mime_type is None else mime_type
|
mtype = ffi.NULL if mime_type is None else as_dc_charpointer(mime_type)
|
||||||
assert os.path.exists(path)
|
if not os.path.exists(path):
|
||||||
|
raise ValueError("path does not exist: {!r}".format(path))
|
||||||
|
blobdir = self.account.get_blob_dir()
|
||||||
|
if not path.startswith(blobdir):
|
||||||
|
for i in range(50):
|
||||||
|
ext = "" if i == 0 else "-" + str(i)
|
||||||
|
dest = os.path.join(blobdir, os.path.basename(path) + ext)
|
||||||
|
if os.path.exists(dest):
|
||||||
|
continue
|
||||||
|
shutil.copyfile(path, dest)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError("could not create blobdir-path for {}".format(path))
|
||||||
|
path = dest
|
||||||
|
assert path.startswith(blobdir), path
|
||||||
lib.dc_msg_set_file(self._dc_msg, as_dc_charpointer(path), mtype)
|
lib.dc_msg_set_file(self._dc_msg, as_dc_charpointer(path), mtype)
|
||||||
|
|
||||||
@props.with_doc
|
@props.with_doc
|
||||||
@@ -91,12 +125,20 @@ class Message(object):
|
|||||||
|
|
||||||
:returns: a :class:`deltachat.message.MessageType` instance.
|
:returns: a :class:`deltachat.message.MessageType` instance.
|
||||||
"""
|
"""
|
||||||
|
assert self.id > 0
|
||||||
return MessageType(lib.dc_msg_get_viewtype(self._dc_msg))
|
return MessageType(lib.dc_msg_get_viewtype(self._dc_msg))
|
||||||
|
|
||||||
def is_setup_message(self):
|
def is_setup_message(self):
|
||||||
""" return True if this message is a setup message. """
|
""" return True if this message is a setup message. """
|
||||||
return lib.dc_msg_is_setupmessage(self._dc_msg)
|
return lib.dc_msg_is_setupmessage(self._dc_msg)
|
||||||
|
|
||||||
|
def get_message_info(self):
|
||||||
|
""" Return informational text for a single message.
|
||||||
|
|
||||||
|
The text is multiline and may contain eg. the raw text of the message.
|
||||||
|
"""
|
||||||
|
return from_dc_charpointer(lib.dc_get_msg_info(self._dc_context, self.id))
|
||||||
|
|
||||||
def continue_key_transfer(self, setup_code):
|
def continue_key_transfer(self, setup_code):
|
||||||
""" extract key and use it as primary key for this account. """
|
""" extract key and use it as primary key for this account. """
|
||||||
lib.dc_continue_key_transfer(self._dc_context, self.id, as_dc_charpointer(setup_code))
|
lib.dc_continue_key_transfer(self._dc_context, self.id, as_dc_charpointer(setup_code))
|
||||||
@@ -144,7 +186,7 @@ class Message(object):
|
|||||||
"""
|
"""
|
||||||
from .chatting import Chat
|
from .chatting import Chat
|
||||||
chat_id = lib.dc_msg_get_chat_id(self._dc_msg)
|
chat_id = lib.dc_msg_get_chat_id(self._dc_msg)
|
||||||
return Chat(self._dc_context, chat_id)
|
return Chat(self.account, chat_id)
|
||||||
|
|
||||||
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.
|
||||||
@@ -156,10 +198,8 @@ class Message(object):
|
|||||||
return Contact(self._dc_context, contact_id)
|
return Contact(self._dc_context, contact_id)
|
||||||
|
|
||||||
|
|
||||||
@attr.s
|
|
||||||
class MessageType(object):
|
class MessageType(object):
|
||||||
""" DeltaChat message type, with is_* methods. """
|
""" DeltaChat message type, with is_* methods. """
|
||||||
_type = attr.ib(validator=v.instance_of(int))
|
|
||||||
_mapping = {
|
_mapping = {
|
||||||
const.DC_MSG_TEXT: 'text',
|
const.DC_MSG_TEXT: 'text',
|
||||||
const.DC_MSG_IMAGE: 'image',
|
const.DC_MSG_IMAGE: 'image',
|
||||||
@@ -169,6 +209,12 @@ class MessageType(object):
|
|||||||
const.DC_MSG_FILE: 'file'
|
const.DC_MSG_FILE: 'file'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self, _type):
|
||||||
|
self._type = _type
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self._type == getattr(other, "_type", None)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_typecode(cls, view_type):
|
def get_typecode(cls, view_type):
|
||||||
for code, value in cls._mapping.items():
|
for code, value in cls._mapping.items():
|
||||||
@@ -206,15 +252,24 @@ class MessageType(object):
|
|||||||
return self._type == const.DC_MSG_FILE
|
return self._type == const.DC_MSG_FILE
|
||||||
|
|
||||||
|
|
||||||
@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.
|
||||||
"""
|
"""
|
||||||
message = attr.ib(validator=v.instance_of(Message))
|
def __init__(self, message):
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.message == getattr(other, "message", None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _msgstate(self):
|
def _msgstate(self):
|
||||||
return lib.dc_msg_get_state(self.message._dc_msg)
|
if self.message.id == 0:
|
||||||
|
return lib.dc_msg_get_state(self.message._dc_msg)
|
||||||
|
dc_msg = ffi.gc(
|
||||||
|
lib.dc_get_msg(self.message._dc_context, self.message.id),
|
||||||
|
lib.dc_msg_unref
|
||||||
|
)
|
||||||
|
return lib.dc_msg_get_state(dc_msg)
|
||||||
|
|
||||||
def is_in_fresh(self):
|
def is_in_fresh(self):
|
||||||
""" return True if Message is incoming fresh message (un-noticed).
|
""" return True if Message is incoming fresh message (un-noticed).
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ from __future__ import print_function
|
|||||||
import pytest
|
import pytest
|
||||||
import os
|
import os
|
||||||
from deltachat import const, Account
|
from deltachat import const, Account
|
||||||
|
from deltachat.message import Message
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
class TestOfflineAccount:
|
class TestOfflineAccountBasic:
|
||||||
def test_wrong_db(self, tmpdir):
|
def test_wrong_db(self, tmpdir):
|
||||||
p = tmpdir.join("hello.db")
|
p = tmpdir.join("hello.db")
|
||||||
p.write("123")
|
p.write("123")
|
||||||
@@ -57,9 +58,15 @@ class TestOfflineAccount:
|
|||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
ac1.get_config("123123")
|
ac1.get_config("123123")
|
||||||
|
|
||||||
|
|
||||||
|
class TestOfflineContact:
|
||||||
def test_contact_attr(self, acfactory):
|
def test_contact_attr(self, acfactory):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
ac1 = acfactory.get_configured_offline_account()
|
||||||
contact1 = ac1.create_contact(email="some1@hello.com", name="some1")
|
contact1 = ac1.create_contact(email="some1@hello.com", name="some1")
|
||||||
|
contact2 = ac1.create_contact(email="some1@hello.com", name="some1")
|
||||||
|
str(contact1)
|
||||||
|
repr(contact1)
|
||||||
|
assert contact1 == contact2
|
||||||
assert contact1.id
|
assert contact1.id
|
||||||
assert contact1.addr == "some1@hello.com"
|
assert contact1.addr == "some1@hello.com"
|
||||||
assert contact1.display_name == "some1"
|
assert contact1.display_name == "some1"
|
||||||
@@ -89,26 +96,38 @@ class TestOfflineAccount:
|
|||||||
chat.send_text("one messae")
|
chat.send_text("one messae")
|
||||||
assert not ac1.delete_contact(contact1)
|
assert not ac1.delete_contact(contact1)
|
||||||
|
|
||||||
def test_chat(self, acfactory):
|
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
class TestOfflineChat:
|
||||||
|
@pytest.fixture
|
||||||
|
def ac1(self, acfactory):
|
||||||
|
return acfactory.get_configured_offline_account()
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def chat1(self, ac1):
|
||||||
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)
|
||||||
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL, chat.id
|
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL, chat.id
|
||||||
|
return chat
|
||||||
|
|
||||||
|
def test_display(self, chat1):
|
||||||
|
str(chat1)
|
||||||
|
repr(chat1)
|
||||||
|
|
||||||
|
def test_chat_idempotent(self, chat1, ac1):
|
||||||
|
contact1 = chat1.get_contacts()[0]
|
||||||
chat2 = ac1.create_chat_by_contact(contact1.id)
|
chat2 = ac1.create_chat_by_contact(contact1.id)
|
||||||
assert chat2.id == chat.id
|
assert chat2.id == chat1.id
|
||||||
assert chat2.get_name() == chat.get_name()
|
assert chat2.get_name() == chat1.get_name()
|
||||||
assert chat == chat2
|
assert chat1 == chat2
|
||||||
assert not (chat != chat2)
|
assert not (chat1 != chat2)
|
||||||
|
|
||||||
for ichat in ac1.get_chats():
|
for ichat in ac1.get_chats():
|
||||||
if ichat.id == chat.id:
|
if ichat.id == chat1.id:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
pytest.fail("could not find chat")
|
pytest.fail("could not find chat")
|
||||||
|
|
||||||
def test_group_chat_creation(self, acfactory):
|
def test_group_chat_creation(self, ac1):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
|
||||||
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
||||||
contact2 = ac1.create_contact("some2@hello.com", name="some2")
|
contact2 = ac1.create_contact("some2@hello.com", name="some2")
|
||||||
chat = ac1.create_group_chat(name="title1")
|
chat = ac1.create_group_chat(name="title1")
|
||||||
@@ -121,29 +140,46 @@ 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):
|
def test_delete_and_send_fails(self, ac1, chat1):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
chat1.delete()
|
||||||
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")
|
ac1._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
chat.send_text("msg1")
|
chat1.send_text("msg1")
|
||||||
|
|
||||||
def test_create_message(self, acfactory):
|
def test_prepare_message_and_send(self, ac1, chat1):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
msg = chat1.prepare_message(Message.new(chat1.account, "text"))
|
||||||
message = ac1.create_message("text")
|
msg.set_text("hello world")
|
||||||
assert message.id == 0
|
assert msg.text == "hello world"
|
||||||
assert message._dc_msg is message._dc_msg
|
assert msg.id > 0
|
||||||
message.set_text("hello")
|
msg = chat1.send_prepared(msg)
|
||||||
assert message.text == "hello"
|
assert "Sent" in msg.get_message_info()
|
||||||
assert message.id == 0
|
str(msg)
|
||||||
|
repr(msg)
|
||||||
|
assert msg == ac1.get_message_by_id(msg.id)
|
||||||
|
|
||||||
def test_message(self, acfactory):
|
def test_prepare_file(self, ac1, chat1):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
blobdir = ac1.get_blob_dir()
|
||||||
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
p = os.path.join(blobdir, "somedata.txt")
|
||||||
chat = ac1.create_chat_by_contact(contact1)
|
with open(p, "w") as f:
|
||||||
msg = chat.send_text("msg1")
|
f.write("some data")
|
||||||
|
message = chat1.prepare_message_file(p)
|
||||||
|
assert message.id > 0
|
||||||
|
message.set_text("hello world")
|
||||||
|
assert message.get_state().is_out_preparing()
|
||||||
|
assert message.text == "hello world"
|
||||||
|
msg = chat1.send_prepared(message)
|
||||||
|
s = msg.get_message_info()
|
||||||
|
assert "Sent" in s
|
||||||
|
|
||||||
|
def test_message_eq_contains(self, chat1):
|
||||||
|
msg = chat1.send_text("msg1")
|
||||||
|
assert msg in chat1.get_messages()
|
||||||
|
assert not (msg not in chat1.get_messages())
|
||||||
|
str(msg)
|
||||||
|
repr(msg)
|
||||||
|
|
||||||
|
def test_message_send_text(self, chat1):
|
||||||
|
msg = chat1.send_text("msg1")
|
||||||
assert msg
|
assert msg
|
||||||
assert msg.view_type.is_text()
|
assert msg.view_type.is_text()
|
||||||
assert msg.view_type.name == "text"
|
assert msg.view_type.name == "text"
|
||||||
@@ -161,23 +197,17 @@ 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_create_chat_by_mssage_id(self, acfactory):
|
def test_create_chat_by_message_id(self, ac1, chat1):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
msg = chat1.send_text("msg1")
|
||||||
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
assert chat1 == ac1.create_chat_by_message(msg)
|
||||||
chat = ac1.create_chat_by_contact(contact1)
|
assert chat1 == ac1.create_chat_by_message(msg.id)
|
||||||
msg = chat.send_text("msg1")
|
|
||||||
assert chat == ac1.create_chat_by_message(msg)
|
|
||||||
assert chat == ac1.create_chat_by_message(msg.id)
|
|
||||||
|
|
||||||
def test_message_image(self, acfactory, data, lp):
|
def test_message_image(self, chat1, data, lp):
|
||||||
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):
|
with pytest.raises(ValueError):
|
||||||
chat.send_image(path="notexists")
|
chat1.send_image(path="notexists")
|
||||||
fn = data.get_path("d.png")
|
fn = data.get_path("d.png")
|
||||||
lp.sec("sending image")
|
lp.sec("sending image")
|
||||||
msg = chat.send_image(fn)
|
msg = chat1.send_image(fn)
|
||||||
assert msg.view_type.name == "image"
|
assert msg.view_type.name == "image"
|
||||||
assert msg
|
assert msg
|
||||||
assert msg.id > 0
|
assert msg.id > 0
|
||||||
@@ -189,13 +219,10 @@ class TestOfflineAccount:
|
|||||||
("text/plain", "text/plain"),
|
("text/plain", "text/plain"),
|
||||||
("image/png", "image/png"),
|
("image/png", "image/png"),
|
||||||
])
|
])
|
||||||
def test_message_file(self, acfactory, data, lp, typein, typeout):
|
def test_message_file(self, ac1, chat1, data, lp, typein, typeout):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
|
||||||
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
|
||||||
chat = ac1.create_chat_by_contact(contact1)
|
|
||||||
lp.sec("sending file")
|
lp.sec("sending file")
|
||||||
fn = data.get_path("r.txt")
|
fn = data.get_path("r.txt")
|
||||||
msg = chat.send_file(fn, typein)
|
msg = chat1.send_file(fn, typein)
|
||||||
assert msg
|
assert msg
|
||||||
assert msg.id > 0
|
assert msg.id > 0
|
||||||
assert msg.view_type.name == "file"
|
assert msg.view_type.name == "file"
|
||||||
@@ -203,6 +230,9 @@ class TestOfflineAccount:
|
|||||||
assert os.path.exists(msg.filename)
|
assert os.path.exists(msg.filename)
|
||||||
assert msg.filename.endswith(msg.basename)
|
assert msg.filename.endswith(msg.basename)
|
||||||
assert msg.filemime == typeout
|
assert msg.filemime == typeout
|
||||||
|
msg2 = chat1.send_file(fn, typein)
|
||||||
|
assert msg2 != msg
|
||||||
|
assert msg2.filename != msg.filename
|
||||||
|
|
||||||
def test_create_chat_mismatch(self, acfactory):
|
def test_create_chat_mismatch(self, acfactory):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
ac1 = acfactory.get_configured_offline_account()
|
||||||
@@ -215,12 +245,9 @@ class TestOfflineAccount:
|
|||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
ac2.create_chat_by_message(msg)
|
ac2.create_chat_by_message(msg)
|
||||||
|
|
||||||
def test_chat_message_distinctions(self, acfactory):
|
def test_chat_message_distinctions(self, ac1, chat1):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
|
||||||
contact1 = ac1.create_contact("some1@hello.com", name="some1")
|
|
||||||
chat = ac1.create_chat_by_contact(contact1)
|
|
||||||
past1s = datetime.utcnow() - timedelta(seconds=1)
|
past1s = datetime.utcnow() - timedelta(seconds=1)
|
||||||
msg = chat.send_text("msg1")
|
msg = chat1.send_text("msg1")
|
||||||
ts = msg.time_sent
|
ts = msg.time_sent
|
||||||
assert msg.time_received is None
|
assert msg.time_received is None
|
||||||
assert ts.strftime("Y")
|
assert ts.strftime("Y")
|
||||||
@@ -228,8 +255,7 @@ class TestOfflineAccount:
|
|||||||
contact = msg.get_sender_contact()
|
contact = msg.get_sender_contact()
|
||||||
assert contact == ac1.get_self_contact()
|
assert contact == ac1.get_self_contact()
|
||||||
|
|
||||||
def test_basic_configure_ok_addr_setting_forbidden(self, acfactory):
|
def test_basic_configure_ok_addr_setting_forbidden(self, ac1):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
|
||||||
assert ac1.get_config("mail_pw")
|
assert ac1.get_config("mail_pw")
|
||||||
assert ac1.is_configured()
|
assert ac1.is_configured()
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ValueError):
|
||||||
@@ -268,11 +294,21 @@ class TestOfflineAccount:
|
|||||||
assert messages[0].text == "msg1"
|
assert messages[0].text == "msg1"
|
||||||
assert os.path.exists(messages[1].filename)
|
assert os.path.exists(messages[1].filename)
|
||||||
|
|
||||||
def test_ac_setup_message_fails(self, acfactory):
|
def test_ac_setup_message_fails(self, ac1):
|
||||||
ac1 = acfactory.get_configured_offline_account()
|
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
ac1.initiate_key_transfer()
|
ac1.initiate_key_transfer()
|
||||||
|
|
||||||
|
def test_set_get_draft(self, chat1):
|
||||||
|
msg = Message.new(chat1.account, "text")
|
||||||
|
msg1 = chat1.prepare_message(msg)
|
||||||
|
msg1.set_text("hello")
|
||||||
|
chat1.set_draft(msg1)
|
||||||
|
msg1.set_text("obsolete")
|
||||||
|
msg2 = chat1.get_draft()
|
||||||
|
assert msg2.text == "hello"
|
||||||
|
chat1.set_draft(None)
|
||||||
|
assert chat1.get_draft() is None
|
||||||
|
|
||||||
|
|
||||||
class TestOnlineAccount:
|
class TestOnlineAccount:
|
||||||
def test_one_account_init(self, acfactory):
|
def test_one_account_init(self, acfactory):
|
||||||
@@ -293,7 +329,7 @@ class TestOnlineAccount:
|
|||||||
ev = ac1._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
ev = ac1._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
||||||
assert ev[1] == msg_out.id
|
assert ev[1] == msg_out.id
|
||||||
|
|
||||||
def test_two_acocunts_send_receive(self, acfactory):
|
def test_two_accounts_send_receive(self, acfactory):
|
||||||
ac1 = acfactory.get_online_configuring_account()
|
ac1 = acfactory.get_online_configuring_account()
|
||||||
ac2 = acfactory.get_online_configuring_account()
|
ac2 = acfactory.get_online_configuring_account()
|
||||||
c2 = ac1.create_contact(email=ac2.get_config("addr"))
|
c2 = ac1.create_contact(email=ac2.get_config("addr"))
|
||||||
@@ -390,7 +426,6 @@ class TestOnlineAccount:
|
|||||||
lp.step("1")
|
lp.step("1")
|
||||||
ac1._evlogger.get_matching("DC_EVENT_MSG_READ")
|
ac1._evlogger.get_matching("DC_EVENT_MSG_READ")
|
||||||
lp.step("2")
|
lp.step("2")
|
||||||
# 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_saved_mime_on_received_message(self, acfactory, lp):
|
def test_saved_mime_on_received_message(self, acfactory, lp):
|
||||||
@@ -473,7 +508,7 @@ class TestOnlineAccount:
|
|||||||
wait_configuration_progress(ac1, 1000)
|
wait_configuration_progress(ac1, 1000)
|
||||||
assert ac1.get_info()["fingerprint"] != ac2.get_info()["fingerprint"]
|
assert ac1.get_info()["fingerprint"] != ac2.get_info()["fingerprint"]
|
||||||
setup_code = ac1.initiate_key_transfer()
|
setup_code = ac1.initiate_key_transfer()
|
||||||
ac2._evlogger.set_timeout(10)
|
ac2._evlogger.set_timeout(30)
|
||||||
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG|DC_EVENT_MSGS_CHANGED")
|
||||||
msg = ac2.get_message_by_id(ev[2])
|
msg = ac2.get_message_by_id(ev[2])
|
||||||
assert msg.is_setup_message()
|
assert msg.is_setup_message()
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
from filecmp import cmp
|
from filecmp import cmp
|
||||||
from deltachat import const
|
from deltachat import const
|
||||||
from conftest import wait_configuration_progress, wait_msgs_changed
|
from conftest import wait_configuration_progress, wait_msgs_changed
|
||||||
@@ -13,17 +11,14 @@ class TestInCreation:
|
|||||||
wait_configuration_progress(ac1, 1000)
|
wait_configuration_progress(ac1, 1000)
|
||||||
wait_configuration_progress(ac2, 1000)
|
wait_configuration_progress(ac2, 1000)
|
||||||
|
|
||||||
blobdir = ac1.get_blobdir()
|
|
||||||
|
|
||||||
c2 = ac1.create_contact(email=ac2.get_config("addr"))
|
c2 = ac1.create_contact(email=ac2.get_config("addr"))
|
||||||
chat = ac1.create_chat_by_contact(c2)
|
chat = ac1.create_chat_by_contact(c2)
|
||||||
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
|
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||||
wait_msgs_changed(ac1, 0, 0) # why no chat id?
|
wait_msgs_changed(ac1, 0, 0) # why no chat id?
|
||||||
|
|
||||||
lp.sec("create a message with a file in creation")
|
lp.sec("create a message with a file in creation")
|
||||||
path = os.path.join(blobdir, "d.png")
|
path = data.get_path("d.png")
|
||||||
open(path, 'a').close()
|
prepared_original = chat.prepare_message_file(path)
|
||||||
prepared_original = chat.prepare_file(path)
|
|
||||||
assert prepared_original.get_state().is_out_preparing()
|
assert prepared_original.get_state().is_out_preparing()
|
||||||
wait_msgs_changed(ac1, chat.id, prepared_original.id)
|
wait_msgs_changed(ac1, chat.id, prepared_original.id)
|
||||||
|
|
||||||
@@ -37,11 +32,11 @@ class TestInCreation:
|
|||||||
forwarded_id = wait_msgs_changed(ac1, chat2.id)
|
forwarded_id = wait_msgs_changed(ac1, chat2.id)
|
||||||
if forwarded_id == 0:
|
if forwarded_id == 0:
|
||||||
forwarded_id = wait_msgs_changed(ac1, chat2.id)
|
forwarded_id = wait_msgs_changed(ac1, chat2.id)
|
||||||
|
assert forwarded_id
|
||||||
forwarded_msg = ac1.get_message_by_id(forwarded_id)
|
forwarded_msg = ac1.get_message_by_id(forwarded_id)
|
||||||
assert forwarded_msg.get_state().is_out_preparing()
|
assert forwarded_msg.get_state().is_out_preparing()
|
||||||
|
|
||||||
lp.sec("finish creating the file and send it")
|
lp.sec("finish creating the file and send it")
|
||||||
shutil.copy(data.get_path("d.png"), path)
|
|
||||||
sent_original = chat.send_prepared(prepared_original)
|
sent_original = chat.send_prepared(prepared_original)
|
||||||
assert sent_original.id == prepared_original.id
|
assert sent_original.id == prepared_original.id
|
||||||
state = sent_original.get_state()
|
state = sent_original.get_state()
|
||||||
@@ -61,11 +56,13 @@ class TestInCreation:
|
|||||||
assert ev[1] == chat2.id
|
assert ev[1] == chat2.id
|
||||||
assert ev[2] == forwarded_id
|
assert ev[2] == forwarded_id
|
||||||
|
|
||||||
lp.sec("wait for both messages to arrive")
|
lp.sec("wait1 for original or forwarded messages to arrive")
|
||||||
ev1 = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
ev1 = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||||
assert ev1[1] >= const.DC_CHAT_ID_LAST_SPECIAL
|
assert ev1[1] >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||||
received_original = ac2.get_message_by_id(ev1[2])
|
received_original = ac2.get_message_by_id(ev1[2])
|
||||||
assert cmp(received_original.filename, path, False)
|
assert cmp(received_original.filename, path, False)
|
||||||
|
|
||||||
|
lp.sec("wait2 for original or forwarded messages to arrive")
|
||||||
ev2 = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
ev2 = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||||
assert ev2[1] >= const.DC_CHAT_ID_LAST_SPECIAL
|
assert ev2[1] >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||||
assert ev2[1] != ev1[1]
|
assert ev2[1] != ev1[1]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ envlist =
|
|||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
commands =
|
commands =
|
||||||
pytest -rsXx {posargs:tests}
|
pytest -v -rsXx {posargs:tests}
|
||||||
python tests/package_wheels.py {toxworkdir}/wheelhouse
|
python tests/package_wheels.py {toxworkdir}/wheelhouse
|
||||||
passenv =
|
passenv =
|
||||||
TRAVIS
|
TRAVIS
|
||||||
|
|||||||
Reference in New Issue
Block a user