mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
Compare commits
6 Commits
fd6dcca192
...
fix-stock-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5ee7a5264 | ||
|
|
46b90e206e | ||
|
|
1928adbe3d | ||
|
|
d82dbdd80c | ||
|
|
a5c09cdf20 | ||
|
|
3658412b0d |
@@ -8,6 +8,7 @@
|
||||
|
||||
### Fixes
|
||||
- fix detection of "All mail", "Trash", "Junk" etc folders. #3760
|
||||
- fix info messages shown for non-dc MUA #3754
|
||||
|
||||
|
||||
## 1.101.0
|
||||
|
||||
54
src/chat.rs
54
src/chat.rs
@@ -32,6 +32,7 @@ use crate::receive_imf::ReceivedMsg;
|
||||
use crate::scheduler::InterruptInfo;
|
||||
use crate::smtp::send_msg_to_smtp;
|
||||
use crate::stock_str;
|
||||
use crate::stock_str::ByContact;
|
||||
use crate::tools::{
|
||||
create_id, create_outgoing_rfc724_mid, create_smeared_timestamp, create_smeared_timestamps,
|
||||
get_abs_path, gm2local_offset, improve_single_line_input, time, IsNoneOrEmpty,
|
||||
@@ -414,7 +415,6 @@ impl ChatId {
|
||||
promote: bool,
|
||||
from_id: ContactId,
|
||||
) -> Result<()> {
|
||||
let msg_text = context.stock_protection_msg(protect, from_id).await;
|
||||
let cmd = match protect {
|
||||
ProtectionStatus::Protected => SystemMessage::ChatProtectionEnabled,
|
||||
ProtectionStatus::Unprotected => SystemMessage::ChatProtectionDisabled,
|
||||
@@ -423,7 +423,11 @@ impl ChatId {
|
||||
if promote {
|
||||
let mut msg = Message {
|
||||
viewtype: Viewtype::Text,
|
||||
text: Some(msg_text),
|
||||
text: Some(
|
||||
context
|
||||
.stock_protection_msg(protect, ByContact::SelfName)
|
||||
.await,
|
||||
),
|
||||
..Default::default()
|
||||
};
|
||||
msg.param.set_cmd(cmd);
|
||||
@@ -432,7 +436,9 @@ impl ChatId {
|
||||
add_info_msg_with_cmd(
|
||||
context,
|
||||
self,
|
||||
&msg_text,
|
||||
&context
|
||||
.stock_protection_msg(protect, ByContact::YouOrName(from_id))
|
||||
.await,
|
||||
cmd,
|
||||
create_smeared_timestamp(context).await,
|
||||
None,
|
||||
@@ -2744,7 +2750,7 @@ pub(crate) async fn add_contact_to_chat_ex(
|
||||
msg.viewtype = Viewtype::Text;
|
||||
|
||||
msg.text =
|
||||
Some(stock_str::msg_add_member(context, contact.get_addr(), ContactId::SELF).await);
|
||||
Some(stock_str::msg_add_member(context, contact.get_addr(), ByContact::SelfName).await);
|
||||
msg.param.set_cmd(SystemMessage::MemberAddedToGroup);
|
||||
msg.param.set(Param::Arg, contact.get_addr());
|
||||
msg.param.set_int(Param::Arg2, from_handshake.into());
|
||||
@@ -2877,13 +2883,13 @@ pub async fn remove_contact_from_chat(
|
||||
if contact.id == ContactId::SELF {
|
||||
set_group_explicitly_left(context, &chat.grpid).await?;
|
||||
msg.text =
|
||||
Some(stock_str::msg_group_left(context, ContactId::SELF).await);
|
||||
Some(stock_str::msg_group_left(context, ByContact::SelfName).await);
|
||||
} else {
|
||||
msg.text = Some(
|
||||
stock_str::msg_del_member(
|
||||
context,
|
||||
contact.get_addr(),
|
||||
ContactId::SELF,
|
||||
ByContact::SelfName,
|
||||
)
|
||||
.await,
|
||||
);
|
||||
@@ -2976,7 +2982,8 @@ pub async fn set_chat_name(context: &Context, chat_id: ChatId, new_name: &str) -
|
||||
if chat.is_promoted() && !chat.is_mailing_list() && chat.typ != Chattype::Broadcast {
|
||||
msg.viewtype = Viewtype::Text;
|
||||
msg.text = Some(
|
||||
stock_str::msg_grp_name(context, &chat.name, &new_name, ContactId::SELF).await,
|
||||
stock_str::msg_grp_name(context, &chat.name, &new_name, ByContact::SelfName)
|
||||
.await,
|
||||
);
|
||||
msg.param.set_cmd(SystemMessage::GroupNameChanged);
|
||||
if !chat.name.is_empty() {
|
||||
@@ -3026,14 +3033,14 @@ pub async fn set_chat_profile_image(
|
||||
if new_image.as_ref().is_empty() {
|
||||
chat.param.remove(Param::ProfileImage);
|
||||
msg.param.remove(Param::Arg);
|
||||
msg.text = Some(stock_str::msg_grp_img_deleted(context, ContactId::SELF).await);
|
||||
msg.text = Some(stock_str::msg_grp_img_deleted(context, ByContact::SelfName).await);
|
||||
} else {
|
||||
let mut image_blob =
|
||||
BlobObject::new_from_path(context, Path::new(new_image.as_ref())).await?;
|
||||
image_blob.recode_to_avatar_size(context).await?;
|
||||
chat.param.set(Param::ProfileImage, image_blob.as_name());
|
||||
msg.param.set(Param::Arg, image_blob.as_name());
|
||||
msg.text = Some(stock_str::msg_grp_img_changed(context, ContactId::SELF).await);
|
||||
msg.text = Some(stock_str::msg_grp_img_changed(context, ByContact::SelfName).await);
|
||||
}
|
||||
chat.update_param(context).await?;
|
||||
if chat.is_promoted() && !chat.is_mailing_list() {
|
||||
@@ -5338,6 +5345,35 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_info_message_wording() -> Result<()> {
|
||||
let alice = TestContext::new_alice().await;
|
||||
let alice_grp = create_group_chat(&alice, ProtectionStatus::Unprotected, "grp").await?;
|
||||
add_contact_to_chat(
|
||||
&alice,
|
||||
alice_grp,
|
||||
Contact::create(&alice, "", "bob@example.net").await?,
|
||||
)
|
||||
.await?;
|
||||
alice.send_text(alice_grp, "alice->bob").await;
|
||||
add_contact_to_chat(
|
||||
&alice,
|
||||
alice_grp,
|
||||
Contact::create(&alice, "", "claire@example.org").await?,
|
||||
)
|
||||
.await?;
|
||||
let sent2 = alice.pop_sent_msg().await;
|
||||
let msg = Message::load_from_db(&alice, sent2.sender_msg_id).await?;
|
||||
|
||||
// For DC, info message reads "You added"; for non-DC MUA, info message should not read "You added"
|
||||
let you_added = "You added";
|
||||
assert!(msg.get_text().unwrap().contains(you_added));
|
||||
assert!(!sent2.payload().contains(you_added));
|
||||
assert!(sent2.payload().contains("added by"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_can_send_group() -> Result<()> {
|
||||
let alice = TestContext::new_alice().await;
|
||||
|
||||
@@ -282,6 +282,24 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_config_name_and_addr(&self) -> String {
|
||||
let name = self
|
||||
.get_config(Config::Displayname)
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_default();
|
||||
let addr = self
|
||||
.get_config(Config::Addr)
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_else(|| "unconfigured".to_string());
|
||||
if !name.is_empty() {
|
||||
format!("{} ({})", name, addr)
|
||||
} else {
|
||||
addr
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the given config key.
|
||||
/// If `None` is passed as a value the value is cleared and set to the default if there is one.
|
||||
pub async fn set_config(&self, key: Config, value: Option<&str>) -> Result<()> {
|
||||
|
||||
@@ -83,6 +83,7 @@ use crate::message::{Message, MessageState, MsgId, Viewtype};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::sql::{self, params_iter};
|
||||
use crate::stock_str;
|
||||
use crate::stock_str::ByContact;
|
||||
use crate::tools::{duration_to_str, time};
|
||||
use std::cmp::max;
|
||||
|
||||
@@ -204,7 +205,7 @@ impl ChatId {
|
||||
}
|
||||
self.inner_set_ephemeral_timer(context, timer).await?;
|
||||
let mut msg = Message::new(Viewtype::Text);
|
||||
msg.text = Some(stock_ephemeral_timer_changed(context, timer, ContactId::SELF).await);
|
||||
msg.text = Some(stock_ephemeral_timer_changed(context, timer, ByContact::SelfName).await);
|
||||
msg.param.set_cmd(SystemMessage::EphemeralTimerChanged);
|
||||
if let Err(err) = send_msg(context, self, &mut msg).await {
|
||||
error!(
|
||||
@@ -220,7 +221,7 @@ impl ChatId {
|
||||
pub(crate) async fn stock_ephemeral_timer_changed(
|
||||
context: &Context,
|
||||
timer: Timer,
|
||||
from_id: ContactId,
|
||||
from_id: ByContact,
|
||||
) -> String {
|
||||
match timer {
|
||||
Timer::Disabled => stock_str::msg_ephemeral_timer_disabled(context, from_id).await,
|
||||
@@ -637,7 +638,12 @@ mod tests {
|
||||
let context = TestContext::new().await;
|
||||
|
||||
assert_eq!(
|
||||
stock_ephemeral_timer_changed(&context, Timer::Disabled, ContactId::SELF).await,
|
||||
stock_ephemeral_timer_changed(
|
||||
&context,
|
||||
Timer::Disabled,
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You disabled message deletion timer."
|
||||
);
|
||||
|
||||
@@ -645,7 +651,7 @@ mod tests {
|
||||
stock_ephemeral_timer_changed(
|
||||
&context,
|
||||
Timer::Enabled { duration: 1 },
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 1 s."
|
||||
@@ -654,7 +660,7 @@ mod tests {
|
||||
stock_ephemeral_timer_changed(
|
||||
&context,
|
||||
Timer::Enabled { duration: 30 },
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 30 s."
|
||||
@@ -663,7 +669,7 @@ mod tests {
|
||||
stock_ephemeral_timer_changed(
|
||||
&context,
|
||||
Timer::Enabled { duration: 60 },
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 1 minute."
|
||||
@@ -672,7 +678,7 @@ mod tests {
|
||||
stock_ephemeral_timer_changed(
|
||||
&context,
|
||||
Timer::Enabled { duration: 90 },
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 1.5 minutes."
|
||||
@@ -681,7 +687,7 @@ mod tests {
|
||||
stock_ephemeral_timer_changed(
|
||||
&context,
|
||||
Timer::Enabled { duration: 30 * 60 },
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 30 minutes."
|
||||
@@ -690,7 +696,7 @@ mod tests {
|
||||
stock_ephemeral_timer_changed(
|
||||
&context,
|
||||
Timer::Enabled { duration: 60 * 60 },
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 1 hour."
|
||||
@@ -699,7 +705,7 @@ mod tests {
|
||||
stock_ephemeral_timer_changed(
|
||||
&context,
|
||||
Timer::Enabled { duration: 5400 },
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 1.5 hours."
|
||||
@@ -710,7 +716,7 @@ mod tests {
|
||||
Timer::Enabled {
|
||||
duration: 2 * 60 * 60
|
||||
},
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 2 hours."
|
||||
@@ -721,7 +727,7 @@ mod tests {
|
||||
Timer::Enabled {
|
||||
duration: 24 * 60 * 60
|
||||
},
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 1 day."
|
||||
@@ -732,7 +738,7 @@ mod tests {
|
||||
Timer::Enabled {
|
||||
duration: 2 * 24 * 60 * 60
|
||||
},
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 2 days."
|
||||
@@ -743,7 +749,7 @@ mod tests {
|
||||
Timer::Enabled {
|
||||
duration: 7 * 24 * 60 * 60
|
||||
},
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 1 week."
|
||||
@@ -754,7 +760,7 @@ mod tests {
|
||||
Timer::Enabled {
|
||||
duration: 4 * 7 * 24 * 60 * 60
|
||||
},
|
||||
ContactId::SELF
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You set message deletion timer to 4 weeks."
|
||||
|
||||
@@ -37,6 +37,7 @@ use crate::reaction::{set_msg_reaction, Reaction};
|
||||
use crate::securejoin::{self, handle_securejoin_handshake, observe_securejoin_on_other_device};
|
||||
use crate::sql;
|
||||
use crate::stock_str;
|
||||
use crate::stock_str::ByContact;
|
||||
use crate::tools::{create_id, extract_grpid_from_rfc724_mid, smeared_time};
|
||||
|
||||
/// This is the struct that is returned after receiving one email (aka MIME message).
|
||||
@@ -933,7 +934,12 @@ async fn add_parts(
|
||||
chat::add_info_msg(
|
||||
context,
|
||||
chat_id,
|
||||
&stock_ephemeral_timer_changed(context, ephemeral_timer, from_id).await,
|
||||
&stock_ephemeral_timer_changed(
|
||||
context,
|
||||
ephemeral_timer,
|
||||
ByContact::YouOrName(from_id),
|
||||
)
|
||||
.await,
|
||||
sort_timestamp,
|
||||
)
|
||||
.await?;
|
||||
@@ -948,7 +954,10 @@ async fn add_parts(
|
||||
}
|
||||
|
||||
if mime_parser.is_system_message == SystemMessage::EphemeralTimerChanged {
|
||||
better_msg = Some(stock_ephemeral_timer_changed(context, ephemeral_timer, from_id).await);
|
||||
better_msg = Some(
|
||||
stock_ephemeral_timer_changed(context, ephemeral_timer, ByContact::YouOrName(from_id))
|
||||
.await,
|
||||
);
|
||||
|
||||
// Do not delete the system message itself.
|
||||
//
|
||||
@@ -996,7 +1005,11 @@ async fn add_parts(
|
||||
// do not return an error as this would result in retrying the message
|
||||
}
|
||||
}
|
||||
better_msg = Some(context.stock_protection_msg(new_status, from_id).await);
|
||||
better_msg = Some(
|
||||
context
|
||||
.stock_protection_msg(new_status, ByContact::YouOrName(from_id))
|
||||
.await,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1601,9 +1614,16 @@ async fn apply_group_changes(
|
||||
match removed_id {
|
||||
Some(contact_id) => {
|
||||
better_msg = if contact_id == from_id {
|
||||
Some(stock_str::msg_group_left(context, from_id).await)
|
||||
Some(stock_str::msg_group_left(context, ByContact::YouOrName(from_id)).await)
|
||||
} else {
|
||||
Some(stock_str::msg_del_member(context, &removed_addr, from_id).await)
|
||||
Some(
|
||||
stock_str::msg_del_member(
|
||||
context,
|
||||
&removed_addr,
|
||||
ByContact::YouOrName(from_id),
|
||||
)
|
||||
.await,
|
||||
)
|
||||
};
|
||||
}
|
||||
None => warn!(context, "removed {:?} has no contact_id", removed_addr),
|
||||
@@ -1614,7 +1634,10 @@ async fn apply_group_changes(
|
||||
.get_header(HeaderDef::ChatGroupMemberAdded)
|
||||
.cloned()
|
||||
{
|
||||
better_msg = Some(stock_str::msg_add_member(context, &added_member, from_id).await);
|
||||
better_msg = Some(
|
||||
stock_str::msg_add_member(context, &added_member, ByContact::YouOrName(from_id))
|
||||
.await,
|
||||
);
|
||||
recreate_member_list = true;
|
||||
} else if let Some(old_name) = mime_parser.get_header(HeaderDef::ChatGroupNameChanged) {
|
||||
if let Some(grpname) = mime_parser
|
||||
@@ -1636,8 +1659,15 @@ async fn apply_group_changes(
|
||||
send_event_chat_modified = true;
|
||||
}
|
||||
|
||||
better_msg =
|
||||
Some(stock_str::msg_grp_name(context, old_name, grpname, from_id).await);
|
||||
better_msg = Some(
|
||||
stock_str::msg_grp_name(
|
||||
context,
|
||||
old_name,
|
||||
grpname,
|
||||
ByContact::YouOrName(from_id),
|
||||
)
|
||||
.await,
|
||||
);
|
||||
}
|
||||
} else if let Some(value) = mime_parser.get_header(HeaderDef::ChatContent) {
|
||||
if value == "group-avatar-changed" {
|
||||
@@ -1645,12 +1675,14 @@ async fn apply_group_changes(
|
||||
// this is just an explicit message containing the group-avatar,
|
||||
// apart from that, the group-avatar is send along with various other messages
|
||||
better_msg = match avatar_action {
|
||||
AvatarAction::Delete => {
|
||||
Some(stock_str::msg_grp_img_deleted(context, from_id).await)
|
||||
}
|
||||
AvatarAction::Change(_) => {
|
||||
Some(stock_str::msg_grp_img_changed(context, from_id).await)
|
||||
}
|
||||
AvatarAction::Delete => Some(
|
||||
stock_str::msg_grp_img_deleted(context, ByContact::YouOrName(from_id))
|
||||
.await,
|
||||
),
|
||||
AvatarAction::Change(_) => Some(
|
||||
stock_str::msg_grp_img_changed(context, ByContact::YouOrName(from_id))
|
||||
.await,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
424
src/stock_str.rs
424
src/stock_str.rs
@@ -404,6 +404,11 @@ pub enum StockMessage {
|
||||
ProtectionDisabledBy = 161,
|
||||
}
|
||||
|
||||
pub(crate) enum ByContact {
|
||||
YouOrName(ContactId),
|
||||
SelfName,
|
||||
}
|
||||
|
||||
impl StockMessage {
|
||||
/// Default untranslated strings for stock messages.
|
||||
///
|
||||
@@ -553,29 +558,45 @@ pub(crate) async fn msg_grp_name(
|
||||
context: &Context,
|
||||
from_group: impl AsRef<str>,
|
||||
to_group: impl AsRef<str>,
|
||||
by_contact: ContactId,
|
||||
by_contact: ByContact,
|
||||
) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouChangedGrpName)
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouChangedGrpName)
|
||||
.await
|
||||
.replace1(from_group)
|
||||
.replace2(to_group)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgGrpNameChangedBy)
|
||||
.await
|
||||
.replace1(from_group)
|
||||
.replace2(to_group)
|
||||
.replace3(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgGrpNameChangedBy)
|
||||
.await
|
||||
.replace1(from_group)
|
||||
.replace2(to_group)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgGrpNameChangedBy)
|
||||
.await
|
||||
.replace1(from_group)
|
||||
.replace2(to_group)
|
||||
.replace3(by_contact.get_stock_name(context).await)
|
||||
.replace3(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn msg_grp_img_changed(context: &Context, by_contact: ContactId) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouChangedGrpImg).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgGrpImgChangedBy)
|
||||
pub(crate) async fn msg_grp_img_changed(context: &Context, by_contact: ByContact) -> String {
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouChangedGrpImg).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgGrpImgChangedBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgGrpImgChangedBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
.replace1(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,7 +607,7 @@ pub(crate) async fn msg_grp_img_changed(context: &Context, by_contact: ContactId
|
||||
pub(crate) async fn msg_add_member(
|
||||
context: &Context,
|
||||
added_member_addr: impl AsRef<str>,
|
||||
by_contact: ContactId,
|
||||
by_contact: ByContact,
|
||||
) -> String {
|
||||
let addr = added_member_addr.as_ref();
|
||||
let who = match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await {
|
||||
@@ -596,15 +617,23 @@ pub(crate) async fn msg_add_member(
|
||||
.unwrap_or_else(|_| addr.to_string()),
|
||||
_ => addr.to_string(),
|
||||
};
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouAddMember)
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouAddMember)
|
||||
.await
|
||||
.replace1(who)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgAddMemberBy)
|
||||
.await
|
||||
.replace1(who)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgAddMemberBy)
|
||||
.await
|
||||
.replace1(who)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgAddMemberBy)
|
||||
.await
|
||||
.replace1(who)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
.replace2(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,7 +644,7 @@ pub(crate) async fn msg_add_member(
|
||||
pub(crate) async fn msg_del_member(
|
||||
context: &Context,
|
||||
removed_member_addr: impl AsRef<str>,
|
||||
by_contact: ContactId,
|
||||
by_contact: ByContact,
|
||||
) -> String {
|
||||
let addr = removed_member_addr.as_ref();
|
||||
let who = match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await {
|
||||
@@ -625,26 +654,41 @@ pub(crate) async fn msg_del_member(
|
||||
.unwrap_or_else(|_| addr.to_string()),
|
||||
_ => addr.to_string(),
|
||||
};
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouDelMember)
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouDelMember)
|
||||
.await
|
||||
.replace1(who)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgDelMemberBy)
|
||||
.await
|
||||
.replace1(who)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgDelMemberBy)
|
||||
.await
|
||||
.replace1(who)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgDelMemberBy)
|
||||
.await
|
||||
.replace1(who)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
.replace2(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
/// Stock string: `Group left.`.
|
||||
pub(crate) async fn msg_group_left(context: &Context, by_contact: ContactId) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouLeftGroup).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgGroupLeftBy)
|
||||
pub(crate) async fn msg_group_left(context: &Context, by_contact: ByContact) -> String {
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouLeftGroup).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgGroupLeftBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgGroupLeftBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
.replace1(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,13 +735,20 @@ pub(crate) async fn read_rcpt_mail_body(context: &Context, message: impl AsRef<s
|
||||
}
|
||||
|
||||
/// Stock string: `Group image deleted.`.
|
||||
pub(crate) async fn msg_grp_img_deleted(context: &Context, by_contact: ContactId) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouDeletedGrpImg).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgGrpImgDeletedBy)
|
||||
pub(crate) async fn msg_grp_img_deleted(context: &Context, by_contact: ByContact) -> String {
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouDeletedGrpImg).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgGrpImgDeletedBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgGrpImgDeletedBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
.replace1(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -893,14 +944,21 @@ pub(crate) async fn failed_sending_to(context: &Context, name: impl AsRef<str>)
|
||||
/// Stock string: `Message deletion timer is disabled.`.
|
||||
pub(crate) async fn msg_ephemeral_timer_disabled(
|
||||
context: &Context,
|
||||
by_contact: ContactId,
|
||||
by_contact: ByContact,
|
||||
) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouDisabledEphemeralTimer).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerDisabledBy)
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouDisabledEphemeralTimer).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerDisabledBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgEphemeralTimerDisabledBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
.replace1(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -908,61 +966,97 @@ pub(crate) async fn msg_ephemeral_timer_disabled(
|
||||
pub(crate) async fn msg_ephemeral_timer_enabled(
|
||||
context: &Context,
|
||||
timer: impl AsRef<str>,
|
||||
by_contact: ContactId,
|
||||
by_contact: ByContact,
|
||||
) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEnabledEphemeralTimer)
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEnabledEphemeralTimer)
|
||||
.await
|
||||
.replace1(timer)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerEnabledBy)
|
||||
.await
|
||||
.replace1(timer)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgEphemeralTimerEnabledBy)
|
||||
.await
|
||||
.replace1(timer)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerEnabledBy)
|
||||
.await
|
||||
.replace1(timer)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
.replace2(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
/// Stock string: `Message deletion timer is set to 1 minute.`.
|
||||
pub(crate) async fn msg_ephemeral_timer_minute(context: &Context, by_contact: ContactId) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerMinute).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerMinuteBy)
|
||||
pub(crate) async fn msg_ephemeral_timer_minute(context: &Context, by_contact: ByContact) -> String {
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerMinute).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerMinuteBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgEphemeralTimerMinuteBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
.replace1(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
/// Stock string: `Message deletion timer is set to 1 hour.`.
|
||||
pub(crate) async fn msg_ephemeral_timer_hour(context: &Context, by_contact: ContactId) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerHour).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerHourBy)
|
||||
pub(crate) async fn msg_ephemeral_timer_hour(context: &Context, by_contact: ByContact) -> String {
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerHour).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerHourBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgEphemeralTimerHourBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
.replace1(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
/// Stock string: `Message deletion timer is set to 1 day.`.
|
||||
pub(crate) async fn msg_ephemeral_timer_day(context: &Context, by_contact: ContactId) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerDay).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerDayBy)
|
||||
pub(crate) async fn msg_ephemeral_timer_day(context: &Context, by_contact: ByContact) -> String {
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerDay).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerDayBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgEphemeralTimerDayBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
.replace1(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
/// Stock string: `Message deletion timer is set to 1 week.`.
|
||||
pub(crate) async fn msg_ephemeral_timer_week(context: &Context, by_contact: ContactId) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerWeek).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerWeekBy)
|
||||
pub(crate) async fn msg_ephemeral_timer_week(context: &Context, by_contact: ByContact) -> String {
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerWeek).await
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerWeekBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgEphemeralTimerWeekBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
.replace1(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1004,24 +1098,38 @@ pub(crate) async fn error_no_network(context: &Context) -> String {
|
||||
}
|
||||
|
||||
/// Stock string: `Chat protection enabled.`.
|
||||
pub(crate) async fn protection_enabled(context: &Context, by_contact: ContactId) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::YouEnabledProtection).await
|
||||
} else {
|
||||
translated(context, StockMessage::ProtectionEnabledBy)
|
||||
pub(crate) async fn protection_enabled(context: &Context, by_contact: ByContact) -> String {
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::YouEnabledProtection).await
|
||||
} else {
|
||||
translated(context, StockMessage::ProtectionEnabledBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::ProtectionEnabledBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
.replace1(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
/// Stock string: `Chat protection disabled.`.
|
||||
pub(crate) async fn protection_disabled(context: &Context, by_contact: ContactId) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::YouDisabledProtection).await
|
||||
} else {
|
||||
translated(context, StockMessage::ProtectionDisabledBy)
|
||||
pub(crate) async fn protection_disabled(context: &Context, by_contact: ByContact) -> String {
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::YouDisabledProtection).await
|
||||
} else {
|
||||
translated(context, StockMessage::ProtectionDisabledBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::ProtectionDisabledBy)
|
||||
.await
|
||||
.replace1(by_contact.get_stock_name(context).await)
|
||||
.replace1(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1044,17 +1152,25 @@ pub(crate) async fn delete_server_turned_off(context: &Context) -> String {
|
||||
pub(crate) async fn msg_ephemeral_timer_minutes(
|
||||
context: &Context,
|
||||
minutes: impl AsRef<str>,
|
||||
by_contact: ContactId,
|
||||
by_contact: ByContact,
|
||||
) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerMinutes)
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerMinutes)
|
||||
.await
|
||||
.replace1(minutes)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerMinutesBy)
|
||||
.await
|
||||
.replace1(minutes)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgEphemeralTimerMinutesBy)
|
||||
.await
|
||||
.replace1(minutes)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerMinutesBy)
|
||||
.await
|
||||
.replace1(minutes)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
.replace2(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1062,17 +1178,25 @@ pub(crate) async fn msg_ephemeral_timer_minutes(
|
||||
pub(crate) async fn msg_ephemeral_timer_hours(
|
||||
context: &Context,
|
||||
hours: impl AsRef<str>,
|
||||
by_contact: ContactId,
|
||||
by_contact: ByContact,
|
||||
) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerHours)
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerHours)
|
||||
.await
|
||||
.replace1(hours)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerHoursBy)
|
||||
.await
|
||||
.replace1(hours)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgEphemeralTimerHoursBy)
|
||||
.await
|
||||
.replace1(hours)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerHoursBy)
|
||||
.await
|
||||
.replace1(hours)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
.replace2(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1080,17 +1204,25 @@ pub(crate) async fn msg_ephemeral_timer_hours(
|
||||
pub(crate) async fn msg_ephemeral_timer_days(
|
||||
context: &Context,
|
||||
days: impl AsRef<str>,
|
||||
by_contact: ContactId,
|
||||
by_contact: ByContact,
|
||||
) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerDays)
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerDays)
|
||||
.await
|
||||
.replace1(days)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerDaysBy)
|
||||
.await
|
||||
.replace1(days)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgEphemeralTimerDaysBy)
|
||||
.await
|
||||
.replace1(days)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerDaysBy)
|
||||
.await
|
||||
.replace1(days)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
.replace2(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1098,17 +1230,25 @@ pub(crate) async fn msg_ephemeral_timer_days(
|
||||
pub(crate) async fn msg_ephemeral_timer_weeks(
|
||||
context: &Context,
|
||||
weeks: impl AsRef<str>,
|
||||
by_contact: ContactId,
|
||||
by_contact: ByContact,
|
||||
) -> String {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerWeeks)
|
||||
match by_contact {
|
||||
ByContact::YouOrName(by_contact) => {
|
||||
if by_contact == ContactId::SELF {
|
||||
translated(context, StockMessage::MsgYouEphemeralTimerWeeks)
|
||||
.await
|
||||
.replace1(weeks)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerWeeksBy)
|
||||
.await
|
||||
.replace1(weeks)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
}
|
||||
}
|
||||
ByContact::SelfName => translated(context, StockMessage::MsgEphemeralTimerWeeksBy)
|
||||
.await
|
||||
.replace1(weeks)
|
||||
} else {
|
||||
translated(context, StockMessage::MsgEphemeralTimerWeeksBy)
|
||||
.await
|
||||
.replace1(weeks)
|
||||
.replace2(by_contact.get_stock_name(context).await)
|
||||
.replace2(context.get_config_name_and_addr().await),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1266,7 +1406,7 @@ impl Context {
|
||||
pub(crate) async fn stock_protection_msg(
|
||||
&self,
|
||||
protect: ProtectionStatus,
|
||||
from_id: ContactId,
|
||||
from_id: ByContact,
|
||||
) -> String {
|
||||
match protect {
|
||||
ProtectionStatus::Unprotected => protection_enabled(self, from_id).await,
|
||||
@@ -1394,7 +1534,12 @@ mod tests {
|
||||
async fn test_stock_system_msg_add_member_by_me() {
|
||||
let t = TestContext::new().await;
|
||||
assert_eq!(
|
||||
msg_add_member(&t, "alice@example.org", ContactId::SELF).await,
|
||||
msg_add_member(
|
||||
&t,
|
||||
"alice@example.org",
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You added member alice@example.org."
|
||||
)
|
||||
}
|
||||
@@ -1406,7 +1551,12 @@ mod tests {
|
||||
.await
|
||||
.expect("failed to create contact");
|
||||
assert_eq!(
|
||||
msg_add_member(&t, "alice@example.org", ContactId::SELF).await,
|
||||
msg_add_member(
|
||||
&t,
|
||||
"alice@example.org",
|
||||
ByContact::YouOrName(ContactId::SELF)
|
||||
)
|
||||
.await,
|
||||
"You added member Alice (alice@example.org)."
|
||||
);
|
||||
}
|
||||
@@ -1423,11 +1573,27 @@ mod tests {
|
||||
.expect("failed to create bob")
|
||||
};
|
||||
assert_eq!(
|
||||
msg_add_member(&t, "alice@example.org", contact_id,).await,
|
||||
msg_add_member(&t, "alice@example.org", ByContact::YouOrName(contact_id)).await,
|
||||
"Member Alice (alice@example.org) added by Bob (bob@example.com)."
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_stock_system_msg_add_member_by_self_name() -> Result<()> {
|
||||
let t = TestContext::new_bob().await;
|
||||
assert_eq!(
|
||||
msg_add_member(&t, "alice@example.org", ByContact::SelfName).await,
|
||||
"Member alice@example.org added by bob@example.net."
|
||||
);
|
||||
|
||||
t.set_config(Config::Displayname, Some("Bobby")).await?;
|
||||
assert_eq!(
|
||||
msg_add_member(&t, "alice@example.org", ByContact::SelfName).await,
|
||||
"Member alice@example.org added by Bobby (bob@example.net)."
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_quota_exceeding_stock_str() -> Result<()> {
|
||||
let t = TestContext::new().await;
|
||||
|
||||
Reference in New Issue
Block a user