use anyhow::Result;
use crate::chat::ChatId;
use crate::contact::ContactId;
use crate::context::Context;
use crate::param::{Param, Params};
impl Context {
pub(crate) async fn update_contacts_timestamp(
&self,
contact_id: ContactId,
scope: Param,
new_timestamp: i64,
) -> Result<bool> {
self.sql
.transaction(|transaction| {
let mut param: Params = transaction.query_row(
"SELECT param FROM contacts WHERE id=?",
[contact_id],
|row| {
let param: String = row.get(0)?;
Ok(param.parse().unwrap_or_default())
},
)?;
let update = param.update_timestamp(scope, new_timestamp)?;
if update {
transaction.execute(
"UPDATE contacts SET param=? WHERE id=?",
(param.to_string(), contact_id),
)?;
}
Ok(update)
})
.await
}
}
impl ChatId {
pub(crate) async fn update_timestamp(
&self,
context: &Context,
scope: Param,
new_timestamp: i64,
) -> Result<bool> {
context
.sql
.transaction(|transaction| {
let mut param: Params =
transaction.query_row("SELECT param FROM chats WHERE id=?", [self], |row| {
let param: String = row.get(0)?;
Ok(param.parse().unwrap_or_default())
})?;
let update = param.update_timestamp(scope, new_timestamp)?;
if update {
transaction.execute(
"UPDATE chats SET param=? WHERE id=?",
(param.to_string(), self),
)?;
}
Ok(update)
})
.await
}
}
impl Params {
pub(crate) fn update_timestamp(&mut self, scope: Param, new_timestamp: i64) -> Result<bool> {
let old_timestamp = self.get_i64(scope).unwrap_or_default();
if new_timestamp >= old_timestamp {
self.set_i64(scope, new_timestamp);
return Ok(true);
}
Ok(false)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::chat::Chat;
use crate::receive_imf::receive_imf;
use crate::test_utils::TestContext;
use crate::tools::time;
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_params_update_timestamp() -> Result<()> {
let mut params = Params::new();
let ts = time();
assert!(params.update_timestamp(Param::LastSubject, ts)?);
assert!(params.update_timestamp(Param::LastSubject, ts)?); assert!(params.update_timestamp(Param::LastSubject, ts + 10)?);
assert!(!params.update_timestamp(Param::LastSubject, ts)?); assert!(!params.update_timestamp(Param::LastSubject, 0)?);
assert_eq!(params.get_i64(Param::LastSubject).unwrap(), ts + 10);
assert!(params.update_timestamp(Param::GroupNameTimestamp, 0)?); assert!(params.update_timestamp(Param::GroupNameTimestamp, 0)?); assert_eq!(params.get_i64(Param::GroupNameTimestamp).unwrap(), 0);
assert!(!params.update_timestamp(Param::AvatarTimestamp, -1)?);
assert_eq!(params.get_i64(Param::AvatarTimestamp), None);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_out_of_order_subject() -> Result<()> {
let t = TestContext::new_alice().await;
receive_imf(
&t,
b"From: Bob Authname <bob@example.org>\n\
To: alice@example.org\n\
Subject: updated subject\n\
Message-ID: <msg2@example.org>\n\
Chat-Version: 1.0\n\
Date: Sun, 22 Mar 2021 23:37:57 +0000\n\
\n\
second message\n",
false,
)
.await?;
receive_imf(
&t,
b"From: Bob Authname <bob@example.org>\n\
To: alice@example.org\n\
Subject: original subject\n\
Message-ID: <msg1@example.org>\n\
Chat-Version: 1.0\n\
Date: Sun, 22 Mar 2021 22:37:57 +0000\n\
\n\
first message\n",
false,
)
.await?;
let msg = t.get_last_msg().await;
let chat = Chat::load_from_db(&t, msg.chat_id).await?;
assert_eq!(
chat.param.get(Param::LastSubject).unwrap(),
"updated subject"
);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_out_of_order_group_name() -> Result<()> {
let t = TestContext::new_alice().await;
receive_imf(
&t,
b"From: Bob Authname <bob@example.org>\n\
To: alice@example.org\n\
Message-ID: <msg1@example.org>\n\
Chat-Version: 1.0\n\
Chat-Group-ID: abcde123456\n\
Chat-Group-Name: initial name\n\
Date: Sun, 22 Mar 2021 01:00:00 +0000\n\
\n\
first message\n",
false,
)
.await?;
let msg = t.get_last_msg().await;
let chat = Chat::load_from_db(&t, msg.chat_id).await?;
assert_eq!(chat.name, "initial name");
receive_imf(
&t,
b"From: Bob Authname <bob@example.org>\n\
To: alice@example.org\n\
Message-ID: <msg3@example.org>\n\
Chat-Version: 1.0\n\
Chat-Group-ID: abcde123456\n\
Chat-Group-Name: =?utf-8?q?another=0Aname update?=\n\
Chat-Group-Name-Changed: =?utf-8?q?a=0Aname update?=\n\
Date: Sun, 22 Mar 2021 03:00:00 +0000\n\
\n\
third message\n",
false,
)
.await?;
receive_imf(
&t,
b"From: Bob Authname <bob@example.org>\n\
To: alice@example.org\n\
Message-ID: <msg2@example.org>\n\
Chat-Version: 1.0\n\
Chat-Group-ID: abcde123456\n\
Chat-Group-Name: =?utf-8?q?a=0Aname update?=\n\
Chat-Group-Name-Changed: initial name\n\
Date: Sun, 22 Mar 2021 02:00:00 +0000\n\
\n\
second message\n",
false,
)
.await?;
let msg = t.get_last_msg().await;
let chat = Chat::load_from_db(&t, msg.chat_id).await?;
assert_eq!(chat.name, "another name update");
assert_eq!(msg.text.contains('\n'), false);
Ok(())
}
}