From b455344a14010b1af0f2b80e7f150ced1153feee Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 22 Feb 2025 22:12:03 +0100 Subject: [PATCH] add can_send_edit_request() api --- deltachat-ffi/deltachat.h | 14 ++++++++++ deltachat-ffi/src/lib.rs | 17 ++++++++++++ src/chat.rs | 17 +++--------- src/message.rs | 16 +++++++++++ src/message/message_tests.rs | 52 ++++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 13 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index ca33f0444..92a599e69 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -1039,6 +1039,20 @@ uint32_t dc_send_msg_sync (dc_context_t* context, uint32 uint32_t dc_send_text_msg (dc_context_t* context, uint32_t chat_id, const char* text_to_send); +/** + * Check if a message can be edited using dc_send_edit_request(). + * + * Messages that cannot be edited are eg. info messages or messages not sent by self. + * UI will usually check this function whether to display an "Edit" option or not. + * + * @memberof dc_context_t + * @param context The context object. + * @param msg_id The message ID to check. + * @return 1=message can be edited, 0=message cannot be edited. + */ + int dc_can_send_edit_request (dc_context_t* context, uint32_t msg_id); + + /** * Send chat members a request to edit the given message's text. * diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 3d25e0c2b..4c2004d29 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -1041,6 +1041,23 @@ pub unsafe extern "C" fn dc_send_text_msg( }) } +#[no_mangle] +pub unsafe extern "C" fn dc_can_send_edit_request( + context: *mut dc_context_t, + msg_id: u32, + new_text: *const libc::c_char, +) -> libc::c_int { + if context.is_null() || new_text.is_null() { + eprintln!("ignoring careless call to dc_can_send_edit_request()"); + return 0; + } + let ctx = &*context; + + block_on(message::can_send_edit_request(ctx, MsgId::new(msg_id))) + .log_err(ctx) + .unwrap_or_default() as libc::c_int +} + #[no_mangle] pub unsafe extern "C" fn dc_send_edit_request( context: *mut dc_context_t, diff --git a/src/chat.rs b/src/chat.rs index 04896a0d3..939c57840 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -3133,22 +3133,13 @@ pub async fn send_text_msg( /// Sends chat members a request to edit the given message's text. pub async fn send_edit_request(context: &Context, msg_id: MsgId, new_text: String) -> Result<()> { - let mut original_msg = Message::load_from_db(context, msg_id).await?; ensure!( - original_msg.from_id == ContactId::SELF, - "Can edit only own messages" - ); - ensure!(!original_msg.is_info(), "Cannot edit info messages"); - ensure!(!original_msg.has_html(), "Cannot edit HTML messages"); - ensure!( - original_msg.viewtype != Viewtype::VideochatInvitation, - "Cannot edit videochat invitations" - ); - ensure!( - !original_msg.text.is_empty(), // avoid complexity in UI element changes. focus is typos and rewordings - "Cannot add text" + message::can_send_edit_request(context, msg_id).await?, + "Message cannot be edited" ); ensure!(!new_text.trim().is_empty(), "Edited text cannot be empty"); + + let mut original_msg = Message::load_from_db(context, msg_id).await?; if original_msg.text == new_text { info!(context, "Text unchanged."); return Ok(()); diff --git a/src/message.rs b/src/message.rs index 0841c7420..fb51850a5 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1500,6 +1500,22 @@ pub async fn get_msg_read_receipts( .await } +/// Returns true if the message can be edited. +pub async fn can_send_edit_request(context: &Context, msg_id: MsgId) -> Result { + let msg = Message::load_from_db(context, msg_id).await?; + if msg.from_id != ContactId::SELF + || msg.is_info() + || msg.viewtype == Viewtype::VideochatInvitation + || msg.has_html() + || msg.text.is_empty() + { + return Ok(false); + } + let chat = Chat::load_from_db(context, msg.get_chat_id()).await?; + let can_send = chat.can_send(context).await?; + Ok(can_send) +} + pub(crate) fn guess_msgtype_from_suffix(msg: &Message) -> Option<(Viewtype, &'static str)> { msg.param .get(Param::Filename) diff --git a/src/message/message_tests.rs b/src/message/message_tests.rs index 27a2f6953..93424001e 100644 --- a/src/message/message_tests.rs +++ b/src/message/message_tests.rs @@ -783,3 +783,55 @@ async fn test_sanitize_filename_message() -> Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn text_can_send_edit_request() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + let chat_id = alice + .create_group_with_members(ProtectionStatus::Unprotected, "My Group", &[&bob]) + .await; + + // Alice can edit her message + let sent1 = alice.send_text(chat_id, "foo").await; + assert!(can_send_edit_request(&alice, sent1.sender_msg_id).await?); + + // Bob cannot edit Alice's message + let msg = bob.recv_msg(&sent1).await; + assert!(!can_send_edit_request(&bob, msg.id).await?); + + // HTML messages cannot be edited + let mut msg = Message::new_text("plain text".to_string()); + msg.set_html(Some("html text".to_string())); + let sent2 = alice.send_msg(chat_id, &mut msg).await; + assert!(!can_send_edit_request(&alice, sent2.sender_msg_id).await?); + + // Info messages cannot be edited + chat::set_chat_name(&alice, chat_id, "bar").await?; + let msg = alice.get_last_msg().await; + assert!(msg.is_info()); + assert_eq!(msg.from_id, ContactId::SELF); + assert!(!can_send_edit_request(&alice, msg.id).await?); + + // Videochat invitations cannot be edited + alice + .set_config(Config::WebrtcInstance, Some("https://foo.bar")) + .await?; + let msg_id = chat::send_videochat_invitation(&alice, chat_id).await?; + assert!(!can_send_edit_request(&alice, msg_id).await?); + + // If not text was given initally, there is nothing to edit + // (this also avoids complexity in UI element changes; focus is typos and rewordings) + let mut msg = Message::new(Viewtype::File); + msg.make_vcard(&alice, &[ContactId::SELF]).await?; + let sent3 = alice.send_msg(chat_id, &mut msg).await; + assert!(msg.text.is_empty()); + assert!(!can_send_edit_request(&alice, sent3.sender_msg_id).await?); + + // Messages in left groups cannot be edited any longer (as one cannot send to that group) + chat::remove_contact_from_chat(&alice, chat_id, ContactId::SELF).await?; + assert!(!can_send_edit_request(&alice, sent1.sender_msg_id).await?); + + Ok(()) +}