mirror of
https://github.com/chatmail/core.git
synced 2026-05-18 14:26:31 +03:00
Compare commits
7 Commits
v1.136.4
...
simon/i537
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7dd715bd0c | ||
|
|
b95d58208c | ||
|
|
c468eb088e | ||
|
|
de37135ed6 | ||
|
|
33777d8759 | ||
|
|
8cc348bfa4 | ||
|
|
76bbd5fd72 |
@@ -22,6 +22,7 @@ classifiers = [
|
||||
dynamic = [
|
||||
"version"
|
||||
]
|
||||
readme = "README.md"
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
deltachat_rpc_client = [
|
||||
|
||||
@@ -2805,6 +2805,12 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -
|
||||
msg.chat_id.set_gossiped_timestamp(context, now).await?;
|
||||
}
|
||||
|
||||
if rendered_msg.is_group {
|
||||
msg.chat_id
|
||||
.update_timestamp(context, Param::MemberListTimestamp, now)
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(last_added_location_id) = rendered_msg.last_added_location_id {
|
||||
if let Err(err) = location::set_kml_sent_timestamp(context, msg.chat_id, now).await {
|
||||
error!(context, "Failed to set kml sent_timestamp: {err:#}.");
|
||||
|
||||
@@ -39,8 +39,12 @@ use crate::tools::{
|
||||
};
|
||||
use crate::{chat, stock_str};
|
||||
|
||||
|
||||
/// Time during which a contact is considered as seen recently.
|
||||
#[cfg(not(test))]
|
||||
const SEEN_RECENTLY_SECONDS: i64 = 600;
|
||||
#[cfg(test)]
|
||||
const SEEN_RECENTLY_SECONDS: i64 = 4;
|
||||
|
||||
/// Valid contact address.
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -2811,6 +2815,52 @@ Hi."#;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_was_seen_recently_event() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = tcm.alice().await;
|
||||
let bob = tcm.bob().await;
|
||||
|
||||
let chat = alice.create_chat(&bob).await;
|
||||
let sent_msg = alice.send_text(chat.id, "moin").await;
|
||||
|
||||
let chat = bob.create_chat(&alice).await;
|
||||
let contacts = chat::get_chat_contacts(&bob, chat.id).await?;
|
||||
let contact = Contact::get_by_id(&bob, *contacts.first().unwrap()).await?;
|
||||
assert!(!contact.was_seen_recently());
|
||||
|
||||
bob.recv_msg(&sent_msg).await;
|
||||
let contact = Contact::get_by_id(&bob, *contacts.first().unwrap()).await?;
|
||||
assert!(contact.was_seen_recently());
|
||||
|
||||
// wait for recently seen to be done
|
||||
tokio::time::sleep(Duration::from_secs((SEEN_RECENTLY_SECONDS + 2) as u64)).await;
|
||||
let contact = Contact::get_by_id(&bob, *contacts.first().unwrap()).await?;
|
||||
assert!(!contact.was_seen_recently());
|
||||
|
||||
// first contact establishing will always emit events.
|
||||
while bob.evtracker.try_recv().is_ok() {}
|
||||
|
||||
let chat = alice.create_chat(&bob).await;
|
||||
let sent_msg = alice.send_text(chat.id, "moin2").await;
|
||||
let contact = Contact::get_by_id(&bob, *contacts.first().unwrap()).await?;
|
||||
assert!(!contact.was_seen_recently());
|
||||
bob.recv_msg(&sent_msg).await;
|
||||
let contact = Contact::get_by_id(&bob, *contacts.first().unwrap()).await?;
|
||||
assert!(contact.was_seen_recently());
|
||||
println!("wait for event from alice turning to recently seen");
|
||||
bob.evtracker.get_matching(|evt| matches!(evt, EventType::ContactsChanged{..})).await;
|
||||
|
||||
// wait for recently seen to be done
|
||||
tokio::time::sleep(Duration::from_secs((SEEN_RECENTLY_SECONDS + 2) as u64)).await;
|
||||
let contact = Contact::get_by_id(&bob, *contacts.first().unwrap()).await?;
|
||||
assert!(!contact.was_seen_recently());
|
||||
println!("wait for event from alice turning to not recently seen");
|
||||
bob.evtracker.get_matching(|evt| matches!(evt, EventType::ContactsChanged{..})).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_verified_by_none() -> Result<()> {
|
||||
|
||||
@@ -804,6 +804,12 @@ impl Context {
|
||||
"show_emails",
|
||||
self.get_config_int(Config::ShowEmails).await?.to_string(),
|
||||
);
|
||||
res.insert(
|
||||
"save_mime_headers",
|
||||
self.get_config_bool(Config::SaveMimeHeaders)
|
||||
.await?
|
||||
.to_string(),
|
||||
);
|
||||
res.insert(
|
||||
"download_limit",
|
||||
self.get_config_int(Config::DownloadLimit)
|
||||
@@ -1605,7 +1611,6 @@ mod tests {
|
||||
"mail_port",
|
||||
"mail_security",
|
||||
"notify_about_wrong_pw",
|
||||
"save_mime_headers",
|
||||
"self_reporting_id",
|
||||
"selfstatus",
|
||||
"send_server",
|
||||
|
||||
@@ -569,9 +569,21 @@ pub(crate) async fn ephemeral_loop(context: &Context, interrupt_receiver: Receiv
|
||||
"Ephemeral loop waiting for deletion in {} or interrupt",
|
||||
duration_to_str(duration)
|
||||
);
|
||||
if timeout(duration, interrupt_receiver.recv()).await.is_ok() {
|
||||
// received an interruption signal, recompute waiting time (if any)
|
||||
continue;
|
||||
match timeout(duration, interrupt_receiver.recv()).await {
|
||||
Ok(Ok(())) => {
|
||||
// received an interruption signal, recompute waiting time (if any)
|
||||
continue;
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
warn!(
|
||||
context,
|
||||
"Interrupt channel closed, ephemeral loop exits now: {err:#}."
|
||||
);
|
||||
return;
|
||||
}
|
||||
Err(_err) => {
|
||||
// Timeout.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -679,7 +679,21 @@ pub(crate) async fn location_loop(context: &Context, interrupt_receiver: Receive
|
||||
"Location loop is waiting for {} or interrupt",
|
||||
duration_to_str(duration)
|
||||
);
|
||||
timeout(duration, interrupt_receiver.recv()).await.ok();
|
||||
match timeout(duration, interrupt_receiver.recv()).await {
|
||||
Err(_err) => {
|
||||
info!(context, "Location loop timeout.");
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
warn!(
|
||||
context,
|
||||
"Interrupt channel closed, location loop exits now: {err:#}."
|
||||
);
|
||||
return;
|
||||
}
|
||||
Ok(Ok(())) => {
|
||||
info!(context, "Location loop received interrupt.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ pub struct RenderedEmail {
|
||||
// pub envelope: Envelope,
|
||||
pub is_encrypted: bool,
|
||||
pub is_gossiped: bool,
|
||||
pub is_group: bool,
|
||||
pub last_added_location_id: Option<u32>,
|
||||
|
||||
/// A comma-separated string of sync-IDs that are used by the rendered email
|
||||
@@ -587,6 +588,8 @@ impl<'a> MimeFactory<'a> {
|
||||
));
|
||||
}
|
||||
|
||||
let mut is_group = false;
|
||||
|
||||
if let Loaded::Message { chat } = &self.loaded {
|
||||
if chat.typ == Chattype::Broadcast {
|
||||
let encoded_chat_name = encode_words(&chat.name);
|
||||
@@ -594,6 +597,8 @@ impl<'a> MimeFactory<'a> {
|
||||
"List-ID".into(),
|
||||
format!("{encoded_chat_name} <{}>", chat.grpid),
|
||||
));
|
||||
} else if chat.typ == Chattype::Group {
|
||||
is_group = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -865,6 +870,7 @@ impl<'a> MimeFactory<'a> {
|
||||
// envelope: Envelope::new,
|
||||
is_encrypted,
|
||||
is_gossiped,
|
||||
is_group,
|
||||
last_added_location_id,
|
||||
sync_ids_to_delete: self.sync_ids_to_delete,
|
||||
rfc724_mid,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use tokio::fs;
|
||||
|
||||
use super::*;
|
||||
@@ -12,6 +14,7 @@ use crate::download::MIN_DOWNLOAD_LIMIT;
|
||||
use crate::imap::prefetch_should_download;
|
||||
use crate::imex::{imex, ImexMode};
|
||||
use crate::test_utils::{get_chat_msg, TestContext, TestContextManager};
|
||||
use crate::tools::SystemTime;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_grpid_simple() {
|
||||
@@ -3608,6 +3611,52 @@ async fn test_sync_member_list_on_rejoin() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test for the bug when remote group membership changes from outdated messages overrode local
|
||||
/// ones. Especially that was a problem when a message is sent offline so that it doesn't
|
||||
/// incorporate recent group membership changes.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_ignore_outdated_membership_changes() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = &tcm.alice().await;
|
||||
let bob = &tcm.bob().await;
|
||||
let alice_bob_id =
|
||||
Contact::create(alice, "", &bob.get_config(Config::Addr).await?.unwrap()).await?;
|
||||
let alice_chat_id = create_group_chat(alice, ProtectionStatus::Unprotected, "grp").await?;
|
||||
|
||||
// Alice creates a group chat. Bob accepts it.
|
||||
add_contact_to_chat(alice, alice_chat_id, alice_bob_id).await?;
|
||||
send_text_msg(alice, alice_chat_id, "populate".to_string()).await?;
|
||||
let msg = &alice.pop_sent_msg().await;
|
||||
bob.recv_msg(msg).await;
|
||||
let bob_chat_id = bob.get_last_msg().await.chat_id;
|
||||
bob_chat_id.accept(bob).await?;
|
||||
|
||||
// Bob replies.
|
||||
send_text_msg(bob, bob_chat_id, "i'm bob".to_string()).await?;
|
||||
let msg = &bob.pop_sent_msg().await;
|
||||
|
||||
SystemTime::shift(Duration::from_secs(3600));
|
||||
|
||||
// Alice leaves.
|
||||
remove_contact_from_chat(alice, alice_chat_id, ContactId::SELF).await?;
|
||||
alice.pop_sent_msg().await;
|
||||
assert!(!is_contact_in_chat(alice, alice_chat_id, ContactId::SELF).await?);
|
||||
|
||||
// Alice receives Bob's message, but it's outdated to add Alice back.
|
||||
alice.recv_msg(msg).await;
|
||||
assert!(!is_contact_in_chat(alice, alice_chat_id, ContactId::SELF).await?);
|
||||
|
||||
SystemTime::shift(Duration::from_secs(3600));
|
||||
|
||||
// Bob replies again adding Alice back.
|
||||
send_text_msg(bob, bob_chat_id, "i'm bob".to_string()).await?;
|
||||
let msg = &bob.pop_sent_msg().await;
|
||||
alice.recv_msg(msg).await;
|
||||
assert!(is_contact_in_chat(alice, alice_chat_id, ContactId::SELF).await?);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_dont_recreate_contacts_on_add_remove() -> Result<()> {
|
||||
let alice = TestContext::new_alice().await;
|
||||
@@ -3891,7 +3940,6 @@ async fn test_mua_can_readd() -> Result<()> {
|
||||
|
||||
// And leaves it.
|
||||
remove_contact_from_chat(&alice, alice_chat.id, ContactId::SELF).await?;
|
||||
let alice_chat = Chat::load_from_db(&alice, alice_chat.id).await?;
|
||||
assert!(!is_contact_in_chat(&alice, alice_chat.id, ContactId::SELF).await?);
|
||||
|
||||
// Bob uses a classical MUA to answer, adding Alice back.
|
||||
@@ -3900,7 +3948,7 @@ async fn test_mua_can_readd() -> Result<()> {
|
||||
b"Subject: Re: Message from alice\r\n\
|
||||
From: <bob@example.net>\r\n\
|
||||
To: <alice@example.org>, <claire@example.org>, <fiona@example.org>\r\n\
|
||||
Date: Mon, 12 Dec 2022 14:32:39 +0000\r\n\
|
||||
Date: Mon, 12 Dec 3000 14:32:39 +0000\r\n\
|
||||
Message-ID: <bobs_answer_to_two_recipients@example.net>\r\n\
|
||||
In-Reply-To: <Mr.alices_original_mail@example.org>\r\n\
|
||||
\r\n\
|
||||
@@ -3909,8 +3957,6 @@ async fn test_mua_can_readd() -> Result<()> {
|
||||
)
|
||||
.await?
|
||||
.unwrap();
|
||||
|
||||
let alice_chat = Chat::load_from_db(&alice, alice_chat.id).await?;
|
||||
assert!(is_contact_in_chat(&alice, alice_chat.id, ContactId::SELF).await?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -677,11 +677,18 @@ fn new_connection(path: &Path, passphrase: &str) -> Result<Connection> {
|
||||
"PRAGMA cipher_memory_security = OFF; -- Too slow on Android
|
||||
PRAGMA secure_delete=on;
|
||||
PRAGMA busy_timeout = 0; -- fail immediately
|
||||
PRAGMA temp_store=memory; -- Avoid SQLITE_IOERR_GETTEMPPATH errors on Android
|
||||
PRAGMA soft_heap_limit = 8388608; -- 8 MiB limit, same as set in Android SQLiteDatabase.
|
||||
PRAGMA foreign_keys=on;
|
||||
",
|
||||
)?;
|
||||
|
||||
// Avoid SQLITE_IOERR_GETTEMPPATH errors on Android and maybe other systems.
|
||||
// Downside is more RAM consumption esp. on VACUUM.
|
||||
// Therefore, on systems known to have working default (using files), stay with that.
|
||||
if cfg!(not(target_os = "ios")) {
|
||||
conn.pragma_update(None, "temp_store", "memory")?;
|
||||
}
|
||||
|
||||
conn.pragma_update(None, "key", passphrase)?;
|
||||
// Try to enable auto_vacuum. This will only be
|
||||
// applied if the database is new or after successful
|
||||
|
||||
213
src/summary.rs
213
src/summary.rs
@@ -120,70 +120,120 @@ impl Summary {
|
||||
impl Message {
|
||||
/// Returns a summary text.
|
||||
async fn get_summary_text(&self, context: &Context) -> String {
|
||||
let mut append_text = true;
|
||||
let prefix = match self.viewtype {
|
||||
Viewtype::Image => stock_str::image(context).await,
|
||||
Viewtype::Gif => stock_str::gif(context).await,
|
||||
Viewtype::Sticker => stock_str::sticker(context).await,
|
||||
Viewtype::Video => stock_str::video(context).await,
|
||||
Viewtype::Voice => stock_str::voice_message(context).await,
|
||||
Viewtype::Audio | Viewtype::File => {
|
||||
let (emoji, type_name, type_file, append_text);
|
||||
match self.viewtype {
|
||||
Viewtype::Image => {
|
||||
emoji = Some("📷");
|
||||
type_name = Some(stock_str::image(context).await);
|
||||
type_file = None;
|
||||
append_text = true;
|
||||
}
|
||||
Viewtype::Gif => {
|
||||
emoji = None;
|
||||
type_name = Some(stock_str::gif(context).await);
|
||||
type_file = None;
|
||||
append_text = true;
|
||||
}
|
||||
Viewtype::Sticker => {
|
||||
emoji = None;
|
||||
type_name = Some(stock_str::sticker(context).await);
|
||||
type_file = None;
|
||||
append_text = true;
|
||||
}
|
||||
Viewtype::Video => {
|
||||
emoji = Some("🎥");
|
||||
type_name = Some(stock_str::video(context).await);
|
||||
type_file = None;
|
||||
append_text = true;
|
||||
}
|
||||
Viewtype::Voice => {
|
||||
emoji = Some("🎤");
|
||||
type_name = Some(stock_str::voice_message(context).await);
|
||||
type_file = None;
|
||||
append_text = true;
|
||||
}
|
||||
Viewtype::Audio => {
|
||||
emoji = Some("🎵");
|
||||
type_name = Some(stock_str::audio(context).await);
|
||||
type_file = self.get_filename();
|
||||
append_text = true
|
||||
}
|
||||
Viewtype::File => {
|
||||
if self.param.get_cmd() == SystemMessage::AutocryptSetupMessage {
|
||||
emoji = None;
|
||||
type_name = Some(stock_str::ac_setup_msg_subject(context).await);
|
||||
type_file = None;
|
||||
append_text = false;
|
||||
stock_str::ac_setup_msg_subject(context).await
|
||||
} else {
|
||||
let file_name = self
|
||||
.get_filename()
|
||||
.unwrap_or_else(|| String::from("ErrFileName"));
|
||||
let label = if self.viewtype == Viewtype::Audio {
|
||||
stock_str::audio(context).await
|
||||
} else {
|
||||
stock_str::file(context).await
|
||||
};
|
||||
format!("{label} – {file_name}")
|
||||
emoji = Some("📎");
|
||||
type_name = Some(stock_str::file(context).await);
|
||||
type_file = self.get_filename();
|
||||
append_text = true
|
||||
}
|
||||
}
|
||||
Viewtype::VideochatInvitation => {
|
||||
emoji = None;
|
||||
type_name = Some(stock_str::videochat_invitation(context).await);
|
||||
type_file = None;
|
||||
append_text = false;
|
||||
stock_str::videochat_invitation(context).await
|
||||
}
|
||||
Viewtype::Webxdc => {
|
||||
emoji = None;
|
||||
type_name = None;
|
||||
type_file = Some(
|
||||
self.get_webxdc_info(context)
|
||||
.await
|
||||
.map(|info| info.name)
|
||||
.unwrap_or_else(|_| "ErrWebxdcName".to_string()),
|
||||
);
|
||||
append_text = true;
|
||||
self.get_webxdc_info(context)
|
||||
.await
|
||||
.map(|info| info.name)
|
||||
.unwrap_or_else(|_| "ErrWebxdcName".to_string())
|
||||
}
|
||||
Viewtype::Text | Viewtype::Unknown => {
|
||||
if self.param.get_cmd() != SystemMessage::LocationOnly {
|
||||
"".to_string()
|
||||
} else {
|
||||
emoji = None;
|
||||
if self.param.get_cmd() == SystemMessage::LocationOnly {
|
||||
type_name = Some(stock_str::location(context).await);
|
||||
type_file = None;
|
||||
append_text = false;
|
||||
stock_str::location(context).await
|
||||
} else {
|
||||
type_name = None;
|
||||
type_file = None;
|
||||
append_text = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if !append_text {
|
||||
return prefix;
|
||||
}
|
||||
let text = self.text.clone();
|
||||
|
||||
let summary_content = if self.text.is_empty() {
|
||||
prefix
|
||||
} else if prefix.is_empty() {
|
||||
self.text.to_string()
|
||||
let summary = if let Some(type_file) = type_file {
|
||||
if append_text && !text.is_empty() {
|
||||
format!("{type_file} – {text}")
|
||||
} else {
|
||||
type_file
|
||||
}
|
||||
} else if append_text && !text.is_empty() {
|
||||
if emoji.is_some() {
|
||||
text
|
||||
} else if let Some(type_name) = type_name {
|
||||
format!("{type_name} – {text}")
|
||||
} else {
|
||||
text
|
||||
}
|
||||
} else if let Some(type_name) = type_name {
|
||||
type_name
|
||||
} else {
|
||||
format!("{prefix} – {}", self.text)
|
||||
"".to_string()
|
||||
};
|
||||
|
||||
let summary = if let Some(emoji) = emoji {
|
||||
format!("{emoji} {summary}")
|
||||
} else {
|
||||
summary
|
||||
};
|
||||
|
||||
let summary = if self.is_forwarded() {
|
||||
format!(
|
||||
"{}: {}",
|
||||
stock_str::forwarded(context).await,
|
||||
summary_content
|
||||
)
|
||||
format!("{}: {}", stock_str::forwarded(context).await, summary)
|
||||
} else {
|
||||
summary_content
|
||||
summary
|
||||
};
|
||||
|
||||
summary.split_whitespace().collect::<Vec<&str>>().join(" ")
|
||||
@@ -211,75 +261,99 @@ mod tests {
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Image);
|
||||
msg.set_file("foo.bar", None);
|
||||
msg.set_file("foo.jpg", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Image" // file names are not added for images
|
||||
"📷 Image" // file names are not added for images
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Image);
|
||||
msg.set_text(some_text.to_string());
|
||||
msg.set_file("foo.jpg", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"📷 bla bla" // type is visible by emoji if text is set
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Video);
|
||||
msg.set_file("foo.bar", None);
|
||||
msg.set_file("foo.mp4", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Video" // file names are not added for videos
|
||||
"🎥 Video" // file names are not added for videos
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Video);
|
||||
msg.set_text(some_text.to_string());
|
||||
msg.set_file("foo.mp4", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"🎥 bla bla" // type is visible by emoji if text is set
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Gif);
|
||||
msg.set_file("foo.bar", None);
|
||||
msg.set_file("foo.gif", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"GIF" // file names are not added for GIFs
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Gif);
|
||||
msg.set_text(some_text.to_string());
|
||||
msg.set_file("foo.gif", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"GIF \u{2013} bla bla" // file names are not added for GIFs
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Sticker);
|
||||
msg.set_file("foo.bar", None);
|
||||
msg.set_file("foo.png", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Sticker" // file names are not added for stickers
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Voice);
|
||||
msg.set_file("foo.bar", None);
|
||||
msg.set_file("foo.mp3", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Voice message" // file names are not added for voice messages, empty text is skipped
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Voice);
|
||||
msg.set_file("foo.bar", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Voice message" // file names are not added for voice messages
|
||||
"🎤 Voice message" // file names are not added for voice messages
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Voice);
|
||||
msg.set_text(some_text.clone());
|
||||
msg.set_file("foo.bar", None);
|
||||
msg.set_file("foo.mp3", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Voice message \u{2013} bla bla" // `\u{2013}` explicitly checks for "EN DASH"
|
||||
"🎤 bla bla" // `\u{2013}` explicitly checks for "EN DASH"
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Audio);
|
||||
msg.set_file("foo.bar", None);
|
||||
msg.set_file("foo.mp3", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Audio \u{2013} foo.bar" // file name is added for audio
|
||||
"🎵 foo.mp3" // file name is added for audio
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Audio);
|
||||
msg.set_file("foo.bar", None);
|
||||
msg.set_file("foo.mp3", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Audio \u{2013} foo.bar" // file name is added for audio, empty text is not added
|
||||
"🎵 foo.mp3" // file name is added for audio, empty text is not added
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::Audio);
|
||||
msg.set_text(some_text.clone());
|
||||
msg.set_file("foo.mp3", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"🎵 foo.mp3 \u{2013} bla bla" // file name and text added for audio
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::File);
|
||||
msg.set_file("foo.bar", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Audio \u{2013} foo.bar \u{2013} bla bla" // file name and text added for audio
|
||||
"📎 foo.bar" // file name is added for files
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::File);
|
||||
@@ -287,7 +361,15 @@ mod tests {
|
||||
msg.set_file("foo.bar", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"File \u{2013} foo.bar \u{2013} bla bla" // file name is added for files
|
||||
"📎 foo.bar \u{2013} bla bla" // file name is added for files
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::VideochatInvitation);
|
||||
msg.set_text(some_text.clone());
|
||||
msg.set_file("foo.bar", None);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Video chat invitation" // text is not added for videochat invitations
|
||||
);
|
||||
|
||||
// Forwarded
|
||||
@@ -305,10 +387,11 @@ mod tests {
|
||||
msg.param.set_int(Param::Forwarded, 1);
|
||||
assert_eq!(
|
||||
msg.get_summary_text(ctx).await,
|
||||
"Forwarded: File \u{2013} foo.bar \u{2013} bla bla"
|
||||
"Forwarded: 📎 foo.bar \u{2013} bla bla"
|
||||
);
|
||||
|
||||
let mut msg = Message::new(Viewtype::File);
|
||||
msg.set_text(some_text.clone());
|
||||
msg.param.set(Param::File, "foo.bar");
|
||||
msg.param.set_cmd(SystemMessage::AutocryptSetupMessage);
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user