mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 17:36:29 +03:00
attach selfavatar
This commit is contained in:
committed by
holger krekel
parent
3cf39dace0
commit
7f723ef2bf
55
src/chat.rs
55
src/chat.rs
@@ -1597,6 +1597,46 @@ pub fn set_gossiped_timestamp(context: &Context, chat_id: u32, timestamp: i64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn shall_attach_selfavatar(context: &Context, chat_id: u32) -> Result<bool, Error> {
|
||||||
|
let resend_every_days = 14;
|
||||||
|
let timestamp_some_days_ago = time() - resend_every_days * 24 * 60 * 60;
|
||||||
|
let needs_attach = context.sql.query_map(
|
||||||
|
"SELECT c.selfavatar_sent
|
||||||
|
FROM chats_contacts cc
|
||||||
|
LEFT JOIN contacts c ON c.id=cc.contact_id
|
||||||
|
WHERE cc.chat_id=? AND cc.contact_id!=?;",
|
||||||
|
params![chat_id, DC_CONTACT_ID_SELF],
|
||||||
|
|row| Ok(row.get::<_, i64>(0)),
|
||||||
|
|rows| {
|
||||||
|
let mut needs_attach = false;
|
||||||
|
for row in rows {
|
||||||
|
if let Ok(selfavatar_sent) = row {
|
||||||
|
let selfavatar_sent = selfavatar_sent?;
|
||||||
|
if selfavatar_sent < timestamp_some_days_ago {
|
||||||
|
needs_attach = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(needs_attach)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
Ok(needs_attach)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_selfavatar_timestamp(
|
||||||
|
context: &Context,
|
||||||
|
chat_id: u32,
|
||||||
|
timestamp: i64,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
context.sql.execute(
|
||||||
|
"UPDATE contacts
|
||||||
|
SET selfavatar_sent=?
|
||||||
|
WHERE id IN(SELECT contact_id FROM chats_contacts WHERE chat_id=?);",
|
||||||
|
params![timestamp, chat_id],
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn remove_contact_from_chat(
|
pub fn remove_contact_from_chat(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
chat_id: u32,
|
chat_id: u32,
|
||||||
@@ -2435,4 +2475,19 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(chat2.name, chat.name);
|
assert_eq!(chat2.name, chat.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_shall_attach_selfavatar() {
|
||||||
|
let t = dummy_context();
|
||||||
|
let chat_id = create_group_chat(&t.ctx, VerifiedStatus::Unverified, "foo").unwrap();
|
||||||
|
assert!(!shall_attach_selfavatar(&t.ctx, chat_id).unwrap());
|
||||||
|
|
||||||
|
let (contact_id, _) =
|
||||||
|
Contact::add_or_lookup(&t.ctx, "", "foo@bar.org", Origin::IncomingUnknownTo).unwrap();
|
||||||
|
add_contact_to_chat(&t.ctx, chat_id, contact_id);
|
||||||
|
assert!(shall_attach_selfavatar(&t.ctx, chat_id).unwrap());
|
||||||
|
|
||||||
|
assert!(set_selfavatar_timestamp(&t.ctx, chat_id, time()).is_ok());
|
||||||
|
assert!(!shall_attach_selfavatar(&t.ctx, chat_id).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/job.rs
18
src/job.rs
@@ -633,7 +633,15 @@ pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<(), Error> {
|
|||||||
/* create message */
|
/* create message */
|
||||||
let needs_encryption = msg.param.get_int(Param::GuaranteeE2ee).unwrap_or_default();
|
let needs_encryption = msg.param.get_int(Param::GuaranteeE2ee).unwrap_or_default();
|
||||||
|
|
||||||
let mimefactory = MimeFactory::from_msg(context, &msg)?;
|
let attach_selfavatar = match chat::shall_attach_selfavatar(context, msg.chat_id) {
|
||||||
|
Ok(attach_selfavatar) => attach_selfavatar,
|
||||||
|
Err(err) => {
|
||||||
|
warn!(context, "job: cannot get selfavatar-state: {}", err);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mimefactory = MimeFactory::from_msg(context, &msg, attach_selfavatar)?;
|
||||||
let mut rendered_msg = mimefactory.render().map_err(|err| {
|
let mut rendered_msg = mimefactory.render().map_err(|err| {
|
||||||
message::set_msg_failed(context, msg_id, Some(err.to_string()));
|
message::set_msg_failed(context, msg_id, Some(err.to_string()));
|
||||||
err
|
err
|
||||||
@@ -672,6 +680,7 @@ pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<(), Error> {
|
|||||||
if rendered_msg.is_gossiped {
|
if rendered_msg.is_gossiped {
|
||||||
chat::set_gossiped_timestamp(context, msg.chat_id, time());
|
chat::set_gossiped_timestamp(context, msg.chat_id, time());
|
||||||
}
|
}
|
||||||
|
|
||||||
if 0 != rendered_msg.last_added_location_id {
|
if 0 != rendered_msg.last_added_location_id {
|
||||||
if let Err(err) = location::set_kml_sent_timestamp(context, msg.chat_id, time()) {
|
if let Err(err) = location::set_kml_sent_timestamp(context, msg.chat_id, time()) {
|
||||||
error!(context, "Failed to set kml sent_timestamp: {:?}", err);
|
error!(context, "Failed to set kml sent_timestamp: {:?}", err);
|
||||||
@@ -684,6 +693,13 @@ pub fn job_send_msg(context: &Context, msg_id: MsgId) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if attach_selfavatar {
|
||||||
|
if let Err(err) = chat::set_selfavatar_timestamp(context, msg.chat_id, time()) {
|
||||||
|
error!(context, "Failed to set selfavatar timestamp: {:?}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if rendered_msg.is_encrypted && needs_encryption == 0 {
|
if rendered_msg.is_encrypted && needs_encryption == 0 {
|
||||||
msg.param.set_int(Param::GuaranteeE2ee, 1);
|
msg.param.set_int(Param::GuaranteeE2ee, 1);
|
||||||
msg.save_param_to_disk(context);
|
msg.save_param_to_disk(context);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use chrono::TimeZone;
|
use chrono::TimeZone;
|
||||||
use lettre_email::{mime, Address, Header, MimeMultipartType, PartBuilder};
|
use lettre_email::{mime, Address, Header, MimeMultipartType, PartBuilder};
|
||||||
|
|
||||||
|
use crate::blob::BlobObject;
|
||||||
use crate::chat::{self, Chat};
|
use crate::chat::{self, Chat};
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
@@ -41,6 +42,7 @@ pub struct MimeFactory<'a, 'b> {
|
|||||||
pub req_mdn: bool,
|
pub req_mdn: bool,
|
||||||
pub context: &'a Context,
|
pub context: &'a Context,
|
||||||
last_added_location_id: u32,
|
last_added_location_id: u32,
|
||||||
|
attach_selfavatar: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result of rendering a message, ready to be submitted to a send job.
|
/// Result of rendering a message, ready to be submitted to a send job.
|
||||||
@@ -62,7 +64,11 @@ pub struct RenderedEmail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> MimeFactory<'a, 'b> {
|
impl<'a, 'b> MimeFactory<'a, 'b> {
|
||||||
pub fn from_msg(context: &'a Context, msg: &'b Message) -> Result<MimeFactory<'a, 'b>, Error> {
|
pub fn from_msg(
|
||||||
|
context: &'a Context,
|
||||||
|
msg: &'b Message,
|
||||||
|
add_selfavatar: bool,
|
||||||
|
) -> Result<MimeFactory<'a, 'b>, Error> {
|
||||||
let chat = Chat::load_from_db(context, msg.chat_id)?;
|
let chat = Chat::load_from_db(context, msg.chat_id)?;
|
||||||
|
|
||||||
let mut factory = MimeFactory {
|
let mut factory = MimeFactory {
|
||||||
@@ -84,6 +90,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
|
|||||||
references: String::default(),
|
references: String::default(),
|
||||||
req_mdn: false,
|
req_mdn: false,
|
||||||
last_added_location_id: 0,
|
last_added_location_id: 0,
|
||||||
|
attach_selfavatar: add_selfavatar,
|
||||||
context,
|
context,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -210,6 +217,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
|
|||||||
references: String::default(),
|
references: String::default(),
|
||||||
req_mdn: false,
|
req_mdn: false,
|
||||||
last_added_location_id: 0,
|
last_added_location_id: 0,
|
||||||
|
attach_selfavatar: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -873,6 +881,21 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.attach_selfavatar {
|
||||||
|
match context.get_config(Config::Selfavatar) {
|
||||||
|
Some(path) => match build_selfavatar_file(context, path) {
|
||||||
|
Ok((part, filename)) => {
|
||||||
|
parts.push(part);
|
||||||
|
protected_headers.push(Header::new("Chat-Profile-Image".into(), filename))
|
||||||
|
}
|
||||||
|
Err(err) => warn!(context, "mimefactory: cannot attach selfavatar: {}", err),
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
protected_headers.push(Header::new("Chat-Profile-Image".into(), "0".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Single part, render as regular message.
|
// Single part, render as regular message.
|
||||||
if parts.len() == 1 {
|
if parts.len() == 1 {
|
||||||
return Ok(parts.pop().unwrap());
|
return Ok(parts.pop().unwrap());
|
||||||
@@ -1024,6 +1047,31 @@ fn build_body_file(
|
|||||||
Ok((mail, filename_to_send))
|
Ok((mail, filename_to_send))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_selfavatar_file(context: &Context, path: String) -> Result<(PartBuilder, String), Error> {
|
||||||
|
let blob = BlobObject::from_path(context, path)?;
|
||||||
|
let filename_to_send = match blob.suffix() {
|
||||||
|
Some(suffix) => format!("avatar.{}", suffix),
|
||||||
|
None => "avatar".to_string(),
|
||||||
|
};
|
||||||
|
let mimetype = match message::guess_msgtype_from_suffix(blob.as_rel_path()) {
|
||||||
|
Some(res) => res.1.parse()?,
|
||||||
|
None => mime::APPLICATION_OCTET_STREAM,
|
||||||
|
};
|
||||||
|
let body = std::fs::read(blob.to_abs_path())?;
|
||||||
|
let encoded_body = base64::encode(&body);
|
||||||
|
|
||||||
|
let part = PartBuilder::new()
|
||||||
|
.content_type(&mimetype)
|
||||||
|
.header((
|
||||||
|
"Content-Disposition",
|
||||||
|
format!("attachment; filename=\"{}\"", &filename_to_send),
|
||||||
|
))
|
||||||
|
.header(("Content-Transfer-Encoding", "base64"))
|
||||||
|
.body(encoded_body);
|
||||||
|
|
||||||
|
Ok((part, filename_to_send))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn vec_contains_lowercase(vec: &[String], part: &str) -> bool {
|
pub(crate) fn vec_contains_lowercase(vec: &[String], part: &str) -> bool {
|
||||||
let partlc = part.to_lowercase();
|
let partlc = part.to_lowercase();
|
||||||
for cur in vec.iter() {
|
for cur in vec.iter() {
|
||||||
|
|||||||
Reference in New Issue
Block a user