diff --git a/README.md b/README.md
index db0a438..175ffd0 100644
--- a/README.md
+++ b/README.md
@@ -33,10 +33,12 @@ docker run --rm -p 1080:1080 -p 1025:1025 marlonb/mailcrab:latest
Both the backend server and the frontend are written in Rust. The backend receives email over an unencrypted connection on a configurable port. All email is stored in memory while the application is running. An API exposes all received email:
-- `/api/messages` return all message metadata
-- `/api/message/[id]` returns a complete message, given its `id`
-- `/api/version` returns version information about the executable
-- `/ws` send email metadata to each connected client when a new email is received
+- `GET /api/messages` return all message metadata
+- `GET /api/message/[id]` returns a complete message, given its `id`
+- `POST /api/delete/[id]` deletes a message, given its `id`
+- `POST /api/delete-all` deletes all messages
+- `GET /api/version` returns version information about the executable
+- `GET /ws` send email metadata to each connected client when a new email is received
The frontend initially performs a call to `/api/messages` to receive all existing email metadata and then subscribes for new messages using the websocket connection. When opening a message, the `/api/message/[id]` endpoint is used to retrieve the complete message body and raw email.
diff --git a/backend/src/tests.rs b/backend/src/tests.rs
index c5b468a..4875894 100644
--- a/backend/src/tests.rs
+++ b/backend/src/tests.rs
@@ -41,7 +41,7 @@ async fn send_message(
.join("\n");
let html: String = format!(
"{}\n
external link
",
- body.replace("\n", "
\n")
+ body.replace('\n', "
\n")
);
let builder = Message::builder()
diff --git a/backend/src/web_server.rs b/backend/src/web_server.rs
index 88d1de7..3836ad7 100644
--- a/backend/src/web_server.rs
+++ b/backend/src/web_server.rs
@@ -6,7 +6,7 @@ use axum::{
},
http::{header, StatusCode, Uri},
response::{Html, IntoResponse, Response},
- routing::get,
+ routing::{get, post},
Extension, Json, Router,
};
use serde::Serialize;
@@ -165,6 +165,38 @@ async fn message_body_handler(
}
}
+/// delete a message
+async fn message_delete_handler(
+ Path(id): Path,
+ Extension(state): Extension>,
+) -> Result {
+ if let Ok(mut storage) = state.storage.write() {
+ if storage.remove(&id).is_some() {
+ info!("message {} removed", &id);
+
+ Ok(StatusCode::OK)
+ } else {
+ Err(StatusCode::NOT_FOUND)
+ }
+ } else {
+ Err(StatusCode::INTERNAL_SERVER_ERROR)
+ }
+}
+
+/// delete all messages
+async fn message_delete_all_handler(
+ Extension(state): Extension>,
+) -> Result {
+ if let Ok(mut storage) = state.storage.write() {
+ storage.clear();
+ info!("storage cleared");
+
+ Ok(StatusCode::OK)
+ } else {
+ Err(StatusCode::INTERNAL_SERVER_ERROR)
+ }
+}
+
/// return version
async fn version_handler() -> Result, StatusCode> {
let vi = VersionInfo {
@@ -220,6 +252,8 @@ pub async fn web_server(
.route("/api/messages", get(messages_handler))
.route("/api/message/:id", get(message_handler))
.route("/api/message/:id/body", get(message_body_handler))
+ .route("/api/delete/:id", post(message_delete_handler))
+ .route("/api/delete-all", post(message_delete_all_handler))
.route("/api/version", get(version_handler))
.nest_service("/static", get(static_handler));