Procházet zdrojové kódy

new endpoints added

Yurii Sokolovskyi před 3 měsíci
rodič
revize
2697202918
3 změnil soubory, kde provedl 129 přidání a 22 odebrání
  1. 78 5
      src/main.rs
  2. 32 16
      src/server.rs
  3. 19 1
      src/server_wasi.rs

+ 78 - 5
src/main.rs

@@ -10,26 +10,30 @@ use std::io::{BufReader, Write};
 use std::net::SocketAddr;
 use std::time::Duration;
 use anyhow::anyhow;
-use serde::Deserialize;
+use serde::{Deserialize, Serialize};
 use crate::indexes::{Indexes, SerializableMessage, SerializableThread};
 use config::{Config, INSTANCE};
 use crate::server::{get_email, get_folders, get_sorted_threads_by_date, get_thread_messages};
 use mailparse::parse_mail;
 use regex::Regex;
 use crate::templates::util::parse_email;
+use crate::util::{compress_and_save_file, read_and_decompress_file};
 
 #[cfg(not(target_os = "wasi"))]
 use axum::extract::Query;
 #[cfg(not(target_os = "wasi"))]
 use axum::{Json, Router};
 #[cfg(not(target_os = "wasi"))]
-use axum::http::Method;
+use axum::http::{Method, StatusCode};
 #[cfg(not(target_os = "wasi"))]
 use axum::response::{IntoResponse, Response};
 #[cfg(not(target_os = "wasi"))]
 use axum::routing::{get, post};
 #[cfg(not(target_os = "wasi"))]
 use tower_http::cors::{Any, CorsLayer};
+#[cfg(not(target_os = "wasi"))]
+use imap::create_folder;
+
 
 #[cfg(target_os = "wasi")]
 use bytecodec::DecodeExt;
