feat: get contact-id for info messages (#6714)

instead of showing addresses in info message, provide an API to get the
contact-id.

UI can then make the info message tappable and open the contact profile
in scope

the corresponding iOS PR - incl. **screencast** - is at
https://github.com/deltachat/deltachat-ios/pull/2652 ; jsonrpc can come
in a subsequent PR when things are settled on android/ios

the number of parameters in `add_info_msg_with_cmd` gets bigger and
bigger, however, i did not want to refactor this in this PR. it is also
not really adding complexity



closes #6702

---------

Co-authored-by: link2xt <link2xt@testrun.org>
Co-authored-by: Hocuri <hocuri@gmx.de>
This commit is contained in:
bjoern
2025-03-31 18:56:57 +02:00
committed by GitHub
parent e2f9c80cd5
commit 97b0d09ed2
18 changed files with 311 additions and 62 deletions

View File

@@ -582,7 +582,18 @@ impl ChatId {
ProtectionStatus::Unprotected => SystemMessage::ChatProtectionDisabled,
ProtectionStatus::ProtectionBroken => SystemMessage::ChatProtectionDisabled,
};
add_info_msg_with_cmd(context, self, &text, cmd, timestamp_sort, None, None, None).await?;
add_info_msg_with_cmd(
context,
self,
&text,
cmd,
timestamp_sort,
None,
None,
None,
None,
)
.await?;
Ok(())
}
@@ -1791,6 +1802,7 @@ impl Chat {
Some(now),
None,
None,
None,
)
.await?;
context.emit_event(EventType::ChatModified(self.id));
@@ -3942,6 +3954,8 @@ pub(crate) async fn add_contact_to_chat_ex(
msg.param.set_cmd(SystemMessage::MemberAddedToGroup);
msg.param.set(Param::Arg, contact_addr);
msg.param.set_int(Param::Arg2, from_handshake.into());
msg.param
.set_int(Param::ContactAddedRemoved, contact.id.to_u32() as i32);
send_msg(context, chat_id, &mut msg).await?;
sync = Nosync;
@@ -4139,6 +4153,8 @@ pub async fn remove_contact_from_chat(
}
msg.param.set_cmd(SystemMessage::MemberRemovedFromGroup);
msg.param.set(Param::Arg, contact.get_addr().to_lowercase());
msg.param
.set(Param::ContactAddedRemoved, contact.id.to_u32() as i32);
let res = send_msg(context, chat_id, &mut msg).await;
if contact_id == ContactId::SELF {
res?;
@@ -4737,13 +4753,17 @@ pub(crate) async fn add_info_msg_with_cmd(
timestamp_sent_rcvd: Option<i64>,
parent: Option<&Message>,
from_id: Option<ContactId>,
added_removed_id: Option<ContactId>,
) -> Result<MsgId> {
let rfc724_mid = create_outgoing_rfc724_mid();
let ephemeral_timer = chat_id.get_ephemeral_timer(context).await?;
let mut param = Params::new();
if cmd != SystemMessage::Unknown {
param.set_cmd(cmd)
param.set_cmd(cmd);
}
if let Some(contact_id) = added_removed_id {
param.set(Param::ContactAddedRemoved, contact_id.to_u32().to_string());
}
let row_id =
@@ -4791,6 +4811,7 @@ pub(crate) async fn add_info_msg(
None,
None,
None,
None,
)
.await
}

View File

@@ -1,6 +1,7 @@
use super::*;
use crate::chatlist::get_archived_cnt;
use crate::constants::{DC_GCL_ARCHIVED_ONLY, DC_GCL_NO_SPECIALS};
use crate::ephemeral::Timer;
use crate::headerdef::HeaderDef;
use crate::imex::{has_backup, imex, ImexMode};
use crate::message::{delete_msgs, MessengerMessage};
@@ -331,11 +332,12 @@ async fn test_member_add_remove() -> Result<()> {
// Alice adds Bob to the chat.
add_contact_to_chat(&alice, alice_chat_id, alice_bob_contact_id).await?;
let sent = alice.pop_sent_msg().await;
// Locally set name "robert" should not leak.
assert!(!sent.payload.contains("robert"));
assert_eq!(
sent.load_from_db().await.get_text(),
"You added member robert (bob@example.net)."
"You added member robert."
);
// Alice removes Bob from the chat.
@@ -344,7 +346,7 @@ async fn test_member_add_remove() -> Result<()> {
assert!(!sent.payload.contains("robert"));
assert_eq!(
sent.load_from_db().await.get_text(),
"You removed member robert (bob@example.net)."
"You removed member robert."
);
// Alice leaves the chat.
@@ -412,7 +414,7 @@ async fn test_parallel_member_remove() -> Result<()> {
// Test that remove message is rewritten.
assert_eq!(
bob_received_remove_msg.get_text(),
"Member Me (bob@example.net) removed by alice@example.org."
"Member Me removed by alice@example.org."
);
Ok(())
@@ -521,6 +523,14 @@ async fn test_modify_chat_multi_device() -> Result<()> {
assert!(a2_msg.is_system_message());
assert_eq!(a1_msg.get_info_type(), SystemMessage::GroupNameChanged);
assert_eq!(a2_msg.get_info_type(), SystemMessage::GroupNameChanged);
assert_eq!(
a1_msg.get_info_contact_id(&a1).await?,
Some(ContactId::SELF)
);
assert_eq!(
a2_msg.get_info_contact_id(&a2).await?,
Some(ContactId::SELF)
);
assert_eq!(Chat::load_from_db(&a1, a1_chat_id).await?.name, "bar");
assert_eq!(Chat::load_from_db(&a2, a2_chat_id).await?.name, "bar");
@@ -1574,6 +1584,7 @@ async fn test_add_info_msg_with_cmd() -> Result<()> {
None,
None,
None,
None,
)
.await?;
@@ -3332,6 +3343,128 @@ async fn test_do_not_overwrite_draft() -> Result<()> {
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_info_contact_id() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await;
let alice2 = &tcm.alice().await;
let bob = &tcm.bob().await;
async fn pop_recv_and_check(
alice: &TestContext,
alice2: &TestContext,
bob: &TestContext,
expected_type: SystemMessage,
expected_alice_id: ContactId,
expected_bob_id: ContactId,
) -> Result<()> {
let sent_msg = alice.pop_sent_msg().await;
let msg = Message::load_from_db(alice, sent_msg.sender_msg_id).await?;
assert_eq!(msg.get_info_type(), expected_type);
assert_eq!(
msg.get_info_contact_id(alice).await?,
Some(expected_alice_id)
);
let msg = alice2.recv_msg(&sent_msg).await;
assert_eq!(msg.get_info_type(), expected_type);
assert_eq!(
msg.get_info_contact_id(alice2).await?,
Some(expected_alice_id)
);
let msg = bob.recv_msg(&sent_msg).await;
assert_eq!(msg.get_info_type(), expected_type);
assert_eq!(msg.get_info_contact_id(bob).await?, Some(expected_bob_id));
Ok(())
}
// Alice creates group, Bob receives group
let alice_chat_id = alice
.create_group_with_members(ProtectionStatus::Unprotected, "play", &[bob])
.await;
let sent_msg1 = alice.send_text(alice_chat_id, "moin").await;
let msg = bob.recv_msg(&sent_msg1).await;
let bob_alice_id = msg.from_id;
assert!(!bob_alice_id.is_special());
// Alice does group changes, Bob receives them
set_chat_name(alice, alice_chat_id, "games").await?;
pop_recv_and_check(
alice,
alice2,
bob,
SystemMessage::GroupNameChanged,
ContactId::SELF,
bob_alice_id,
)
.await?;
let file = alice.get_blobdir().join("avatar.png");
let bytes = include_bytes!("../../test-data/image/avatar64x64.png");
tokio::fs::write(&file, bytes).await?;
set_chat_profile_image(alice, alice_chat_id, file.to_str().unwrap()).await?;
pop_recv_and_check(
alice,
alice2,
bob,
SystemMessage::GroupImageChanged,
ContactId::SELF,
bob_alice_id,
)
.await?;
alice_chat_id
.set_ephemeral_timer(alice, Timer::Enabled { duration: 60 })
.await?;
pop_recv_and_check(
alice,
alice2,
bob,
SystemMessage::EphemeralTimerChanged,
ContactId::SELF,
bob_alice_id,
)
.await?;
let fiona_id = alice.add_or_lookup_contact_id(&tcm.fiona().await).await; // contexts are in sync, fiona_id is same everywhere
add_contact_to_chat(alice, alice_chat_id, fiona_id).await?;
pop_recv_and_check(
alice,
alice2,
bob,
SystemMessage::MemberAddedToGroup,
fiona_id,
fiona_id,
)
.await?;
remove_contact_from_chat(alice, alice_chat_id, fiona_id).await?;
pop_recv_and_check(
alice,
alice2,
bob,
SystemMessage::MemberRemovedFromGroup,
fiona_id,
fiona_id,
)
.await?;
// When fiona_id is deleted, get_info_contact_id() returns None.
// We raw delete in db as Contact::delete() leaves a tombstone (which is great as the tap works longer then)
alice
.sql
.execute("DELETE FROM contacts WHERE id=?", (fiona_id,))
.await?;
let msg = alice.get_last_msg().await;
assert_eq!(msg.get_info_type(), SystemMessage::MemberRemovedFromGroup);
assert!(msg.get_info_contact_id(alice).await?.is_none());
Ok(())
}
/// Test group consistency.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_add_member_bug() -> Result<()> {

View File

@@ -1406,16 +1406,13 @@ impl Contact {
&self.addr
}
/// Get a summary of authorized name and address.
///
/// The returned string is either "Name (email@domain.com)" or just
/// "email@domain.com" if the name is unset.
/// Get authorized name or address.
///
/// This string is suitable for sending over email
/// as it does not leak the locally set name.
pub fn get_authname_n_addr(&self) -> String {
pub(crate) fn get_authname_or_addr(&self) -> String {
if !self.authname.is_empty() {
format!("{} ({})", self.authname, self.addr)
(&self.authname).into()
} else {
(&self.addr).into()
}

View File

@@ -936,6 +936,51 @@ impl Message {
self.param.get_cmd()
}
/// Return the contact ID of the profile to open when tapping the info message.
pub async fn get_info_contact_id(&self, context: &Context) -> Result<Option<ContactId>> {
match self.param.get_cmd() {
SystemMessage::GroupNameChanged
| SystemMessage::GroupImageChanged
| SystemMessage::EphemeralTimerChanged => {
if self.from_id != ContactId::INFO {
Ok(Some(self.from_id))
} else {
Ok(None)
}
}
SystemMessage::MemberAddedToGroup | SystemMessage::MemberRemovedFromGroup => {
if let Some(contact_i32) = self.param.get_int(Param::ContactAddedRemoved) {
let contact_id = ContactId::new(contact_i32.try_into()?);
if contact_id == ContactId::SELF
|| Contact::real_exists_by_id(context, contact_id).await?
{
Ok(Some(contact_id))
} else {
Ok(None)
}
} else {
Ok(None)
}
}
SystemMessage::AutocryptSetupMessage
| SystemMessage::SecurejoinMessage
| SystemMessage::LocationStreamingEnabled
| SystemMessage::LocationOnly
| SystemMessage::ChatProtectionEnabled
| SystemMessage::ChatProtectionDisabled
| SystemMessage::InvalidUnencryptedMail
| SystemMessage::SecurejoinWait
| SystemMessage::SecurejoinWaitTimeout
| SystemMessage::MultiDeviceSync
| SystemMessage::WebxdcStatusUpdate
| SystemMessage::WebxdcInfoMessage
| SystemMessage::IrohNodeAddr
| SystemMessage::Unknown => Ok(None),
}
}
/// Returns true if the message is a system message.
pub fn is_system_message(&self) -> bool {
let cmd = self.param.get_cmd();

View File

@@ -215,6 +215,9 @@ pub enum Param {
/// For messages: Message text was edited.
IsEdited = b'L',
/// For info messages: Contact ID in added or removed to a group.
ContactAddedRemoved = b'5',
}
/// An object for handling key=value parameter lists.

View File

@@ -748,6 +748,7 @@ impl Peerstate {
Some(timestamp),
None,
None,
None,
)
.await?;
}

View File

@@ -1451,13 +1451,13 @@ async fn add_parts(
None => better_msg = Some(m),
Some(_) => {
if !m.is_empty() {
group_changes.extra_msgs.push((m, is_system_message))
group_changes.extra_msgs.push((m, is_system_message, None))
}
}
}
}
for (group_changes_msg, cmd) in group_changes.extra_msgs {
for (group_changes_msg, cmd, added_removed_id) in group_changes.extra_msgs {
chat::add_info_msg_with_cmd(
context,
chat_id,
@@ -1467,6 +1467,7 @@ async fn add_parts(
None,
None,
None,
added_removed_id,
)
.await?;
}
@@ -1550,6 +1551,10 @@ async fn add_parts(
let part_is_empty =
typ == Viewtype::Text && msg.is_empty() && part.param.get(Param::Quote).is_none();
if let Some(contact_id) = group_changes.added_removed_id {
param.set(Param::ContactAddedRemoved, contact_id.to_u32().to_string());
}
save_mime_modified |= mime_parser.is_mime_modified && !part_is_empty && !hidden;
let save_mime_modified = save_mime_modified && parts.peek().is_none();
@@ -2334,10 +2339,12 @@ struct GroupChangesInfo {
/// Optional: A better message that should replace the original system message.
/// If this is an empty string, the original system message should be trashed.
better_msg: Option<String>,
/// Added/removed contact `better_msg` refers to.
added_removed_id: Option<ContactId>,
/// If true, the user should not be notified about the group change.
silent: bool,
/// A list of additional group changes messages that should be shown in the chat.
extra_msgs: Vec<(String, SystemMessage)>,
extra_msgs: Vec<(String, SystemMessage, Option<ContactId>)>,
}
/// Apply group member list, name, avatar and protection status changes from the MIME message.
@@ -2654,6 +2661,11 @@ async fn apply_group_changes(
}
Ok(GroupChangesInfo {
better_msg,
added_removed_id: if added_id.is_some() {
added_id
} else {
removed_id
},
silent,
extra_msgs: group_changes_msgs,
})
@@ -2665,7 +2677,7 @@ async fn group_changes_msgs(
added_ids: &HashSet<ContactId>,
removed_ids: &HashSet<ContactId>,
chat_id: ChatId,
) -> Result<Vec<(String, SystemMessage)>> {
) -> Result<Vec<(String, SystemMessage, Option<ContactId>)>> {
let mut group_changes_msgs = Vec::new();
if !added_ids.is_empty() {
warn!(
@@ -2686,6 +2698,7 @@ async fn group_changes_msgs(
stock_str::msg_add_member_local(context, contact.get_addr(), ContactId::UNDEFINED)
.await,
SystemMessage::MemberAddedToGroup,
Some(contact.id),
));
}
for contact_id in removed_ids {
@@ -2694,6 +2707,7 @@ async fn group_changes_msgs(
stock_str::msg_del_member_local(context, contact.get_addr(), ContactId::UNDEFINED)
.await,
SystemMessage::MemberRemovedFromGroup,
Some(contact.id),
));
}

View File

@@ -126,6 +126,7 @@ pub(super) async fn start_protocol(context: &Context, invite: QrInvite) -> Resul
Some(ts_start),
None,
None,
None,
)
.await?;
chat_id.spawn_securejoin_wait(context, constants::SECUREJOIN_WAIT_TIMEOUT);

View File

@@ -439,6 +439,7 @@ pub(crate) async fn send_msg_to_smtp(
None,
None,
None,
None,
)
.await?;
};

View File

@@ -537,14 +537,6 @@ trait StockStringMods: AsRef<str> + Sized {
}
impl ContactId {
/// Get contact name and address for stock string, e.g. `Bob (bob@example.net)`
async fn get_stock_name_n_addr(self, context: &Context) -> String {
Contact::get_by_id(context, self)
.await
.map(|contact| contact.get_name_n_addr())
.unwrap_or_else(|_| self.to_string())
}
/// Get contact name, e.g. `Bob`, or `bob@example.net` if no name is set.
async fn get_stock_name(self, context: &Context) -> String {
Contact::get_by_id(context, self)
@@ -613,7 +605,7 @@ pub(crate) async fn msg_grp_name(
.await
.replace1(from_group)
.replace2(to_group)
.replace3(&by_contact.get_stock_name_n_addr(context).await)
.replace3(&by_contact.get_stock_name(context).await)
}
}
@@ -623,7 +615,7 @@ pub(crate) async fn msg_grp_img_changed(context: &Context, by_contact: ContactId
} else {
translated(context, StockMessage::MsgGrpImgChangedBy)
.await
.replace1(&by_contact.get_stock_name_n_addr(context).await)
.replace1(&by_contact.get_stock_name(context).await)
}
}
@@ -637,7 +629,7 @@ pub(crate) async fn msg_add_member_remote(context: &Context, added_member_addr:
let whom = &match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await {
Ok(Some(contact_id)) => Contact::get_by_id(context, contact_id)
.await
.map(|contact| contact.get_authname_n_addr())
.map(|contact| contact.get_authname_or_addr())
.unwrap_or_else(|_| addr.to_string()),
_ => addr.to_string(),
};
@@ -659,7 +651,7 @@ pub(crate) async fn msg_add_member_local(
let whom = &match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await {
Ok(Some(contact_id)) => Contact::get_by_id(context, contact_id)
.await
.map(|contact| contact.get_name_n_addr())
.map(|contact| contact.get_display_name().to_string())
.unwrap_or_else(|_| addr.to_string()),
_ => addr.to_string(),
};
@@ -675,7 +667,7 @@ pub(crate) async fn msg_add_member_local(
translated(context, StockMessage::MsgAddMemberBy)
.await
.replace1(whom)
.replace2(&by_contact.get_stock_name_n_addr(context).await)
.replace2(&by_contact.get_stock_name(context).await)
}
}
@@ -688,7 +680,7 @@ pub(crate) async fn msg_del_member_remote(context: &Context, removed_member_addr
let whom = &match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await {
Ok(Some(contact_id)) => Contact::get_by_id(context, contact_id)
.await
.map(|contact| contact.get_authname_n_addr())
.map(|contact| contact.get_authname_or_addr())
.unwrap_or_else(|_| addr.to_string()),
_ => addr.to_string(),
};
@@ -710,7 +702,7 @@ pub(crate) async fn msg_del_member_local(
let whom = &match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await {
Ok(Some(contact_id)) => Contact::get_by_id(context, contact_id)
.await
.map(|contact| contact.get_name_n_addr())
.map(|contact| contact.get_display_name().to_string())
.unwrap_or_else(|_| addr.to_string()),
_ => addr.to_string(),
};
@@ -726,7 +718,7 @@ pub(crate) async fn msg_del_member_local(
translated(context, StockMessage::MsgDelMemberBy)
.await
.replace1(whom)
.replace2(&by_contact.get_stock_name_n_addr(context).await)
.replace2(&by_contact.get_stock_name(context).await)
}
}
@@ -742,7 +734,7 @@ pub(crate) async fn msg_group_left_local(context: &Context, by_contact: ContactI
} else {
translated(context, StockMessage::MsgGroupLeftBy)
.await
.replace1(&by_contact.get_stock_name_n_addr(context).await)
.replace1(&by_contact.get_stock_name(context).await)
}
}
@@ -804,7 +796,7 @@ pub(crate) async fn msg_grp_img_deleted(context: &Context, by_contact: ContactId
} else {
translated(context, StockMessage::MsgGrpImgDeletedBy)
.await
.replace1(&by_contact.get_stock_name_n_addr(context).await)
.replace1(&by_contact.get_stock_name(context).await)
}
}
@@ -821,7 +813,7 @@ pub(crate) async fn secure_join_started(
if let Ok(contact) = Contact::get_by_id(context, inviter_contact_id).await {
translated(context, StockMessage::SecureJoinStarted)
.await
.replace1(&contact.get_name_n_addr())
.replace1(contact.get_display_name())
.replace2(contact.get_display_name())
} else {
format!("secure_join_started: unknown contact {inviter_contact_id}")
@@ -871,7 +863,7 @@ pub(crate) async fn secure_join_group_qr_description(context: &Context, chat: &C
/// Stock string: `%1$s verified.`.
#[allow(dead_code)]
pub(crate) async fn contact_verified(context: &Context, contact: &Contact) -> String {
let addr = &contact.get_name_n_addr();
let addr = contact.get_display_name();
translated(context, StockMessage::ContactVerified)
.await
.replace1(addr)
@@ -879,7 +871,7 @@ pub(crate) async fn contact_verified(context: &Context, contact: &Contact) -> St
/// Stock string: `Cannot establish guaranteed end-to-end encryption with %1$s`.
pub(crate) async fn contact_not_verified(context: &Context, contact: &Contact) -> String {
let addr = &contact.get_name_n_addr();
let addr = contact.get_display_name();
translated(context, StockMessage::ContactNotVerified)
.await
.replace1(addr)
@@ -936,7 +928,7 @@ pub(crate) async fn msg_location_enabled_by(context: &Context, contact: ContactI
} else {
translated(context, StockMessage::MsgLocationEnabledBy)
.await
.replace1(&contact.get_stock_name_n_addr(context).await)
.replace1(&contact.get_stock_name(context).await)
}
}
@@ -998,7 +990,7 @@ pub(crate) async fn msg_ephemeral_timer_disabled(
} else {
translated(context, StockMessage::MsgEphemeralTimerDisabledBy)
.await
.replace1(&by_contact.get_stock_name_n_addr(context).await)
.replace1(&by_contact.get_stock_name(context).await)
}
}
@@ -1016,7 +1008,7 @@ pub(crate) async fn msg_ephemeral_timer_enabled(
translated(context, StockMessage::MsgEphemeralTimerEnabledBy)
.await
.replace1(timer)
.replace2(&by_contact.get_stock_name_n_addr(context).await)
.replace2(&by_contact.get_stock_name(context).await)
}
}
@@ -1027,7 +1019,7 @@ pub(crate) async fn msg_ephemeral_timer_minute(context: &Context, by_contact: Co
} else {
translated(context, StockMessage::MsgEphemeralTimerMinuteBy)
.await
.replace1(&by_contact.get_stock_name_n_addr(context).await)
.replace1(&by_contact.get_stock_name(context).await)
}
}
@@ -1038,7 +1030,7 @@ pub(crate) async fn msg_ephemeral_timer_hour(context: &Context, by_contact: Cont
} else {
translated(context, StockMessage::MsgEphemeralTimerHourBy)
.await
.replace1(&by_contact.get_stock_name_n_addr(context).await)
.replace1(&by_contact.get_stock_name(context).await)
}
}
@@ -1049,7 +1041,7 @@ pub(crate) async fn msg_ephemeral_timer_day(context: &Context, by_contact: Conta
} else {
translated(context, StockMessage::MsgEphemeralTimerDayBy)
.await
.replace1(&by_contact.get_stock_name_n_addr(context).await)
.replace1(&by_contact.get_stock_name(context).await)
}
}
@@ -1060,7 +1052,7 @@ pub(crate) async fn msg_ephemeral_timer_week(context: &Context, by_contact: Cont
} else {
translated(context, StockMessage::MsgEphemeralTimerWeekBy)
.await
.replace1(&by_contact.get_stock_name_n_addr(context).await)
.replace1(&by_contact.get_stock_name(context).await)
}
}
@@ -1142,7 +1134,7 @@ pub(crate) async fn msg_ephemeral_timer_minutes(
translated(context, StockMessage::MsgEphemeralTimerMinutesBy)
.await
.replace1(minutes)
.replace2(&by_contact.get_stock_name_n_addr(context).await)
.replace2(&by_contact.get_stock_name(context).await)
}
}
@@ -1160,7 +1152,7 @@ pub(crate) async fn msg_ephemeral_timer_hours(
translated(context, StockMessage::MsgEphemeralTimerHoursBy)
.await
.replace1(hours)
.replace2(&by_contact.get_stock_name_n_addr(context).await)
.replace2(&by_contact.get_stock_name(context).await)
}
}
@@ -1178,7 +1170,7 @@ pub(crate) async fn msg_ephemeral_timer_days(
translated(context, StockMessage::MsgEphemeralTimerDaysBy)
.await
.replace1(days)
.replace2(&by_contact.get_stock_name_n_addr(context).await)
.replace2(&by_contact.get_stock_name(context).await)
}
}
@@ -1196,7 +1188,7 @@ pub(crate) async fn msg_ephemeral_timer_weeks(
translated(context, StockMessage::MsgEphemeralTimerWeeksBy)
.await
.replace1(weeks)
.replace2(&by_contact.get_stock_name_n_addr(context).await)
.replace2(&by_contact.get_stock_name(context).await)
}
}

View File

@@ -54,10 +54,7 @@ async fn test_stock_string_repl_str() {
.unwrap();
let contact = Contact::get_by_id(&t.ctx, contact_id).await.unwrap();
// uses %1$s substitution
assert_eq!(
contact_verified(&t, &contact).await,
"Someone (someone@example.org) verified."
);
assert_eq!(contact_verified(&t, &contact).await, "Someone verified.");
// We have no string using %1$d to test...
}
@@ -95,7 +92,7 @@ async fn test_stock_system_msg_add_member_by_me_with_displayname() {
);
assert_eq!(
msg_add_member_local(&t, "alice@example.org", ContactId::SELF).await,
"You added member Alice (alice@example.org)."
"You added member Alice."
);
}
@@ -112,7 +109,7 @@ async fn test_stock_system_msg_add_member_by_other_with_displayname() {
};
assert_eq!(
msg_add_member_local(&t, "alice@example.org", contact_id,).await,
"Member Alice (alice@example.org) added by Bob (bob@example.com)."
"Member Alice added by Bob."
);
}

View File

@@ -743,10 +743,7 @@ mod tests {
let fiona = &tcm.fiona().await;
tcm.exec_securejoin_qr(fiona, alice2, &qr).await;
let msg = fiona.get_last_msg().await;
assert_eq!(
msg.text,
"Member Me (fiona@example.net) added by alice@example.org."
);
assert_eq!(msg.text, "Member Me added by alice@example.org.");
Ok(())
}
}

View File

@@ -388,6 +388,7 @@ impl Context {
None,
Some(&instance),
Some(from_id),
None,
)
.await?;
}