feat: Don't show "member added" messages in channels

This commit is contained in:
Hocuri
2026-09-21 21:02:01 +02:00
parent b766a9a8fa
commit 96970fb08e
6 changed files with 27 additions and 72 deletions

View File

@@ -3918,15 +3918,7 @@ pub(crate) async fn add_contact_to_chat_ext(
msg.viewtype = Viewtype::Text; msg.viewtype = Viewtype::Text;
let contact_addr = contact.get_addr().to_lowercase(); let contact_addr = contact.get_addr().to_lowercase();
let added_by = if from_handshake && chat.typ == Chattype::OutBroadcast { let added_by = ContactId::SELF;
// The contact was added via a QR code rather than explicit user action,
// so it could be confusing to say 'You added member Alice'.
// And in a broadcast, SELF is the only one who can add members,
// so, no information is lost by just writing 'Member Alice added' instead.
ContactId::UNDEFINED
} else {
ContactId::SELF
};
msg.text = stock_str::msg_add_member_local(context, contact.id, added_by).await; msg.text = stock_str::msg_add_member_local(context, contact.id, added_by).await;
msg.param.set_cmd(SystemMessage::MemberAddedToGroup); msg.param.set_cmd(SystemMessage::MemberAddedToGroup);
msg.param.set(Param::Arg, contact_addr); msg.param.set(Param::Arg, contact_addr);
@@ -3940,6 +3932,11 @@ pub(crate) async fn add_contact_to_chat_ext(
.await? .await?
.context("Failed to find broadcast shared secret")?; .context("Failed to find broadcast shared secret")?;
msg.param.set(PARAM_BROADCAST_SECRET, secret); msg.param.set(PARAM_BROADCAST_SECRET, secret);
// We don't show "member added" info-messages in channels,
// because there can be a lot members added,
// and these messages would clutter the timeline.
msg.hidden = true;
} }
send_msg(context, chat_id, &mut msg).await?; send_msg(context, chat_id, &mut msg).await?;
@@ -5107,7 +5104,7 @@ async fn set_contacts_by_fingerprints(
if contacts == contacts_old { if contacts == contacts_old {
return Ok(()); return Ok(());
} }
let broadcast_contacts_added = context context
.sql .sql
.transaction(move |transaction| { .transaction(move |transaction| {
// For broadcast channels, we only add members, // For broadcast channels, we only add members,
@@ -5124,31 +5121,12 @@ async fn set_contacts_by_fingerprints(
let mut statement = transaction.prepare( let mut statement = transaction.prepare(
"INSERT OR IGNORE INTO chats_contacts (chat_id, contact_id) VALUES (?, ?)", "INSERT OR IGNORE INTO chats_contacts (chat_id, contact_id) VALUES (?, ?)",
)?; )?;
let mut broadcast_contacts_added = Vec::new();
for contact_id in &contacts { for contact_id in &contacts {
if statement.execute((id, contact_id))? > 0 && chat.typ == Chattype::OutBroadcast { statement.execute((id, contact_id))?;
broadcast_contacts_added.push(*contact_id);
}
} }
Ok(broadcast_contacts_added) Ok(())
}) })
.await?; .await?;
let timestamp = time();
for added_id in broadcast_contacts_added {
let msg = stock_str::msg_add_member_local(context, added_id, ContactId::UNDEFINED).await;
add_info_msg_with_cmd(
context,
id,
&msg,
SystemMessage::MemberAddedToGroup,
Some(timestamp),
timestamp,
None,
Some(ContactId::SELF),
Some(added_id),
)
.await?;
}
context.emit_event(EventType::ChatModified(id)); context.emit_event(EventType::ChatModified(id));
Ok(()) Ok(())
} }

View File

