Skip to content

Commit b71c681

Browse files
committed
feat: Mark reactions as IMAP-seen in marknoticed_chat() (#6210)
When a reaction notification is shown in the UIs, there's an option "Mark Read", but the UIs are unaware of reactions message ids, moreover there are no `msgs` rows for reactions in the core, so the UIs just call `marknoticed_chat()` in this case. We don't want to introduce reactions message ids to the UIs (at least currently), but let's make received reactions usual messages, just hidden, so that the existing `\Seen` flag synchronisation mechanism works for them, and mark all incoming hidden messages in the chat as seen in `marknoticed_chat()`. It's interesting that sent out reactions are already hidden messages, so this change mostly just unifies things.
1 parent 399716a commit b71c681

File tree

4 files changed

+80
-39
lines changed

4 files changed

+80
-39
lines changed

src/chat.rs

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3298,10 +3298,10 @@ pub async fn marknoticed_chat(context: &Context, chat_id: ChatId) -> Result<()>
32983298
.query_map(
32993299
"SELECT DISTINCT(m.chat_id) FROM msgs m
33003300
LEFT JOIN chats c ON m.chat_id=c.id
3301-
WHERE m.state=10 AND m.hidden=0 AND m.chat_id>9 AND c.blocked=0 AND c.archived=1",
3302-
(),
3301+
WHERE m.state=10 AND m.chat_id>9 AND c.blocked=0 AND c.archived=1",
3302+
(),
33033303
|row| row.get::<_, ChatId>(0),
3304-
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into)
3304+
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
33053305
)
33063306
.await?;
33073307
if chat_ids_in_archive.is_empty() {
@@ -3312,7 +3312,7 @@ pub async fn marknoticed_chat(context: &Context, chat_id: ChatId) -> Result<()>
33123312
.sql
33133313
.execute(
33143314
&format!(
3315-
"UPDATE msgs SET state=13 WHERE state=10 AND hidden=0 AND chat_id IN ({});",
3315+
"UPDATE msgs SET state=13 WHERE state=10 AND chat_id IN ({});",
33163316
sql::repeat_vars(chat_ids_in_archive.len())
33173317
),
33183318
rusqlite::params_from_iter(&chat_ids_in_archive),
@@ -3322,20 +3322,39 @@ pub async fn marknoticed_chat(context: &Context, chat_id: ChatId) -> Result<()>
33223322
context.emit_event(EventType::MsgsNoticed(chat_id_in_archive));
33233323
chatlist_events::emit_chatlist_item_changed(context, chat_id_in_archive);
33243324
}
3325-
} else if context
3326-
.sql
3327-
.execute(
3328-
"UPDATE msgs
3329-
SET state=?
3330-
WHERE state=?
3331-
AND hidden=0
3332-
AND chat_id=?;",
3333-
(MessageState::InNoticed, MessageState::InFresh, chat_id),
3334-
)
3335-
.await?
3336-
== 0
3337-
{
3338-
return Ok(());
3325+
} else {
3326+
let conn_fn = |conn: &mut rusqlite::Connection| {
3327+
let nr_msgs_noticed = conn.execute(
3328+
"UPDATE msgs
3329+
SET state=?
3330+
WHERE state=?
3331+
AND hidden=0
3332+
AND chat_id=?",
3333+
(MessageState::InNoticed, MessageState::InFresh, chat_id),
3334+
)?;
3335+
let mut stmt = conn.prepare(
3336+
"SELECT id FROM msgs
3337+
WHERE state>=? AND state<?
3338+
AND hidden=1
3339+
AND chat_id=?
3340+
ORDER BY id DESC LIMIT 100",
3341+
)?;
3342+
let hidden_msgs = stmt
3343+
.query_map(
3344+
(MessageState::InFresh, MessageState::InSeen, chat_id),
3345+
|row| {
3346+
let id: MsgId = row.get(0)?;
3347+
Ok(id)
3348+
},
3349+
)?
3350+
.collect::<std::result::Result<Vec<_>, _>>()?;
3351+
Ok((nr_msgs_noticed, hidden_msgs))
3352+
};
3353+
let (nr_msgs_noticed, hidden_msgs) = context.sql.call_write(conn_fn).await?;
3354+
if nr_msgs_noticed == 0 && hidden_msgs.is_empty() {
3355+
return Ok(());
3356+
}
3357+
message::markseen_msgs(context, hidden_msgs).await?;
33393358
}
33403359

