v0.2.0
This commit is contained in:
1 parent
fc81ecafd6
commit
dc57aa7089
89 files changed
+5290
-1551
No files matched your search
+78
-58
@@ -402,7 +402,9 @@ fn upsert_and_index_headers(
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let _ = user_index.index_messages_batch(&indexable);
|
||||
user_index
|
||||
.index_messages_batch_with_connection(conn, &indexable)
|
||||
.map_err(|e| AppError::InternalError(format!("Search outbox error: {e}")))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -545,7 +547,6 @@ pub async fn get_message(
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
|
||||
|
||||
let usable_cache = cached_body.filter(|c| c.attachments_json.is_some());
|
||||
let fetched_body = usable_cache.is_none();
|
||||
|
||||
let (body_html, body_text, attachments, raw_headers, email_theme) = if let Some(cached) =
|
||||
usable_cache
|
||||
@@ -585,18 +586,32 @@ pub async fn get_message(
|
||||
.await
|
||||
.map_err(|e| match e {
|
||||
crate::imap::client::ImapError::MessageNotFound { .. } => {
|
||||
let _ = db::messages::delete_message(&conn, &folder, uid);
|
||||
let _ = db::folders::invalidate_folder_freshness(&conn, &folder);
|
||||
if let Ok(user_index) = search_engine.open_user_index(&session.user_hash) {
|
||||
let _ = user_index.delete_message(uid, &folder);
|
||||
if let Ok(transaction) = conn.unchecked_transaction() {
|
||||
let _ = db::messages::delete_message(&transaction, &folder, uid);
|
||||
let _ = db::folders::invalidate_folder_freshness(&transaction, &folder);
|
||||
if let Ok(user_index) = search_engine.open_user_index(&session.user_hash) {
|
||||
let _ = user_index.delete_message_with_connection(
|
||||
&transaction,
|
||||
uid,
|
||||
&folder,
|
||||
);
|
||||
}
|
||||
let _ = transaction.commit();
|
||||
}
|
||||
AppError::NotFound(format!("Message UID {uid} not found in folder {folder}"))
|
||||
}
|
||||
other => {
|
||||
let _ = db::messages::delete_message(&conn, &folder, uid);
|
||||
let _ = db::folders::invalidate_folder_freshness(&conn, &folder);
|
||||
if let Ok(user_index) = search_engine.open_user_index(&session.user_hash) {
|
||||
let _ = user_index.delete_message(uid, &folder);
|
||||
if let Ok(transaction) = conn.unchecked_transaction() {
|
||||
let _ = db::messages::delete_message(&transaction, &folder, uid);
|
||||
let _ = db::folders::invalidate_folder_freshness(&transaction, &folder);
|
||||
if let Ok(user_index) = search_engine.open_user_index(&session.user_hash) {
|
||||
let _ = user_index.delete_message_with_connection(
|
||||
&transaction,
|
||||
uid,
|
||||
&folder,
|
||||
);
|
||||
}
|
||||
let _ = transaction.commit();
|
||||
}
|
||||
AppError::ServiceUnavailable(format!("IMAP error: {other}"))
|
||||
}
|
||||
@@ -639,8 +654,11 @@ pub async fn get_message(
|
||||
.and_then(|h| email_theme::detect_email_theme(h))
|
||||
.map(|t| t.as_i32());
|
||||
|
||||
let transaction = conn
|
||||
.unchecked_transaction()
|
||||
.map_err(|e| AppError::InternalError(format!("Database transaction error: {e}")))?;
|
||||
db::messages::cache_message_body(
|
||||
&conn,
|
||||
&transaction,
|
||||
&folder,
|
||||
uid,
|
||||
resolved_html.as_deref(),
|
||||
@@ -651,6 +669,31 @@ pub async fn get_message(
|
||||
)
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
|
||||
|
||||
if let Some(text) = body.text_plain.as_ref()
|
||||
&& !UserIndex::is_excluded_folder(&folder)
|
||||
&& let Some(msg) = db::messages::get_single_message(&transaction, &folder, uid)
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?
|
||||
&& let Ok(user_index) = search_engine.open_user_index(&session.user_hash)
|
||||
{
|
||||
let indexable = IndexableMessage {
|
||||
uid: msg.uid,
|
||||
folder: msg.folder,
|
||||
subject: msg.subject,
|
||||
from_address: msg.from_address,
|
||||
from_name: msg.from_name,
|
||||
to_addresses: msg.to_addresses,
|
||||
body_text: text.clone(),
|
||||
date_epoch: crate::db::messages::parse_date_to_epoch_public(&msg.date),
|
||||
has_attachments: msg.has_attachments,
|
||||
};
|
||||
user_index
|
||||
.index_message_with_connection(&transaction, &indexable)
|
||||
.map_err(|e| AppError::InternalError(format!("Search outbox error: {e}")))?;
|
||||
}
|
||||
transaction
|
||||
.commit()
|
||||
.map_err(|e| AppError::InternalError(format!("Database commit error: {e}")))?;
|
||||
|
||||
(
|
||||
resolved_html,
|
||||
body.text_plain,
|
||||
@@ -742,30 +785,6 @@ pub async fn get_message(
|
||||
}
|
||||
};
|
||||
|
||||
if fetched_body
|
||||
&& let Some(ref text) = body_text
|
||||
&& !UserIndex::is_excluded_folder(&folder)
|
||||
{
|
||||
let indexable = IndexableMessage {
|
||||
uid: msg.uid,
|
||||
folder: msg.folder.clone(),
|
||||
subject: msg.subject.clone(),
|
||||
from_address: msg.from_address.clone(),
|
||||
from_name: msg.from_name.clone(),
|
||||
to_addresses: msg.to_addresses.clone(),
|
||||
body_text: text.clone(),
|
||||
date_epoch: crate::db::messages::parse_date_to_epoch_public(&msg.date),
|
||||
has_attachments: msg.has_attachments,
|
||||
};
|
||||
let search_engine = Arc::clone(&search_engine);
|
||||
let user_hash = session.user_hash.clone();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
if let Ok(user_index) = search_engine.open_user_index(&user_hash) {
|
||||
let _ = user_index.index_message(&indexable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let thread_messages = if let Some(ref message_id) = msg.message_id {
|
||||
db::messages::get_full_thread(&conn, message_id, msg.references_header.as_deref())
|
||||
.unwrap_or_default()
|
||||
@@ -973,34 +992,31 @@ pub async fn move_message_handler(
|
||||
let conn = db::pool::open_user_db(&config.data_dir, &session.user_hash)
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
|
||||
|
||||
db::messages::remove_after_mutation(&conn, &body.from_folder, body.uid)
|
||||
let transaction = conn
|
||||
.unchecked_transaction()
|
||||
.map_err(|e| AppError::InternalError(format!("Database transaction error: {e}")))?;
|
||||
db::messages::remove_after_mutation_in_transaction(&transaction, &body.from_folder, body.uid)
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
|
||||
|
||||
let user_hash = session.user_hash.clone();
|
||||
let from_folder = body.from_folder.clone();
|
||||
let uid = body.uid;
|
||||
let search_result = tokio::task::spawn_blocking(move || {
|
||||
let index = search_engine.open_user_index(&user_hash)?;
|
||||
index.delete_message(uid, &from_folder)
|
||||
})
|
||||
.await;
|
||||
if !matches!(search_result, Ok(Ok(()))) {
|
||||
tracing::warn!(
|
||||
?search_result,
|
||||
"Failed to remove moved message from search index"
|
||||
);
|
||||
if let Ok(index) = search_engine.open_user_index(&session.user_hash) {
|
||||
index
|
||||
.delete_message_with_connection(&transaction, body.uid, &body.from_folder)
|
||||
.map_err(|e| AppError::InternalError(format!("Search outbox error: {e}")))?;
|
||||
}
|
||||
|
||||
db::folders::refresh_unread_count(&conn, &body.from_folder)
|
||||
db::folders::refresh_unread_count(&transaction, &body.from_folder)
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
|
||||
|
||||
if was_unread {
|
||||
db::folders::adjust_unread_count(&conn, &body.to_folder, 1)
|
||||
db::folders::adjust_unread_count(&transaction, &body.to_folder, 1)
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
|
||||
}
|
||||
|
||||
db::folders::invalidate_folder_freshness(&conn, &body.to_folder)
|
||||
db::folders::invalidate_folder_freshness(&transaction, &body.to_folder)
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
|
||||
transaction
|
||||
.commit()
|
||||
.map_err(|e| AppError::InternalError(format!("Database commit error: {e}")))?;
|
||||
|
||||
let undo_move = undo_destination_uid.map(|destination_uid| {
|
||||
serde_json::json!({
|
||||
@@ -1454,6 +1470,7 @@ mod sync_tests {
|
||||
limit: 10,
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
.0
|
||||
.is_empty()
|
||||
@@ -1646,12 +1663,14 @@ mod sync_tests {
|
||||
.is_none()
|
||||
);
|
||||
assert!(db::folders::is_folder_fresh(&conn, "INBOX", 30).unwrap());
|
||||
let requests = fresh_client.header_requests.lock().unwrap();
|
||||
assert_eq!(requests.len(), 4);
|
||||
assert!(requests.iter().all(|(_, uids)| {
|
||||
uids.split(',')
|
||||
.all(|uid| uid.parse::<u32>().unwrap() <= 900)
|
||||
}));
|
||||
{
|
||||
let requests = fresh_client.header_requests.lock().unwrap();
|
||||
assert_eq!(requests.len(), 4);
|
||||
assert!(requests.iter().all(|(_, uids)| {
|
||||
uids.split(',')
|
||||
.all(|uid| uid.parse::<u32>().unwrap() <= 900)
|
||||
}));
|
||||
}
|
||||
let results = engine
|
||||
.open_user_index(user_hash)
|
||||
.unwrap()
|
||||
@@ -1661,6 +1680,7 @@ mod sync_tests {
|
||||
limit: 1100,
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
.0;
|
||||
assert!(results.iter().any(|message| message.uid == 1));
|
||||
|
||||
Reference in new issue
Block a user