@@ -3003,13 +3003,13 @@ async fn test_broadcast_change_name() -> Result<()> {
tcm.section("Bob receives the name-change system message"); tcm.section("Bob receives the name-change system message");
let msg = bob.recv_msg(&sent).await; let msg = bob.recv_msg(&sent).await;
assert_eq!(msg.subject, "Re: My great broadcast"); assert_eq!(msg.subject, "My great broadcast");
let bob_chat = Chat::load_from_db(bob, msg.chat_id).await?; let bob_chat = Chat::load_from_db(bob, msg.chat_id).await?;
assert_eq!(bob_chat.name, "My great broadcast"); assert_eq!(bob_chat.name, "My great broadcast");
tcm.section("Fiona receives the name-change system message"); tcm.section("Fiona receives the name-change system message");
let msg = fiona.recv_msg(&sent).await; let msg = fiona.recv_msg(&sent).await;
assert_eq!(msg.subject, "Re: My great broadcast"); assert_eq!(msg.subject, "My great broadcast");
let fiona_chat = Chat::load_from_db(fiona, msg.chat_id).await?; let fiona_chat = Chat::load_from_db(fiona, msg.chat_id).await?;
assert_eq!(fiona_chat.name, "My great broadcast"); assert_eq!(fiona_chat.name, "My great broadcast");
} }
@@ -3343,41 +3343,27 @@ async fn test_broadcast_recipients_sync1() -> Result<()> {
alice2.assert_warn("unknown grpid").await; alice2.assert_warn("unknown grpid").await;
let member_added = alice1.pop_sent_msg().await; let member_added = alice1.pop_sent_msg().await;
let a2_charlie_added = alice2.recv_msg(&member_added).await; alice2.recv_msg_trash(&member_added).await;
let _c_member_added = charlie.recv_msg(&member_added).await; let _c_member_added = charlie.recv_msg(&member_added).await;
let a2_chatlist = Chatlist::try_load(alice2, 0, Some("Channel"), None).await?;
assert_eq!(a2_chatlist.get_msg_id(0)?.unwrap(), a2_charlie_added.id);
// Alice1 will now sync the full member list to Alice2: // Alice1 will now sync the full member list to Alice2:
sync(alice1, alice2).await; sync(alice1, alice2).await;
let a2_bob_contact = alice2.add_or_lookup_contact_id(bob).await; let a2_bob_contact = alice2.add_or_lookup_contact_id(bob).await;
let a2_charlie_contact = alice2.add_or_lookup_contact_id(charlie).await; let a2_charlie_contact = alice2.add_or_lookup_contact_id(charlie).await;
let a2_chatlist = Chatlist::try_load(alice2, 0, Some("Channel"), None).await?; let a2_chatlist = Chatlist::try_load(alice2, 0, Some("Channel"), None).await?;
let msg_id = a2_chatlist.get_msg_id(0)?.unwrap(); let a2_chat_id = a2_chatlist.get_chat_id(0).unwrap();
let a2_bob_added = Message::load_from_db(alice2, msg_id).await?;
assert_ne!(a2_bob_added.id, a2_charlie_added.id);
assert_eq!(
a2_bob_added.text,
stock_str::msg_add_member_local(alice2, a2_bob_contact, ContactId::UNDEFINED).await
);
assert_eq!(a2_bob_added.from_id, ContactId::SELF);
assert_eq!(
a2_bob_added.param.get_cmd(),
SystemMessage::MemberAddedToGroup
);
assert_eq!(
ContactId::new(
a2_bob_added
.param
.get_int(Param::ContactAddedRemoved)
.unwrap()
.try_into()
.unwrap()
),
a2_bob_contact
);
let a2_chat_members = get_chat_contacts(alice2, a2_charlie_added.chat_id).await?; // Also for Alice2, no info message should be shown;
// she should see only the "Messages are end-to-end encrypted" message.
let a2_chat_msgs = get_chat_msgs(alice2, a2_chat_id).await?;
assert_eq!(a2_chat_msgs.len(), 1);
let ChatItem::Message { msg_id } = a2_chat_msgs[0] else {
unreachable!()
};
let a2_msg = Message::load_from_db(alice2, msg_id).await?;
assert_eq!(a2_msg.get_info_type(), SystemMessage::ChatE2ee);
let a2_chat_members = get_chat_contacts(alice2, a2_chat_id).await?;
assert!(a2_chat_members.contains(&a2_bob_contact)); assert!(a2_chat_members.contains(&a2_bob_contact));
assert!(a2_chat_members.contains(&a2_charlie_contact)); assert!(a2_chat_members.contains(&a2_charlie_contact));
assert_eq!(a2_chat_members.len(), 2); assert_eq!(a2_chat_members.len(), 2);

View File

@@ -3732,10 +3732,9 @@ async fn apply_out_broadcast_changes(
if from_id == ContactId::SELF { if from_id == ContactId::SELF {
let added_id = lookup_key_contact_by_fingerprint(context, added_fpr).await?; let added_id = lookup_key_contact_by_fingerprint(context, added_fpr).await?;
if let Some(added_id) = added_id { if let Some(added_id) = added_id {
if chat::is_contact_in_chat(context, chat.id, added_id).await? { info!(context, "Broadcast addition (TRASH)");
info!(context, "No-op broadcast addition (TRASH)"); better_msg.get_or_insert("".to_string());
better_msg.get_or_insert("".to_string()); if !chat::is_contact_in_chat(context, chat.id, added_id).await? {
} else {
chat::add_to_chat_contacts_table( chat::add_to_chat_contacts_table(
context, context,
mime_parser.timestamp_sent, mime_parser.timestamp_sent,
@@ -3743,11 +3742,6 @@ async fn apply_out_broadcast_changes(
&[added_id], &[added_id],
) )
.await?; .await?;
let msg =
stock_str::msg_add_member_local(context, added_id, ContactId::UNDEFINED)
.await;
better_msg.get_or_insert(msg);
added_removed_id = Some(added_id);
send_event_chat_modified = true; send_event_chat_modified = true;
} }
} else { } else {

View File

@@ -2,5 +2,4 @@ OutBroadcast#Chat#1001: My Channel [1 member(s)]🔇 Icon: e9b6c7a78aa2e4f415644
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Msg#1001: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] Msg#1001: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
Msg#1002🔒: Me (Contact#Contact#Self): Channel image changed. [INFO] √ Msg#1002🔒: Me (Contact#Contact#Self): Channel image changed. [INFO] √
Msg#1005🔒: Me (Contact#Contact#Self): Member bob@example.net added. [INFO] √
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -1,7 +1,6 @@
OutBroadcast#Chat#1001: Channel [0 member(s)]🔇 OutBroadcast#Chat#1001: Channel [0 member(s)]🔇
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Msg#1001: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] Msg#1001: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
Msg#1006🔒: Me (Contact#Contact#Self): Member bob@example.net added. [INFO] √
Msg#1009🔒: Me (Contact#Contact#Self): hi √ Msg#1009🔒: Me (Contact#Contact#Self): hi √
Msg#1010🔒: Me (Contact#Contact#Self): You removed member bob@example.net. [INFO] √ Msg#1010🔒: Me (Contact#Contact#Self): You removed member bob@example.net. [INFO] √
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@@ -1,7 +1,6 @@
OutBroadcast#Chat#1001: Channel [0 member(s)]🔇 OutBroadcast#Chat#1001: Channel [0 member(s)]🔇
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Msg#1002: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO] Msg#1002: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
Msg#1006🔒: Me (Contact#Contact#Self): Member bob@example.net added. [INFO] √
Msg#1009🔒: Me (Contact#Contact#Self): hi √ Msg#1009🔒: Me (Contact#Contact#Self): hi √
Msg#1010🔒: Me (Contact#Contact#Self): You removed member bob@example.net. [INFO] √ Msg#1010🔒: Me (Contact#Contact#Self): You removed member bob@example.net. [INFO] √
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------