Jelajahi Sumber

API endpoints fix

Yurii Sokolovskyi 3 bulan lalu
induk
melakukan
0a7617208b
4 mengubah file dengan 139 tambahan dan 32 penghapusan
  1. 30 15
      src/indexes.rs
  2. 17 6
      src/main.rs
  3. 81 9
      src/server.rs
  4. 11 2
      src/server_wasi.rs

+ 30 - 15
src/indexes.rs

@@ -11,8 +11,8 @@ use crate::models::{MailAddress, StrMessage};
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
 pub struct SerializableThread{
-    id: u32,
-    messages: Vec<String>
+    pub id: u32,
+    pub messages: Vec<String>
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -173,21 +173,24 @@ impl Indexes {
         
         Ok(())
     }
-    
-    pub fn group_threads_by_subject(mut threads: &mut Vec<SerializableThread>, list: String, messages: &mut Vec<SerializableMessage>) -> anyhow::Result<HashMap<String, Vec<u32>>>{
+
+    pub fn group_threads_by_subject(mut threads: &mut Vec<SerializableThread>, list: String, messages: &mut Vec<SerializableMessage>) -> anyhow::Result<Vec<(String, Vec<u32>)>>{
         let threads_for_list = Self::get_threads_for_list(list.clone(), threads, messages);
         let mut map: HashMap<String, Vec<u32>> = HashMap::new();
 
         for thread in threads_for_list {
-            map.entry(Self::get_last_from_list_from_thread(&thread, list.clone(), messages).unwrap().subject)
+            map.entry(Self::get_last_from_list_from_thread(&thread, list.clone(), messages).unwrap().subject.trim().to_string())
                 .or_insert_with(Vec::new)
                 .push(thread.id);
         }
+
+        let mut sorted_vec: Vec<(String, Vec<u32>)> = map.into_iter().collect();
+        sorted_vec.sort_by(|a, b| a.0.cmp(&b.0));
         
-        Ok(map)
+        Ok(sorted_vec)
     }
     
-    pub fn group_threads_by_date(mut threads: &mut Vec<SerializableThread>, list: String, messages: &mut Vec<SerializableMessage>) -> anyhow::Result<HashMap<NaiveDate, Vec<u32>>> {
+    pub fn group_threads_by_date(mut threads: &mut Vec<SerializableThread>, list: String, messages: &mut Vec<SerializableMessage>) -> anyhow::Result<Vec<(NaiveDate, Vec<u32>)>> {
         let threads_for_list = Self::get_threads_for_list(list.clone(), threads, messages);
         let mut map: HashMap<NaiveDate, Vec<(DateTime<Utc>, u32)>> = HashMap::new();
 
@@ -207,11 +210,14 @@ impl Indexes {
                 (date, sorted_ids)
             })
             .collect();
-
-        Ok(sorted_map)
+        
+        let mut sorted_vec: Vec<(NaiveDate, Vec<u32>)> = sorted_map.into_iter().collect();
+        sorted_vec.sort_by(|a, b| a.0.cmp(&b.0));
+        
+        Ok(sorted_vec)
     }
 
-    pub fn group_threads_by_sender(mut threads: &mut Vec<SerializableThread>, list: String, messages: &mut Vec<SerializableMessage>) -> anyhow::Result<HashMap<String, Vec<u32>>>{
+    pub fn group_threads_by_sender(mut threads: &mut Vec<SerializableThread>, list: String, messages: &mut Vec<SerializableMessage>) -> anyhow::Result<Vec<(String, Vec<u32>)>>{
         let mut threads_for_list = Self::get_threads_for_list(list.clone(), threads, messages);
         let mut map: HashMap<String, Vec<u32>> = HashMap::new();
 
@@ -221,10 +227,13 @@ impl Indexes {
                 .push(thread.id);
         }
 
-        Ok(map)
+        let mut sorted_vec: Vec<(String, Vec<u32>)> = map.into_iter().collect();
+        sorted_vec.sort_by(|a, b| a.0.cmp(&b.0));
+        
+        Ok(sorted_vec)
     }
 
-    pub fn group_threads_by_receiver(mut threads: &mut Vec<SerializableThread>, list: String, messages: &mut Vec<SerializableMessage>) -> anyhow::Result<HashMap<String, Vec<u32>>>{
+    pub fn group_threads_by_receiver(mut threads: &mut Vec<SerializableThread>, list: String, messages: &mut Vec<SerializableMessage>) -> anyhow::Result<Vec<(String, Vec<u32>)>>{
         let mut threads_for_list = Self::get_threads_for_list(list.clone(), threads, messages);
         let mut map: HashMap<String, Vec<u32>> = HashMap::new();
 
@@ -236,10 +245,13 @@ impl Indexes {
             }
         }
 
-        Ok(map)
+        let mut sorted_vec: Vec<(String, Vec<u32>)> = map.into_iter().collect();
+        sorted_vec.sort_by(|a, b| a.0.cmp(&b.0));
+        
+        Ok(sorted_vec)
     }
 
-    pub fn group_threads_by_cc(mut threads: &mut Vec<SerializableThread>, list: String, messages: &mut Vec<SerializableMessage>) -> anyhow::Result<HashMap<String, Vec<u32>>>{
+    pub fn group_threads_by_cc(mut threads: &mut Vec<SerializableThread>, list: String, messages: &mut Vec<SerializableMessage>) -> anyhow::Result<Vec<(String, Vec<u32>)>>{
         let mut threads_for_list = Self::get_threads_for_list(list.clone(), threads, messages);
         let mut map: HashMap<String, Vec<u32>> = HashMap::new();
 
@@ -251,7 +263,10 @@ impl Indexes {
             }
         }
 
-        Ok(map)
+        let mut sorted_vec: Vec<(String, Vec<u32>)> = map.into_iter().collect();
+        sorted_vec.sort_by(|a, b| a.0.cmp(&b.0));
+        
+        Ok(sorted_vec)
     }
     
     fn get_threads_for_list(list: String, mut threads: &mut Vec<SerializableThread>, messages: &mut Vec<SerializableMessage>) -> Vec<SerializableThread>{

+ 17 - 6
src/main.rs

@@ -12,7 +12,7 @@ use anyhow::anyhow;
 use serde::Deserialize;
 use crate::indexes::{Indexes, SerializableMessage, SerializableThread};
 use config::{Config, INSTANCE};
-use crate::server::{get_email, get_folders, get_sorted_threads_by_date};
+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;
@@ -363,6 +363,7 @@ async fn main() {
     let app = Router::new()
         .route("/folders", get(get_folders_handle))
         .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))
         .layer(cors);
     
@@ -376,10 +377,9 @@ async fn main() {
 struct GetSortedThreadsByDateQuery {
     folder: String,
 }
-
 #[cfg(not(target_os = "wasi"))]
-async fn sorted_threads_by_date_handle(Query(params): Query<GetSortedThreadsByDateQuery>) -> Json<HashMap<String, Vec<SerializableMessage>>> {
-    let result: HashMap<String, Vec<SerializableMessage>> = serde_json::from_str(&*get_sorted_threads_by_date(params.folder).await).unwrap();
+async fn sorted_threads_by_date_handle(Query(params): Query<GetSortedThreadsByDateQuery>) -> Json<Vec<(String, Vec<u32>)>> {
+    let result: Vec<(String, Vec<u32>)> = serde_json::from_str(&*get_sorted_threads_by_date(params.folder).await).unwrap();
     Json(result)
 }
 
@@ -392,10 +392,21 @@ async fn get_folders_handle() -> Json<Vec<String>> {
 #[cfg(not(target_os = "wasi"))]
 #[derive(Deserialize)]
 struct GetEmailQuery {
-    path: String,
+    id: String,
 }
 #[cfg(not(target_os = "wasi"))]
 async fn get_email_handle(Query(params): Query<GetEmailQuery>) -> Json<String> {
-    let result: String  = get_email(params.path).await;
+    let result: String  = get_email(params.id).await;
+    Json(result)
+}
+
+#[cfg(not(target_os = "wasi"))]
+#[derive(Deserialize)]
+struct GetThreadMessagesQuery {
+    id: u32,
+}
+#[cfg(not(target_os = "wasi"))]
+async fn get_thread_messages_handle(Query(params): Query<GetThreadMessagesQuery>) -> Json<Vec<SerializableMessage>> {
+    let result: Vec<SerializableMessage> = serde_json::from_str(&*get_thread_messages(params.id).await).unwrap();
     Json(result)
 }

+ 81 - 9
src/server.rs

@@ -1,10 +1,11 @@
 use crate::config::Config;
-use crate::indexes::SerializableMessage;
+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 chrono::NaiveDate;
 
 pub async fn get_folders() -> String {
     let mut folders: Vec<String> = Vec::new();
@@ -25,20 +26,91 @@ pub async fn get_folders() -> String {
     serde_json::to_string(&folders).unwrap()
 }
 
-pub async fn get_email(relative_path: String) -> String {
-    let abs_path = Config::global().out_dir.clone().join(relative_path);
-    let mut file = match File::open(abs_path) {
+pub async fn get_email(id: String) -> String {
+    let messages_path = Config::global()
+        .out_dir
+        .clone()
+        .join("messages.json");
+    let messages_file = match File::open(messages_path) {
+        Ok(file) => file,
+        Err(_) => return String::new(),
+    };
+    let messages_reader = BufReader::new(messages_file);
+    let messages: Vec<SerializableMessage> = match serde_json::from_reader(messages_reader)
+    {
+        Ok(messages) => messages,
+        Err(_) => return String::new(),
+    };
+    let message = match messages.iter().find(|message| message.id == id){
+        None => {return String::new()}
+        Some(message) => {message}
+    };
+    
+    let abs_path = Config::global().out_dir.clone()
+        .join(message.list.clone())
+        .join("messages")
+        .join(message.hash.clone() + ".html");
+    let mut file = match File::open(abs_path.clone()) {
         Ok(content) => {content}
         Err(_) => {return "".to_string()}
     };
     let mut content = String::new();
     match file.read_to_string(&mut content) {
         Ok(_) => {}
-        Err(_) => {return "".to_string()}
+        Err(_) => {return String::new()}
     };
     content
 }
 
+pub async fn get_thread_messages(
+    id: u32
+) -> String {
+    let threads_path = Config::global()
+        .out_dir
+        .clone()
+        .join("threads.json");
+    let messages_path = Config::global()
+        .out_dir
+        .clone()
+        .join("messages.json");
+    
+    let threads_file = match File::open(threads_path) {
+        Ok(file) => file,
+        Err(_) => return serde_json::to_string(&Vec::<String>::new()).unwrap(),
+    };
+    let messages_file = match File::open(messages_path) {
+        Ok(file) => file,
+        Err(_) => return serde_json::to_string(&Vec::<SerializableMessage>::new()).unwrap(),
+    };
+    
+    let threads_reader = BufReader::new(threads_file);
+    let messages_reader = BufReader::new(messages_file);
+    
+    let threads: Vec<SerializableThread> = match serde_json::from_reader(threads_reader)
+    {
+        Ok(threads) => threads,
+        Err(_) => return serde_json::to_string(&Vec::<SerializableMessage>::new()).unwrap(),
+    };
+
+    if let Some(thread) = threads.into_iter().find(|thread| thread.id == id) {
+        let messages: Vec<SerializableMessage> = match serde_json::from_reader(messages_reader)
+        {
+            Ok(messages) => messages,
+            Err(_) => return serde_json::to_string(&Vec::<SerializableMessage>::new()).unwrap(),
+        };
+
+        let result_messages: Vec<SerializableMessage> = thread.messages.into_iter()
+            .filter_map(|message_id| {
+                messages.iter().find(|message| message.id == message_id).cloned()
+            })
+            .collect();
+
+        serde_json::to_string(&result_messages).unwrap()
+    } else {
+        serde_json::to_string(&Vec::<SerializableMessage>::new()).unwrap()
+    }
+}
+
 async fn get_threads(
     folder: String,
     file_name: String,
@@ -51,13 +123,13 @@ async fn get_threads(
 
     let file = match File::open(path) {
         Ok(file) => file,
-        Err(_) => return serde_json::to_string(&HashMap::<String, Vec<SerializableMessage>>::new()).unwrap(),
+        Err(_) => return serde_json::to_string(&Vec::<(String, Vec<u32>)>::new()).unwrap(),
     };
     let reader = BufReader::new(file);
-    let messages: HashMap<String, Vec<SerializableMessage>> = match serde_json::from_reader(reader)
+    let messages: Vec<(String, Vec<u32>)> = match serde_json::from_reader(reader)
     {
         Ok(messages) => messages,
-        Err(_) => return serde_json::to_string(&HashMap::<String, Vec<SerializableMessage>>::new()).unwrap(),
+        Err(_) => return serde_json::to_string(&Vec::<(String, Vec<u32>)>::new()).unwrap(),
     };
 
     serde_json::to_string(&messages).unwrap()
@@ -66,5 +138,5 @@ async fn get_threads(
 pub async fn get_sorted_threads_by_date(
     folder: String
 ) -> String {
-    get_threads(folder, "dates.json".to_string()).await
+    get_threads(folder, "date.json".to_string()).await
 }

+ 11 - 2
src/server_wasi.rs

@@ -3,10 +3,11 @@
 use std::collections::HashMap;
 use std::io::{Read, Write};
 use anyhow::anyhow;
+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};
+use crate::server::{get_email, get_folders, get_sorted_threads_by_date, get_thread_messages};
 
 async fn handle_http(req: Request<String>, request_line: &str) -> anyhow::Result<String> {
     let parts: Vec<&str> = request_line.split_whitespace().collect();
@@ -34,8 +35,16 @@ async fn handle_http(req: Request<String>, request_line: &str) -> anyhow::Result
                 format!("{}", get_sorted_threads_by_date(value.to_owned()).await)
             }else{ "404 Not Found".to_string() }
         },
+        "/get_thread_messages" => {
+            if let Some(value) = query.get("id"){
+                match value.parse::<u32>() {
+                    Ok(value) => format!("{}", get_thread_messages(value).await),
+                    Err(_e) => "404 Not Found".to_string(),
+                }
+            }else{"404 Not Found".to_string()}
+        }
         "/email" => {
-            if let Some(value) = query.get("path"){
+            if let Some(value) = query.get("id"){
                 format!("{}", get_email(value.to_owned()).await)
             }else{ "404 Not Found".to_string() }
         },