mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
add profile image API to python, tests, Rust fixes/cleanups
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
""" chatting related objects: Contact, Chat, Message. """
|
""" chatting related objects: Contact, Chat, Message. """
|
||||||
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
import os
|
||||||
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
|
||||||
@@ -315,3 +316,46 @@ class Chat(object):
|
|||||||
return list(iter_array(
|
return list(iter_array(
|
||||||
dc_array, lambda id: Contact(self._dc_context, id))
|
dc_array, lambda id: Contact(self._dc_context, id))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def set_profile_image(self, img_path):
|
||||||
|
"""Set group profile image.
|
||||||
|
|
||||||
|
If the group is already promoted (any message was sent to the group),
|
||||||
|
all group members are informed by a special status message that is sent
|
||||||
|
automatically by this function.
|
||||||
|
:params img_path: path to image object
|
||||||
|
:raises ValueError: if profile image could not be set
|
||||||
|
:returns: None
|
||||||
|
"""
|
||||||
|
assert os.path.exists(img_path), img_path
|
||||||
|
p = as_dc_charpointer(img_path)
|
||||||
|
res = lib.dc_set_chat_profile_image(self._dc_context, self.id, p)
|
||||||
|
if res != 1:
|
||||||
|
raise ValueError("Setting Profile Image {!r} failed".format(p))
|
||||||
|
|
||||||
|
def remove_profile_image(self):
|
||||||
|
"""remove group profile image.
|
||||||
|
|
||||||
|
If the group is already promoted (any message was sent to the group),
|
||||||
|
all group members are informed by a special status message that is sent
|
||||||
|
automatically by this function.
|
||||||
|
:raises ValueError: if profile image could not be reset
|
||||||
|
:returns: None
|
||||||
|
"""
|
||||||
|
res = lib.dc_set_chat_profile_image(self._dc_context, self.id, ffi.NULL)
|
||||||
|
if res != 1:
|
||||||
|
raise ValueError("Removing Profile Image failed")
|
||||||
|
|
||||||
|
def get_profile_image(self):
|
||||||
|
"""Get group profile image.
|
||||||
|
|
||||||
|
For groups, this is the image set by any group member using
|
||||||
|
dc_set_chat_profile_image(). For normal chats, this is the image
|
||||||
|
set by each remote user on their own using dc_set_config(context,
|
||||||
|
"selfavatar", image).
|
||||||
|
:returns: path to profile image, None if no profile image exists.
|
||||||
|
"""
|
||||||
|
dc_res = lib.dc_chat_get_profile_image(self._dc_chat)
|
||||||
|
if dc_res == ffi.NULL:
|
||||||
|
return None
|
||||||
|
return from_dc_charpointer(dc_res)
|
||||||
|
|||||||
@@ -147,6 +147,15 @@ class TestOfflineChat:
|
|||||||
qr = chat.get_join_qr()
|
qr = chat.get_join_qr()
|
||||||
assert ac2.check_qr(qr).is_ask_verifygroup
|
assert ac2.check_qr(qr).is_ask_verifygroup
|
||||||
|
|
||||||
|
def test_get_set_profile_image(self, ac1, data):
|
||||||
|
chat = ac1.create_group_chat(name="title1")
|
||||||
|
p = data.get_path("d.png")
|
||||||
|
chat.set_profile_image(p)
|
||||||
|
p2 = chat.get_profile_image()
|
||||||
|
assert open(p, "rb").read() == open(p2, "rb").read()
|
||||||
|
chat.remove_profile_image()
|
||||||
|
assert chat.get_profile_image() is None
|
||||||
|
|
||||||
def test_delete_and_send_fails(self, ac1, chat1):
|
def test_delete_and_send_fails(self, ac1, chat1):
|
||||||
chat1.delete()
|
chat1.delete()
|
||||||
ac1._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
ac1._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||||
@@ -589,3 +598,44 @@ class TestOnlineAccount:
|
|||||||
ch = ac2.qr_join_chat(qr)
|
ch = ac2.qr_join_chat(qr)
|
||||||
assert ch.id >= 10
|
assert ch.id >= 10
|
||||||
wait_securejoin_inviter_progress(ac1, 1000)
|
wait_securejoin_inviter_progress(ac1, 1000)
|
||||||
|
|
||||||
|
def test_set_get_profile_image(self, acfactory, data, lp):
|
||||||
|
ac1 = acfactory.get_online_configuring_account()
|
||||||
|
ac2 = acfactory.get_online_configuring_account()
|
||||||
|
wait_configuration_progress(ac2, 1000)
|
||||||
|
wait_configuration_progress(ac1, 1000)
|
||||||
|
|
||||||
|
lp.sec("create unpromoted group chat")
|
||||||
|
chat = ac1.create_group_chat("hello")
|
||||||
|
p = data.get_path("d.png")
|
||||||
|
|
||||||
|
lp.sec("set profile image")
|
||||||
|
chat.set_profile_image(p)
|
||||||
|
ac1._evlogger.get_matching("DC_EVENT_CHAT_MODIFIED")
|
||||||
|
assert not chat.is_promoted()
|
||||||
|
|
||||||
|
lp.sec("add ac2 to unpromoted group chat")
|
||||||
|
c2 = ac1.create_contact(email=ac2.get_config("addr"))
|
||||||
|
contact1 = chat.add_contact(c2)
|
||||||
|
assert not chat.is_promoted()
|
||||||
|
|
||||||
|
lp.sec("ac2: add ac1 per chat")
|
||||||
|
c1 = ac2.create_contact(email=ac1.get_config("addr"))
|
||||||
|
ac2.create_chat_by_contact(c1)
|
||||||
|
ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||||
|
|
||||||
|
lp.sec("ac1: send a first message to ac2")
|
||||||
|
chat.send_text("hi")
|
||||||
|
assert chat.is_promoted()
|
||||||
|
|
||||||
|
lp.sec("ac2: wait for receiving message from ac1")
|
||||||
|
ev = ac2._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
|
||||||
|
msg_in = ac2.get_message_by_id(ev[2])
|
||||||
|
assert msg_in.text == "hi"
|
||||||
|
assert not msg_in.chat.is_deaddrop()
|
||||||
|
|
||||||
|
lp.sec("ac2: create proper chat and read profile image")
|
||||||
|
chat2 = ac2.create_chat_by_message(msg_in)
|
||||||
|
p2 = chat2.get_profile_image()
|
||||||
|
assert p2 is not None
|
||||||
|
assert open(p2, "rb").read() == open(p, "rb").read()
|
||||||
|
|||||||
43
src/chat.rs
43
src/chat.rs
@@ -1654,8 +1654,6 @@ pub unsafe fn set_chat_profile_image(
|
|||||||
ensure!(chat_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat ID");
|
ensure!(chat_id > DC_CHAT_ID_LAST_SPECIAL, "Invalid chat ID");
|
||||||
|
|
||||||
let mut chat = Chat::load_from_db(context, chat_id)?;
|
let mut chat = Chat::load_from_db(context, chat_id)?;
|
||||||
let mut msg = dc_msg_new_untyped(context);
|
|
||||||
let new_image_rel;
|
|
||||||
|
|
||||||
if real_group_exists(context, chat_id) {
|
if real_group_exists(context, chat_id) {
|
||||||
if !(is_contact_in_chat(context, chat_id, 1i32 as u32) == 1i32) {
|
if !(is_contact_in_chat(context, chat_id, 1i32 as u32) == 1i32) {
|
||||||
@@ -1668,48 +1666,39 @@ pub unsafe fn set_chat_profile_image(
|
|||||||
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
/* we should respect this - whatever we send to the group, it gets discarded anyway! */
|
||||||
bail!("Failed to set profile image");
|
bail!("Failed to set profile image");
|
||||||
}
|
}
|
||||||
|
let mut new_image_rel: String;
|
||||||
if !new_image.as_ref().is_empty() {
|
if !new_image.as_ref().is_empty() {
|
||||||
let mut img = new_image.as_ref().to_string();
|
new_image_rel = new_image.as_ref().to_string();
|
||||||
if !dc_make_rel_and_copy(context, &mut img) {
|
if !dc_make_rel_and_copy(context, &mut new_image_rel) {
|
||||||
bail!("Failed to set profile image");
|
bail!("Failed to get relative path for profile image");
|
||||||
}
|
}
|
||||||
new_image_rel = Some(img);
|
|
||||||
} else {
|
} else {
|
||||||
new_image_rel = Some("".to_string());
|
new_image_rel = "".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref new_image_rel) = new_image_rel {
|
chat.param.set(Param::ProfileImage, &new_image_rel);
|
||||||
chat.param.set(Param::ProfileImage, new_image_rel);
|
|
||||||
}
|
|
||||||
if chat.update_param().is_ok() {
|
if chat.update_param().is_ok() {
|
||||||
|
info!(context, 0, "after update_param");
|
||||||
if chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
|
if chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
|
||||||
msg.param.set_int(Param::Cmd, 3);
|
let mut msg = dc_msg_new_untyped(context);
|
||||||
if let Some(ref new_image_rel) = new_image_rel {
|
info!(context, 0, "setting params for groupimage change");
|
||||||
msg.param.set(Param::Arg, new_image_rel);
|
msg.param.set_int(Param::Cmd, DC_CMD_GROUPIMAGE_CHANGED);
|
||||||
}
|
msg.param.set(Param::Arg, &new_image_rel);
|
||||||
msg.type_0 = Viewtype::Text;
|
msg.type_0 = Viewtype::Text;
|
||||||
msg.text = Some(context.stock_system_msg(
|
msg.text = Some(context.stock_system_msg(
|
||||||
if new_image_rel.is_some() {
|
if new_image_rel.is_empty() {
|
||||||
StockMessage::MsgGrpImgChanged
|
|
||||||
} else {
|
|
||||||
StockMessage::MsgGrpImgDeleted
|
StockMessage::MsgGrpImgDeleted
|
||||||
|
} else {
|
||||||
|
StockMessage::MsgGrpImgChanged
|
||||||
},
|
},
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
DC_CONTACT_ID_SELF,
|
DC_CONTACT_ID_SELF,
|
||||||
));
|
));
|
||||||
msg.id = send_msg(context, chat_id, &mut msg).unwrap_or_default();
|
msg.id = send_msg(context, chat_id, &mut msg).unwrap_or_default();
|
||||||
context.call_cb(
|
emit_event!(context, Event::MSGS_CHANGED, chat_id, msg.id);
|
||||||
Event::MSGS_CHANGED,
|
|
||||||
chat_id as uintptr_t,
|
|
||||||
msg.id as uintptr_t,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
context.call_cb(
|
emit_event!(context, Event::CHAT_MODIFIED, chat_id, 0);
|
||||||
Event::CHAT_MODIFIED,
|
|
||||||
chat_id as uintptr_t,
|
|
||||||
0i32 as uintptr_t,
|
|
||||||
);
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -557,6 +557,6 @@ pub const DC_CMD_GROUPIMAGE_CHANGED: libc::c_int = 3;
|
|||||||
pub const DC_CMD_MEMBER_ADDED_TO_GROUP: libc::c_int = 4;
|
pub const DC_CMD_MEMBER_ADDED_TO_GROUP: libc::c_int = 4;
|
||||||
pub const DC_CMD_MEMBER_REMOVED_FROM_GROUP: libc::c_int = 5;
|
pub const DC_CMD_MEMBER_REMOVED_FROM_GROUP: libc::c_int = 5;
|
||||||
pub const DC_CMD_AUTOCRYPT_SETUP_MESSAGE: libc::c_int = 6;
|
pub const DC_CMD_AUTOCRYPT_SETUP_MESSAGE: libc::c_int = 6;
|
||||||
const DC_CMD_SECUREJOIN_MESSAGE: libc::c_int = 7;
|
pub const DC_CMD_SECUREJOIN_MESSAGE: libc::c_int = 7;
|
||||||
pub const DC_CMD_LOCATION_STREAMING_ENABLED: libc::c_int = 8;
|
pub const DC_CMD_LOCATION_STREAMING_ENABLED: libc::c_int = 8;
|
||||||
const DC_CMD_LOCATION_ONLY: libc::c_int = 9;
|
pub const DC_CMD_LOCATION_ONLY: libc::c_int = 9;
|
||||||
|
|||||||
@@ -532,6 +532,10 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
|
|||||||
|
|
||||||
/* build header etc. */
|
/* build header etc. */
|
||||||
let command = factory.msg.param.get_int(Param::Cmd).unwrap_or_default();
|
let command = factory.msg.param.get_int(Param::Cmd).unwrap_or_default();
|
||||||
|
info!(
|
||||||
|
factory.context,
|
||||||
|
0, "render_message found command {}", command
|
||||||
|
);
|
||||||
if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup {
|
if chat.typ == Chattype::Group || chat.typ == Chattype::VerifiedGroup {
|
||||||
mailimf_fields_add(
|
mailimf_fields_add(
|
||||||
imf_fields,
|
imf_fields,
|
||||||
@@ -548,7 +552,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
|
|||||||
dc_encode_header_words(name.as_ptr()),
|
dc_encode_header_words(name.as_ptr()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if command == 5 {
|
if command == DC_CMD_MEMBER_REMOVED_FROM_GROUP {
|
||||||
let email_to_remove = factory
|
let email_to_remove = factory
|
||||||
.msg
|
.msg
|
||||||
.param
|
.param
|
||||||
@@ -567,7 +571,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if command == 4 {
|
} else if command == DC_CMD_MEMBER_ADDED_TO_GROUP {
|
||||||
let msg = &factory.msg;
|
let msg = &factory.msg;
|
||||||
do_gossip = 1;
|
do_gossip = 1;
|
||||||
let email_to_add = msg.param.get(Param::Arg).unwrap_or_default().strdup();
|
let email_to_add = msg.param.get(Param::Arg).unwrap_or_default().strdup();
|
||||||
@@ -599,7 +603,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if command == 2 {
|
} else if command == DC_CMD_GROUPNAME_CHANGED {
|
||||||
let msg = &factory.msg;
|
let msg = &factory.msg;
|
||||||
|
|
||||||
let value_to_add = msg.param.get(Param::Arg).unwrap_or_default().strdup();
|
let value_to_add = msg.param.get(Param::Arg).unwrap_or_default().strdup();
|
||||||
@@ -612,7 +616,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
|
|||||||
value_to_add,
|
value_to_add,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else if command == 3 {
|
} else if command == DC_CMD_GROUPIMAGE_CHANGED {
|
||||||
let msg = &factory.msg;
|
let msg = &factory.msg;
|
||||||
grpimage = msg.param.get(Param::Arg);
|
grpimage = msg.param.get(Param::Arg);
|
||||||
if grpimage.is_none() {
|
if grpimage.is_none() {
|
||||||
@@ -626,7 +630,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if command == 8 {
|
if command == DC_CMD_LOCATION_STREAMING_ENABLED {
|
||||||
mailimf_fields_add(
|
mailimf_fields_add(
|
||||||
imf_fields,
|
imf_fields,
|
||||||
mailimf_field_new_custom(
|
mailimf_field_new_custom(
|
||||||
@@ -637,7 +641,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if command == 6 {
|
if command == DC_CMD_AUTOCRYPT_SETUP_MESSAGE {
|
||||||
mailimf_fields_add(
|
mailimf_fields_add(
|
||||||
imf_fields,
|
imf_fields,
|
||||||
mailimf_field_new_custom(
|
mailimf_field_new_custom(
|
||||||
@@ -650,7 +654,7 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
|
|||||||
.stock_str(StockMessage::AcSetupMsgBody)
|
.stock_str(StockMessage::AcSetupMsgBody)
|
||||||
.strdup();
|
.strdup();
|
||||||
}
|
}
|
||||||
if command == 7 {
|
if command == DC_CMD_SECUREJOIN_MESSAGE {
|
||||||
let msg = &factory.msg;
|
let msg = &factory.msg;
|
||||||
let step = msg.param.get(Param::Arg).unwrap_or_default().strdup();
|
let step = msg.param.get(Param::Arg).unwrap_or_default().strdup();
|
||||||
if strlen(step) > 0 {
|
if strlen(step) > 0 {
|
||||||
@@ -725,7 +729,9 @@ pub unsafe fn dc_mimefactory_render(factory: &mut dc_mimefactory_t) -> libc::c_i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
info!(factory.context, 0, "grpimage {:?}", grpimage);
|
||||||
if let Some(grpimage) = grpimage {
|
if let Some(grpimage) = grpimage {
|
||||||
|
info!(factory.context, 0, "setting group image");
|
||||||
let mut meta = dc_msg_new_untyped(factory.context);
|
let mut meta = dc_msg_new_untyped(factory.context);
|
||||||
meta.type_0 = Viewtype::Image;
|
meta.type_0 = Viewtype::Image;
|
||||||
meta.param.set(Param::File, grpimage);
|
meta.param.set(Param::File, grpimage);
|
||||||
|
|||||||
@@ -1078,7 +1078,6 @@ unsafe fn create_or_lookup_group(
|
|||||||
}
|
}
|
||||||
set_better_msg(mime_parser, &better_msg);
|
set_better_msg(mime_parser, &better_msg);
|
||||||
|
|
||||||
// search the grpid in the header
|
|
||||||
let optional_field = dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-ID");
|
let optional_field = dc_mimeparser_lookup_optional_field(mime_parser, "Chat-Group-ID");
|
||||||
if !optional_field.is_null() {
|
if !optional_field.is_null() {
|
||||||
grpid = to_string((*optional_field).fld_value)
|
grpid = to_string((*optional_field).fld_value)
|
||||||
@@ -1316,9 +1315,11 @@ unsafe fn create_or_lookup_group(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// execute group commands
|
// execute group commands
|
||||||
|
info!(context, 0, "before exec group commands");
|
||||||
if !X_MrAddToGrp.is_null() || !X_MrRemoveFromGrp.is_null() {
|
if !X_MrAddToGrp.is_null() || !X_MrRemoveFromGrp.is_null() {
|
||||||
recreate_member_list = 1;
|
recreate_member_list = 1;
|
||||||
} else if 0 != X_MrGrpNameChanged && !grpname.is_null() && strlen(grpname) < 200 {
|
} else if 0 != X_MrGrpNameChanged && !grpname.is_null() && strlen(grpname) < 200 {
|
||||||
|
info!(context, 0, "updating grpname for chat {}", chat_id);
|
||||||
if sql::execute(
|
if sql::execute(
|
||||||
context,
|
context,
|
||||||
&context.sql,
|
&context.sql,
|
||||||
@@ -1331,6 +1332,13 @@ unsafe fn create_or_lookup_group(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !X_MrGrpImageChanged.is_null() {
|
if !X_MrGrpImageChanged.is_null() {
|
||||||
|
info!(
|
||||||
|
context,
|
||||||
|
0,
|
||||||
|
"handling group image changed {} for chat {}",
|
||||||
|
as_str(X_MrGrpImageChanged),
|
||||||
|
chat_id
|
||||||
|
);
|
||||||
let mut ok = 0;
|
let mut ok = 0;
|
||||||
let mut grpimage = ptr::null_mut();
|
let mut grpimage = ptr::null_mut();
|
||||||
if strcmp(
|
if strcmp(
|
||||||
@@ -1347,6 +1355,7 @@ unsafe fn create_or_lookup_group(
|
|||||||
.get(Param::File)
|
.get(Param::File)
|
||||||
.map(|s| s.strdup())
|
.map(|s| s.strdup())
|
||||||
.unwrap_or_else(|| std::ptr::null_mut());
|
.unwrap_or_else(|| std::ptr::null_mut());
|
||||||
|
info!(context, 0, "found image {:?}", grpimage);
|
||||||
ok = 1
|
ok = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user