From af287ee9a84f2563e5df8e7c559f1b4a5f40fb7d Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 29 May 2021 02:46:46 +0300 Subject: [PATCH] Do not allow to delete contacts with ongoing chats Even if chat has no messages, contacts should not be deleted. Otherwise chat will reference invalid contact ID which can't be loaded from the database, resulting in broken contact list in group chats. --- src/contact.rs | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/contact.rs b/src/contact.rs index 297ea28e7..b058f26f3 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -860,7 +860,7 @@ impl Contact { "Can not delete special contact" ); - let count_contacts = context + let count_chats = context .sql .count( "SELECT COUNT(*) FROM chats_contacts WHERE contact_id=?;", @@ -868,19 +868,7 @@ impl Contact { ) .await?; - let count_msgs = if count_contacts > 0 { - context - .sql - .count( - "SELECT COUNT(*) FROM msgs WHERE from_id=? OR to_id=?;", - paramsv![contact_id as i32, contact_id as i32], - ) - .await? - } else { - 0 - }; - - if count_msgs == 0 { + if count_chats == 0 { match context .sql .execute( @@ -902,9 +890,9 @@ impl Contact { info!( context, - "could not delete contact {}, there are {} messages with it", contact_id, count_msgs + "could not delete contact {}, there are {} chats with it", contact_id, count_chats ); - bail!("Could not delete contact with messages in it"); + bail!("Could not delete contact with ongoing chats"); } /// Get a single contact object. For a list, see eg. dc_get_contacts(). @@ -1618,6 +1606,34 @@ mod tests { assert!(!contact.is_blocked()); } + #[async_std::test] + async fn test_delete() -> Result<()> { + let alice = TestContext::new_alice().await; + + assert!(Contact::delete(&alice, DC_CONTACT_ID_SELF).await.is_err()); + + // Create Bob contact + let (contact_id, _) = + Contact::add_or_lookup(&alice, "Bob", "bob@example.net", Origin::ManuallyCreated) + .await + .unwrap(); + + let chat = alice + .create_chat_with_contact("Bob", "bob@example.net") + .await; + + // Can't delete a contact with ongoing chats. + assert!(Contact::delete(&alice, contact_id).await.is_err()); + + // Delete chat. + chat.get_id().delete(&alice).await?; + + // Can delete contact now. + Contact::delete(&alice, contact_id).await?; + + Ok(()) + } + #[async_std::test] async fn test_remote_authnames() { let t = TestContext::new().await;