mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
feat: Assign message to ad-hoc group with matching name and members (#5385)
This should fix ad-hoc groups splitting when messages are fetched out of order from different folders or otherwise reordered, or some messages are missing so that the messages reference chain is broken, or a member was removed from the thread and readded later, etc. Even if this way two different threads are merged, it looks acceptable, having many threads with the same name/subject and members isn't a common use case.
This commit is contained in:
@@ -35,7 +35,7 @@ use crate::peerstate::Peerstate;
|
||||
use crate::reaction::{set_msg_reaction, Reaction};
|
||||
use crate::securejoin::{self, handle_securejoin_handshake, observe_securejoin_on_other_device};
|
||||
use crate::simplify;
|
||||
use crate::sql;
|
||||
use crate::sql::{self, params_iter};
|
||||
use crate::stock_str;
|
||||
use crate::sync::Sync::*;
|
||||
use crate::tools::{self, buf_compress, remove_subject_prefix};
|
||||
@@ -1829,9 +1829,6 @@ async fn lookup_chat_or_create_adhoc_group(
|
||||
{
|
||||
return Ok(Some((new_chat_id, new_chat_id_blocked)));
|
||||
}
|
||||
if !allow_creation {
|
||||
return Ok(None);
|
||||
}
|
||||
// Partial download may be an encrypted message with protected Subject header. We do not want to
|
||||
// create a group with "..." or "Encrypted message" as a subject. The same is for undecipherable
|
||||
// messages. Instead, assign the message to 1:1 chat with the sender.
|
||||
@@ -1854,6 +1851,48 @@ async fn lookup_chat_or_create_adhoc_group(
|
||||
.get_subject()
|
||||
.map(|s| remove_subject_prefix(&s))
|
||||
.unwrap_or_else(|| "👥📧".to_string());
|
||||
let mut contact_ids = Vec::with_capacity(to_ids.len() + 1);
|
||||
contact_ids.extend(to_ids);
|
||||
if !contact_ids.contains(&from_id) {
|
||||
contact_ids.push(from_id);
|
||||
}
|
||||
if let Some((chat_id, blocked)) = context
|
||||
.sql
|
||||
.query_row_optional(
|
||||
&format!(
|
||||
"SELECT c.id, c.blocked
|
||||
FROM chats c INNER JOIN msgs m ON c.id=m.chat_id
|
||||
WHERE m.hidden=0 AND c.grpid='' AND c.name=?
|
||||
AND (SELECT COUNT(*) FROM chats_contacts
|
||||
WHERE chat_id=c.id)=?
|
||||
AND (SELECT COUNT(*) FROM chats_contacts
|
||||
WHERE chat_id=c.id
|
||||
AND contact_id NOT IN ({}))=0
|
||||
ORDER BY m.timestamp DESC",
|
||||
sql::repeat_vars(contact_ids.len()),
|
||||
),
|
||||
rusqlite::params_from_iter(
|
||||
params_iter(&[&grpname])
|
||||
.chain(params_iter(&[contact_ids.len()]))
|
||||
.chain(params_iter(&contact_ids)),
|
||||
),
|
||||
|row| {
|
||||
let id: ChatId = row.get(0)?;
|
||||
let blocked: Blocked = row.get(1)?;
|
||||
Ok((id, blocked))
|
||||
},
|
||||
)
|
||||
.await?
|
||||
{
|
||||
info!(
|
||||
context,
|
||||
"Assigning message to ad-hoc group {chat_id} with matching name and members."
|
||||
);
|
||||
return Ok(Some((chat_id, blocked)));
|
||||
}
|
||||
if !allow_creation {
|
||||
return Ok(None);
|
||||
}
|
||||
create_adhoc_group(
|
||||
context,
|
||||
mime_parser,
|
||||
|
||||
@@ -204,6 +204,71 @@ async fn test_adhoc_group_show_all() {
|
||||
assert_eq!(chat::get_chat_contacts(&t, chat_id).await.unwrap().len(), 3);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_adhoc_groups_merge() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = &tcm.alice().await;
|
||||
receive_imf(
|
||||
alice,
|
||||
b"From: bob@example.net\n\
|
||||
To: alice@example.org, claire@example.com\n\
|
||||
Message-ID: <1111@example.net>\n\
|
||||
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
|
||||
Subject: New thread\n\
|
||||
\n\
|
||||
The first of us should create a thread as discussed\n",
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
receive_imf(
|
||||
alice,
|
||||
b"From: alice@example.org\n\
|
||||
To: bob@example.net, claire@example.com\n\
|
||||
Message-ID: <2222@example.org>\n\
|
||||
Date: Sun, 22 Mar 2020 22:37:58 +0000\n\
|
||||
Subject: New thread\n\
|
||||
\n\
|
||||
The first of us should create a thread as discussed\n",
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
let chats = Chatlist::try_load(alice, 0, None, None).await?;
|
||||
assert_eq!(chats.len(), 1);
|
||||
let chat_id = chats.get_chat_id(0)?;
|
||||
assert_eq!(chat_id.get_msg_cnt(alice).await?, 2);
|
||||
|
||||
// If member list doesn't match, threads aren't merged.
|
||||
receive_imf(
|
||||
alice,
|
||||
b"From: bob@example.net\n\
|
||||
To: alice@example.org, claire@example.com, fiona@example.net\n\
|
||||
Message-ID: <3333@example.net>\n\
|
||||
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
|
||||
Subject: New thread\n\
|
||||
\n\
|
||||
This is another thread, with Fiona\n",
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
let chats = Chatlist::try_load(alice, 0, None, None).await?;
|
||||
assert_eq!(chats.len(), 2);
|
||||
receive_imf(
|
||||
alice,
|
||||
b"From: bob@example.net\n\
|
||||
To: alice@example.org, fiona@example.net\n\
|
||||
Message-ID: <4444@example.net>\n\
|
||||
Date: Sun, 22 Mar 2020 22:37:57 +0000\n\
|
||||
Subject: New thread\n\
|
||||
\n\
|
||||
This is yet another thread, with Fiona and 0 Claires\n",
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
let chats = Chatlist::try_load(alice, 0, None, None).await?;
|
||||
assert_eq!(chats.len(), 3);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_read_receipt_and_unarchive() -> Result<()> {
|
||||
// create alice's account
|
||||
|
||||
@@ -1028,6 +1028,15 @@ CREATE INDEX msgs_status_updates_index2 ON msgs_status_updates (uid);
|
||||
.await?;
|
||||
}
|
||||
|
||||
inc_and_check(&mut migration_version, 121)?;
|
||||
if dbversion < migration_version {
|
||||
sql.execute_migration(
|
||||
"CREATE INDEX chats_index4 ON chats (name)",
|
||||
migration_version,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let new_version = sql
|
||||
.get_raw_config_int(VERSION_CFG)
|
||||
.await?
|
||||
|
||||
Reference in New Issue
Block a user