@@ -38,14 +42,13 @@ use httpcodec::{HttpVersion, ReasonPhrase, Request, RequestDecoder, Response, St
 #[cfg(target_os = "wasi")]
 use lettre::message::{Mailbox, Message as LettreMessage, MultiPart, SinglePart};
 use tokio::runtime::Runtime;
-use tokio::time::sleep;
 #[cfg(target_os = "wasi")]
 use wasmedge_wasi_socket::{Shutdown, TcpListener, TcpStream};
+use crate::imap::{delete_folder, rename_folder};
 #[cfg(target_os = "wasi")]
 use crate::server_wasi::{handle_client};
 #[cfg(target_os = "wasi")]
 use crate::smtp_client::{send_email};
-use crate::util::{compress_and_save_file, read_and_decompress_file};
 
 mod smtp_client;
 
@@ -393,7 +396,7 @@ async fn main() {
 
     // looking for updates
     // let imap_update_handle = tokio::spawn(async move {
-    //     imap::check_for_updates("INBOX".to_string()).await.expect("TODO: panic message");
+    //     imap::check_for_updates("INBOX".to_string()).await.expect("panic message");
     // });
     
 
@@ -415,6 +418,9 @@ async fn main() {
             .route("/sorted_threads_by_date", get(sorted_threads_by_date_handle))
             .route("/get_thread_messages", get(get_thread_messages_handle))
             .route("/email", get(get_email_handle))
+            .route("/create_folder", post(create_folder_handle))
+            .route("/rename_folder", post(rename_folder_handle))
+            .route("/delete_folder", post(delete_folder_handle))
             .layer(cors);
 
         
@@ -431,6 +437,12 @@ async fn main() {
     handle.join().unwrap();
 }
 
+#[derive(Deserialize)]
+#[derive(Serialize)]
+struct ErrorResponse {
+    error: String,
+}
+
 #[cfg(not(target_os = "wasi"))]
 #[derive(Deserialize)]
 struct GetSortedThreadsByDateQuery {
@@ -469,3 +481,64 @@ async fn get_thread_messages_handle(Query(params): Query<GetThreadMessagesQuery>
     let result: Vec<SerializableMessage> = serde_json::from_str(&*get_thread_messages(params.id).await).unwrap();
     Json(result)
 }
+
+#[cfg(not(target_os = "wasi"))]
+#[derive(Deserialize)]
+struct CreateFolderRequest {
+    name: String,
+}
+#[cfg(not(target_os = "wasi"))]
+async fn create_folder_handle(Json(data): Json<CreateFolderRequest>) -> impl IntoResponse {
+    match create_folder(data.name.clone()).await {
+        Ok(_) => {
+            (StatusCode::OK, "OK").into_response()
+        }
+        Err(_) => {
+            let error_response = ErrorResponse {
+                error: format!("Cannot create folder {}", data.name),
+            };
+            (StatusCode::BAD_REQUEST, Json(error_response)).into_response()
+        }
+    }
+}
+
+#[cfg(not(target_os = "wasi"))]
+#[derive(Deserialize)]
+struct DeleteFolderRequest {
+    name: String,
+}
+#[cfg(not(target_os = "wasi"))]
+async fn delete_folder_handle(Json(data): Json<DeleteFolderRequest>) -> impl IntoResponse {
+    match delete_folder(data.name.clone()).await {
+        Ok(_) => {
+            (StatusCode::OK, "OK").into_response()
+        }
+        Err(_) => {
+            let error_response = ErrorResponse {
+                error: format!("Cannot delete folder {}", data.name),
+            };
+            (StatusCode::BAD_REQUEST, Json(error_response)).into_response()
+        }
+    }
+}
+
+#[cfg(not(target_os = "wasi"))]
+#[derive(Deserialize)]
+struct RenameFolderRequest {
+    old_name: String,
+    new_name: String
+}
+#[cfg(not(target_os = "wasi"))]
+async fn rename_folder_handle(Json(data): Json<RenameFolderRequest>) -> impl IntoResponse {
+    match rename_folder(data.old_name.clone(), data.new_name.clone()).await {
+        Ok(_) => {
+            (StatusCode::OK, "OK").into_response()
+        }
+        Err(_) => {
+            let error_response = ErrorResponse {
+                error: format!("Cannot rename folder from {} to {}", data.old_name, data.new_name),
+            };
+            (StatusCode::BAD_REQUEST, Json(error_response)).into_response()
+        }
+    }
+}

+ 32 - 16
src/server.rs

@@ -1,13 +1,8 @@
 use crate::config::Config;
 use crate::indexes::{SerializableMessage, SerializableThread};
 use serde::{Deserialize, Serialize};
-use std::collections::HashMap;
 use std::fs::File;
-use std::io;
-use std::io::{BufReader, Read};
-use std::string::FromUtf8Error;
-use chrono::NaiveDate;
-// use serde_json::Value::String;
+use std::io::{BufReader};
 use crate::util::read_and_decompress_file;
 
 pub async fn get_folders() -> String {
@@ -63,9 +58,7 @@ pub async fn get_email(id: String) -> String {
     content
 }
 
-pub async fn get_thread_messages(
-    id: u32
-) -> String {
+pub async fn get_thread_messages(id: u32) -> String {
     let threads_path = Config::global()
         .out_dir
         .clone()
@@ -112,10 +105,7 @@ pub async fn get_thread_messages(
     }
 }
 
-async fn get_threads(
-    folder: String,
-    file_name: String,
-) -> String {
+async fn get_threads(folder: String, file_name: String) -> String {
     let path = Config::global()
         .out_dir
         .clone()
@@ -136,8 +126,34 @@ async fn get_threads(
     serde_json::to_string(&messages).unwrap()
 }
 
-pub async fn get_sorted_threads_by_date(
-    folder: String
-) -> String {
+pub async fn get_sorted_threads_by_date(folder: String) -> String {
     get_threads(folder, "date.json".to_string()).await
 }
+
+#[derive(Deserialize)]
+struct CreateFolderRequest {
+    name: String,
+}
+pub async fn create_folder(body: String) -> anyhow::Result<()>{
+    let data: CreateFolderRequest = serde_json::from_str(&*body)?;
+    crate::imap::create_folder(data.name.clone()).await
+}
+
+#[derive(Deserialize)]
+struct DeleteFolderRequest {
+    name: String,
+}
+pub async fn delete_folder(body: String) -> anyhow::Result<()>{
+    let data: DeleteFolderRequest = serde_json::from_str(&*body)?;
+    crate::imap::delete_folder(data.name.clone()).await
+}
+
+#[derive(Deserialize)]
+struct RenameFolderRequest {
+    old_name: String,
+    new_name: String
+}
+pub async fn rename_folder(body: String) -> anyhow::Result<()>{
+    let data: RenameFolderRequest = serde_json::from_str(&*body)?;
+    crate::imap::rename_folder(data.old_name.clone(), data.new_name.clone()).await
+}

+ 19 - 1
src/server_wasi.rs

@@ -7,7 +7,7 @@ use serde::de::Unexpected::Str;
 use bytecodec::DecodeExt;
 use httpcodec::{HttpVersion, ReasonPhrase, Request, RequestDecoder, Response, StatusCode, Header};
 use wasmedge_wasi_socket::{Shutdown, TcpListener, TcpStream};
-use crate::server::{get_email, get_folders, get_sorted_threads_by_date, get_thread_messages};
+use crate::server::{get_email, get_folders, get_sorted_threads_by_date, get_thread_messages, create_folder, delete_folder, rename_folder};
 
 async fn handle_http(req: Request<String>, request_line: &str) -> anyhow::Result<String> {
     let parts: Vec<&str> = request_line.split_whitespace().collect();
@@ -48,6 +48,24 @@ async fn handle_http(req: Request<String>, request_line: &str) -> anyhow::Result
                 format!("{}", get_email(value.to_owned()).await)
             }else{ "404 Not Found".to_string() }
         },
+        "/create_folder" => {
+            match create_folder(req.body().clone()).await {
+                Ok(_) => "OK".to_string(), // TODO return 200 OK
+                Err(_) => "400 Bad Request".to_string(),
+            }
+        },
+        "/delete_folder" => {
+            match delete_folder(req.body().clone()).await {
+                Ok(_) => "OK".to_string(), // TODO return 200 OK
+                Err(_) => "400 Bad Request".to_string(),
+            }
+        },
+        "/rename_folder" => {
+            match rename_folder(req.body().clone()).await {
+                Ok(_) => "OK".to_string(), // TODO return 200 OK
+                Err(_) => "400 Bad Request".to_string(),
+            }
+        },
         _ => "404 Not Found".to_string(),
     };