diff --git a/src/chat.rs b/src/chat.rs index e07b7761f..0c5fa9792 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -3534,37 +3534,62 @@ pub async fn get_chat_media( msg_type2: Viewtype, msg_type3: Viewtype, ) -> Result> { - // TODO This query could/should be converted to `AND type IN (?, ?, ?)`. - let list = context - .sql - .query_map( - "SELECT id + let list = if msg_type == Viewtype::Webxdc + && msg_type2 == Viewtype::Unknown + && msg_type3 == Viewtype::Unknown + { + context + .sql + .query_map( + "SELECT id FROM msgs WHERE (1=? OR chat_id=?) AND chat_id != ? - AND (type=? OR type=? OR type=?) + AND type = ? + AND hidden=0 + ORDER BY max(timestamp, timestamp_rcvd), id;", + ( + chat_id.is_none(), + chat_id.unwrap_or_else(|| ChatId::new(0)), + DC_CHAT_ID_TRASH, + Viewtype::Webxdc, + ), + |row| row.get::<_, MsgId>(0), + |ids| Ok(ids.flatten().collect()), + ) + .await? + } else { + context + .sql + .query_map( + "SELECT id + FROM msgs + WHERE (1=? OR chat_id=?) + AND chat_id != ? + AND type IN (?, ?, ?) AND hidden=0 ORDER BY timestamp, id;", - ( - chat_id.is_none(), - chat_id.unwrap_or_else(|| ChatId::new(0)), - DC_CHAT_ID_TRASH, - msg_type, - if msg_type2 != Viewtype::Unknown { - msg_type2 - } else { - msg_type - }, - if msg_type3 != Viewtype::Unknown { - msg_type3 - } else { - msg_type - }, - ), - |row| row.get::<_, MsgId>(0), - |ids| Ok(ids.flatten().collect()), - ) - .await?; + ( + chat_id.is_none(), + chat_id.unwrap_or_else(|| ChatId::new(0)), + DC_CHAT_ID_TRASH, + msg_type, + if msg_type2 != Viewtype::Unknown { + msg_type2 + } else { + msg_type + }, + if msg_type3 != Viewtype::Unknown { + msg_type3 + } else { + msg_type + }, + ), + |row| row.get::<_, MsgId>(0), + |ids| Ok(ids.flatten().collect()), + ) + .await? + }; Ok(list) } diff --git a/src/chat/chat_tests.rs b/src/chat/chat_tests.rs index ba13e3e4b..2f75d7c00 100644 --- a/src/chat/chat_tests.rs +++ b/src/chat/chat_tests.rs @@ -2924,6 +2924,61 @@ async fn test_get_chat_media() -> Result<()> { Ok(()) } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_get_chat_media_webxdc_order() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + let bob = tcm.bob().await; + let chat = alice.create_chat(&bob).await; + + let mut instance1 = Message::new(Viewtype::Webxdc); + instance1.set_file_from_bytes( + &alice, + "test1.xdc", + include_bytes!("../../test-data/webxdc/minimal.xdc"), + None, + )?; + let instance1_id = send_msg(&alice, chat.id, &mut instance1).await?; + + let mut instance2 = Message::new(Viewtype::Webxdc); + instance2.set_file_from_bytes( + &alice, + "test2.xdc", + include_bytes!("../../test-data/webxdc/minimal.xdc"), + None, + )?; + let instance2_id = send_msg(&alice, chat.id, &mut instance2).await?; + + // list is ordered oldest to newest, check that + let media = get_chat_media( + &alice, + Some(chat.id), + Viewtype::Webxdc, + Viewtype::Unknown, + Viewtype::Unknown, + ) + .await?; + assert_eq!(media.first().unwrap(), &instance1_id); + assert_eq!(media.get(1).unwrap(), &instance2_id); + + // add a status update for the oder instance; that resorts the list + alice + .send_webxdc_status_update(instance1_id, r#"{"payload": {"foo": "bar"}}"#) + .await?; + let media = get_chat_media( + &alice, + Some(chat.id), + Viewtype::Webxdc, + Viewtype::Unknown, + Viewtype::Unknown, + ) + .await?; + assert_eq!(media.first().unwrap(), &instance2_id); + assert_eq!(media.get(1).unwrap(), &instance1_id); + + Ok(()) +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_blob_renaming() -> Result<()> { let alice = TestContext::new_alice().await;