33413360
context.emit_event(EventType::MsgsNoticed(chat_id));
@@ -3380,7 +3399,6 @@ pub(crate) async fn mark_old_messages_as_noticed(
33803399
"UPDATE msgs
33813400
SET state=?
33823401
WHERE state=?
3383-
AND hidden=0
33843402
AND chat_id=?
33853403
AND timestamp<=?;",
33863404
(

src/reaction.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ mod tests {
397397
use deltachat_contact_tools::ContactAddress;
398398

399399
use super::*;
400-
use crate::chat::{forward_msgs, get_chat_msgs, send_text_msg};
400+
use crate::chat::{forward_msgs, get_chat_msgs, marknoticed_chat, send_text_msg};
401401
use crate::chatlist::Chatlist;
402402
use crate::config::Config;
403403
use crate::contact::{Contact, Origin};
@@ -641,7 +641,8 @@ Here's my footer -- [email protected]"
641641
assert_eq!(get_chat_msgs(&bob, bob_msg.chat_id).await?.len(), 2);
642642

643643
let bob_reaction_msg = bob.pop_sent_msg().await;
644-
alice.recv_msg_trash(&bob_reaction_msg).await;
644+
let alice_reaction_msg = alice.recv_msg_hidden(&bob_reaction_msg).await;
645+
assert_eq!(alice_reaction_msg.state, MessageState::InFresh);
645646
assert_eq!(get_chat_msgs(&alice, chat_alice.id).await?.len(), 2);
646647

647648
let reactions = get_msg_reactions(&alice, alice_msg.sender_msg_id).await?;
@@ -657,6 +658,20 @@ Here's my footer -- [email protected]"
657658
.await?;
658659
expect_incoming_reactions_event(&alice, alice_msg.sender_msg_id, *bob_id, "👍").await?;
659660

661+
marknoticed_chat(&alice, chat_alice.id).await?;
662+
assert_eq!(
663+
alice_reaction_msg.id.get_state(&alice).await?,
664+
MessageState::InSeen
665+
);
666+
// Reactions don't request MDNs.
667+
assert_eq!(
668+
alice
669+
.sql
670+
.count("SELECT COUNT(*) FROM smtp_mdns", ())
671+
.await?,
672+
0
673+
);
674+
660675
// Alice reacts to own message.
661676
send_reaction(&alice, alice_msg.sender_msg_id, "👍 😀")
662677
.await
@@ -695,7 +710,7 @@ Here's my footer -- [email protected]"
695710
bob_msg1.chat_id.accept(&bob).await?;
696711
send_reaction(&bob, bob_msg1.id, "👍").await?;
697712
let bob_send_reaction = bob.pop_sent_msg().await;
698-
alice.recv_msg_trash(&bob_send_reaction).await;
713+
alice.recv_msg_hidden(&bob_send_reaction).await;
699714
assert!(has_incoming_reactions_event(&alice).await);
700715

701716
let chatlist = Chatlist::try_load(&bob, 0, None, None).await?;
@@ -855,7 +870,7 @@ Here's my footer -- [email protected]"
855870
let bob_reaction_msg = bob.pop_sent_msg().await;
856871

857872
// Alice receives a reaction.
858-
alice.recv_msg_trash(&bob_reaction_msg).await;
873+
alice.recv_msg_hidden(&bob_reaction_msg).await;
859874

860875
let reactions = get_msg_reactions(&alice, alice_msg_id).await?;
861876
assert_eq!(reactions.to_string(), "👍1");
@@ -907,7 +922,7 @@ Here's my footer -- [email protected]"
907922
{
908923
send_reaction(&alice2, alice2_msg.id, "👍").await?;
909924
let msg = alice2.pop_sent_msg().await;
910-
alice1.recv_msg_trash(&msg).await;
925+
alice1.recv_msg_hidden(&msg).await;
911926
}
912927

913928
// Check that the status is still the same.
@@ -929,7 +944,7 @@ Here's my footer -- [email protected]"
929944
let alice1_msg = alice1.recv_msg(&alice0.pop_sent_msg().await).await;
930945

931946
send_reaction(&alice0, alice0_msg_id, "👀").await?;
932-
alice1.recv_msg_trash(&alice0.pop_sent_msg().await).await;
947+
alice1.recv_msg_hidden(&alice0.pop_sent_msg().await).await;
933948

934949
expect_reactions_changed_event(&alice0, chat_id, alice0_msg_id, ContactId::SELF).await?;
935950
expect_reactions_changed_event(&alice1, alice1_msg.chat_id, alice1_msg.id, ContactId::SELF)

src/receive_imf.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ async fn add_parts(
758758
// (of course, the user can add other chats manually later)
759759
let to_id: ContactId;
760760
let state: MessageState;
761-
let mut hidden = false;
761+
let mut hidden = is_reaction;
762762
let mut needs_delete_job = false;
763763
let mut restore_protection = false;
764764

@@ -1016,12 +1016,7 @@ async fn add_parts(
10161016
}
10171017
}
10181018

1019-
state = if seen
1020-
|| fetching_existing_messages
1021-
|| is_mdn
1022-
|| is_reaction
1023-
|| chat_id_blocked == Blocked::Yes
1024-
{
1019+
state = if seen || fetching_existing_messages || is_mdn || chat_id_blocked == Blocked::Yes {
10251020
MessageState::InSeen
10261021
} else {
10271022
MessageState::InFresh
@@ -1230,7 +1225,7 @@ async fn add_parts(
12301225
}
12311226

12321227
let orig_chat_id = chat_id;
1233-
let mut chat_id = if is_mdn || is_reaction {
1228+
let mut chat_id = if is_mdn {
12341229
DC_CHAT_ID_TRASH
12351230
} else {
12361231
chat_id.unwrap_or_else(|| {
@@ -1405,7 +1400,7 @@ async fn add_parts(
14051400
// that the ui should show button to display the full message.
14061401

14071402
// a flag used to avoid adding "show full message" button to multiple parts of the message.
1408-
let mut save_mime_modified = mime_parser.is_mime_modified;
1403+
let mut save_mime_modified = mime_parser.is_mime_modified && !hidden;
14091404

14101405
let mime_headers = if save_mime_headers || save_mime_modified {
14111406
let headers = if !mime_parser.decoded_data.is_empty() {
@@ -1597,10 +1592,10 @@ RETURNING id
15971592
state,
15981593
is_dc_message,
15991594
if trash { "" } else { msg },
1600-
if trash { None } else { message::normalize_text(msg) },
1601-
if trash { "" } else { &subject },
1595+
if trash || hidden { None } else { message::normalize_text(msg) },
1596+
if trash || hidden { "" } else { &subject },
16021597
// txt_raw might contain invalid utf8
1603-
if trash { "" } else { &txt_raw },
1598+
if trash || hidden { "" } else { &txt_raw },
16041599
if trash {
16051600
"".to_string()
16061601
} else {
@@ -1616,7 +1611,7 @@ RETURNING id
16161611
mime_in_reply_to,
16171612
mime_references,
16181613
mime_modified,
1619-
part.error.as_deref().unwrap_or_default(),
1614+
if trash || hidden { "" } else { part.error.as_deref().unwrap_or_default() },
16201615
ephemeral_timer,
16211616
ephemeral_timestamp,
16221617
if is_partial_download.is_some() {
@@ -1626,7 +1621,7 @@ RETURNING id
16261621
} else {
16271622
DownloadState::Done
16281623
},
1629-
mime_parser.hop_info
1624+
if trash || hidden { "" } else { &mime_parser.hop_info },
16301625
],
16311626
|row| {
16321627
let msg_id: MsgId = row.get(0)?;

src/test_utils.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,19 @@ impl TestContext {
607607
msg
608608
}
609609

610+
/// Receive a message using the `receive_imf()` pipeline. Panics if it's not hidden.
611+
pub async fn recv_msg_hidden(&self, msg: &SentMessage<'_>) -> Message {
612+
let received = self
613+
.recv_msg_opt(msg)
614+
.await
615+
.expect("receive_imf() seems not to have added a new message to the db");
616+
let msg = Message::load_from_db(self, *received.msg_ids.last().unwrap())
617+
.await
618+
.unwrap();
619+
assert!(msg.hidden);
620+
msg
621+
}
622+
610623
/// Receive a message using the `receive_imf()` pipeline. This is similar
611624
/// to `recv_msg()`, but doesn't assume that the message is shown in the chat.
612625
pub async fn recv_msg_opt(

0 commit comments

Comments
 (0)