1 parent
96a32ea8fb
commit
a643e7e3ab
106 files changed
+2223
-4669
No files matched your search
@@ -12,10 +12,6 @@ use crate::error::AppError;
|
||||
use crate::imap::client::{ImapClient, ImapCredentials};
|
||||
use crate::search::engine::SearchEngine;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Request / Response types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CreateFolderRequest {
|
||||
pub name: String,
|
||||
@@ -36,19 +32,12 @@ struct MessageResponse {
|
||||
status: &'static str,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Folder names that must not be renamed or deleted.
|
||||
const SYSTEM_FOLDERS: &[&str] = &["INBOX", "Sent", "Drafts", "Trash", "Junk", "Spam"];
|
||||
|
||||
/// Returns `true` if the folder is a system folder (case-insensitive).
|
||||
fn is_system_folder(name: &str) -> bool {
|
||||
SYSTEM_FOLDERS.iter().any(|s| s.eq_ignore_ascii_case(name))
|
||||
}
|
||||
|
||||
/// Validates a folder name. Returns `Ok(())` if valid, or an `AppError::BadRequest`.
|
||||
fn validate_folder_name(name: &str) -> Result<(), AppError> {
|
||||
if name.trim().is_empty() {
|
||||
return Err(AppError::BadRequest(
|
||||
@@ -73,7 +62,6 @@ fn validate_folder_name(name: &str) -> Result<(), AppError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Build IMAP credentials from the session and app configuration.
|
||||
fn build_creds(session: &SessionState, _config: &AppConfig) -> Result<ImapCredentials, AppError> {
|
||||
Ok(ImapCredentials {
|
||||
host: session.imap_host.clone(),
|
||||
@@ -85,11 +73,6 @@ fn build_creds(session: &SessionState, _config: &AppConfig) -> Result<ImapCreden
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Handlers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// `POST /api/folders` -- create a new IMAP folder.
|
||||
pub async fn create_folder(
|
||||
Extension(session): Extension<SessionState>,
|
||||
Extension(config): Extension<Arc<AppConfig>>,
|
||||
@@ -100,13 +83,11 @@ pub async fn create_folder(
|
||||
|
||||
let creds = build_creds(&session, &config)?;
|
||||
|
||||
// Create the folder on the IMAP server (also subscribes).
|
||||
imap_client
|
||||
.create_folder(&creds, &body.name)
|
||||
.await
|
||||
.map_err(|e| AppError::InternalError(format!("IMAP create_folder failed: {e}")))?;
|
||||
|
||||
// Cache the new folder locally.
|
||||
let conn = db::pool::open_user_db(&config.data_dir, &session.user_hash)
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
|
||||
|
||||
@@ -116,7 +97,6 @@ pub async fn create_folder(
|
||||
Ok(Json(MessageResponse { status: "created" }).into_response())
|
||||
}
|
||||
|
||||
/// `PATCH /api/folders/:name` -- rename an existing folder.
|
||||
pub async fn rename_folder(
|
||||
Extension(session): Extension<SessionState>,
|
||||
Extension(config): Extension<Arc<AppConfig>>,
|
||||
@@ -139,7 +119,6 @@ pub async fn rename_folder(
|
||||
.await
|
||||
.map_err(|e| AppError::InternalError(format!("IMAP rename_folder failed: {e}")))?;
|
||||
|
||||
// Update the local cache.
|
||||
let conn = db::pool::open_user_db(&config.data_dir, &session.user_hash)
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
|
||||
|
||||
@@ -151,7 +130,6 @@ pub async fn rename_folder(
|
||||
Ok(Json(MessageResponse { status: "renamed" }).into_response())
|
||||
}
|
||||
|
||||
/// `DELETE /api/folders/:name` -- delete a folder.
|
||||
pub async fn delete_folder(
|
||||
Extension(session): Extension<SessionState>,
|
||||
Extension(config): Extension<Arc<AppConfig>>,
|
||||
@@ -171,7 +149,6 @@ pub async fn delete_folder(
|
||||
.await
|
||||
.map_err(|e| AppError::InternalError(format!("IMAP delete_folder failed: {e}")))?;
|
||||
|
||||
// Remove from local cache.
|
||||
let conn = db::pool::open_user_db(&config.data_dir, &session.user_hash)
|
||||
.map_err(|e| AppError::InternalError(format!("Database error: {e}")))?;
|
||||
|
||||
@@ -183,7 +160,6 @@ pub async fn delete_folder(
|
||||
Ok(Json(MessageResponse { status: "deleted" }).into_response())
|
||||
}
|
||||
|
||||
/// `PATCH /api/folders/:name/subscribe` -- toggle folder subscription.
|
||||
pub async fn subscribe_folder(
|
||||
Extension(session): Extension<SessionState>,
|
||||
Extension(config): Extension<Arc<AppConfig>>,
|
||||
@@ -208,7 +184,6 @@ pub async fn subscribe_folder(
|
||||
.into_response())
|
||||
}
|
||||
|
||||
/// `POST /api/folders/:name/mark-all-read` -- add \Seen to every message.
|
||||
pub async fn mark_all_read(
|
||||
Extension(session): Extension<SessionState>,
|
||||
Extension(config): Extension<Arc<AppConfig>>,
|
||||
@@ -237,7 +212,6 @@ pub async fn mark_all_read(
|
||||
Ok(Json(MessageResponse { status: "read" }).into_response())
|
||||
}
|
||||
|
||||
/// `POST /api/folders/:name/empty` -- permanently remove every message.
|
||||
pub async fn empty_folder(
|
||||
Extension(session): Extension<SessionState>,
|
||||
Extension(config): Extension<Arc<AppConfig>>,
|
||||
@@ -281,10 +255,6 @@ pub async fn empty_folder(
|
||||
Ok(Json(MessageResponse { status: "emptied" }).into_response())
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in new issue
Block a user