|
@@ -1,16 +1,27 @@
|
|
use crate::config::Config;
|
|
use crate::config::Config;
|
|
-use crate::indexes::{SerializableMessage, SerializableThread};
|
|
|
|
|
|
+use crate::indexes::{Indexes, SerializableMessage, SerializableThread};
|
|
use serde::{Deserialize, Serialize};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::fs::File;
|
|
use std::fs::File;
|
|
use std::io::{BufReader};
|
|
use std::io::{BufReader};
|
|
use std::net::{IpAddr, SocketAddr};
|
|
use std::net::{IpAddr, SocketAddr};
|
|
use std::str::FromStr;
|
|
use std::str::FromStr;
|
|
|
|
+use chrono::{DateTime, Utc};
|
|
use warp::Filter;
|
|
use warp::Filter;
|
|
use warp::http::StatusCode;
|
|
use warp::http::StatusCode;
|
|
use crate::{create_folder_lar, delete_folder_lar, rename_folder_lar};
|
|
use crate::{create_folder_lar, delete_folder_lar, rename_folder_lar};
|
|
|
|
+use crate::models::MailAddress;
|
|
use crate::sonic::SearchSonic;
|
|
use crate::sonic::SearchSonic;
|
|
use crate::util::read_and_decompress_file;
|
|
use crate::util::read_and_decompress_file;
|
|
|
|
|
|
|
|
+/// folders -> GET, returns list of all mailboxes
|
|
|
|
+/// sorted_threads_by_date -> GET, returns hashmap with date: list of thread ids sorted by date
|
|
|
|
+/// get_thread -> GET, returns all information about one thread
|
|
|
|
+/// get_thread_messages -> GET, returns a list of SerializableMessage in the thread
|
|
|
|
+/// email -> GET, returns html for the message
|
|
|
|
+/// search -> GET, returns a list of message ids where search found matches
|
|
|
|
+/// create_folder -> POST, creates a new mailbox
|
|
|
|
+/// rename_folder -> POST, renames a mailbox
|
|
|
|
+/// delete_folder -> POST, deletes a mailbox
|
|
pub async fn run_api() {
|
|
pub async fn run_api() {
|
|
let cors = warp::cors()
|
|
let cors = warp::cors()
|
|
.allow_any_origin()
|
|
.allow_any_origin()
|
|
@@ -24,6 +35,10 @@ pub async fn run_api() {
|
|
.and(warp::get())
|
|
.and(warp::get())
|
|
.and(warp::query::<GetSortedThreadsByDateQuery>())
|
|
.and(warp::query::<GetSortedThreadsByDateQuery>())
|
|
.and_then(sorted_threads_by_date_handle))
|
|
.and_then(sorted_threads_by_date_handle))
|
|
|
|
+ .or(warp::path("get_thread")
|
|
|
|
+ .and(warp::get())
|
|
|
|
+ .and(warp::query::<GetThreadQuery>())
|
|
|
|
+ .and_then(get_thread_handle))
|
|
.or(warp::path("get_thread_messages")
|
|
.or(warp::path("get_thread_messages")
|
|
.and(warp::get())
|
|
.and(warp::get())
|
|
.and(warp::query::<GetThreadMessagesQuery>())
|
|
.and(warp::query::<GetThreadMessagesQuery>())
|
|
@@ -109,40 +124,10 @@ pub async fn get_email(id: String) -> String {
|
|
}
|
|
}
|
|
|
|
|
|
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()
|
|
|
|
- .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(),
|
|
|
|
- };
|
|
|
|
|
|
+ let threads = Indexes::get_threads().unwrap();
|
|
|
|
+ let messages = Indexes::get_messages().unwrap();
|
|
|
|
|
|
if let Some(thread) = threads.into_iter().find(|thread| thread.id == id) {
|
|
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()
|
|
let result_messages: Vec<SerializableMessage> = thread.messages.into_iter()
|
|
.filter_map(|message_id| {
|
|
.filter_map(|message_id| {
|
|
messages.iter().find(|message| message.id == message_id).cloned()
|
|
messages.iter().find(|message| message.id == message_id).cloned()
|
|
@@ -155,6 +140,36 @@ pub async fn get_thread_messages(id: u32) -> String {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+pub async fn get_thread(id: u32) -> String {
|
|
|
|
+ let threads = Indexes::get_threads().unwrap();
|
|
|
|
+ let messages = Indexes::get_messages().unwrap();
|
|
|
|
+
|
|
|
|
+ let mut get_thread_response: GetThreadResponse = GetThreadResponse::new();
|
|
|
|
+
|
|
|
|
+ if let Some(thread) = threads.into_iter().find(|thread| thread.id == id) {
|
|
|
|
+ get_thread_response.id = thread.id.clone();
|
|
|
|
+ get_thread_response.messages = thread.messages.clone();
|
|
|
|
+
|
|
|
|
+ if let Some(first_message_id) = thread.messages.first(){
|
|
|
|
+ if let Some(first_message) = messages.clone().into_iter().find(|message| message.id == *first_message_id){
|
|
|
|
+ get_thread_response.subject = first_message.subject.clone();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if let Some(last_message_id) = thread.messages.last(){
|
|
|
|
+ if let Some(last_message) = messages.clone().into_iter().find(|message| message.id == *last_message_id){
|
|
|
|
+ get_thread_response.date = last_message.date.clone();
|
|
|
|
+ get_thread_response.from_name = last_message.name.clone();
|
|
|
|
+ get_thread_response.from_address = last_message.from.clone();
|
|
|
|
+ get_thread_response.to = last_message.to.clone();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ serde_json::to_string(&get_thread_response).unwrap()
|
|
|
|
+ } else {
|
|
|
|
+ serde_json::to_string(&GetThreadResponse::new()).unwrap()
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
async fn get_threads(folder: String, file_name: String) -> String {
|
|
async fn get_threads(folder: String, file_name: String) -> String {
|
|
let path = Config::global()
|
|
let path = Config::global()
|
|
.out_dir
|
|
.out_dir
|
|
@@ -211,6 +226,40 @@ async fn get_email_handle(query: GetEmailQuery) -> Result<impl warp::Reply, warp
|
|
Ok(warp::reply::html(result))
|
|
Ok(warp::reply::html(result))
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#[derive(Deserialize)]
|
|
|
|
+struct GetThreadQuery {
|
|
|
|
+ id: u32,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[derive(Serialize, Deserialize)]
|
|
|
|
+struct GetThreadResponse{
|
|
|
|
+ pub id: u32,
|
|
|
|
+ pub messages: Vec<String>,
|
|
|
|
+ pub subject: String,
|
|
|
|
+ pub date: DateTime<Utc>,
|
|
|
|
+ pub from_name: String,
|
|
|
|
+ pub from_address: String,
|
|
|
|
+ pub to: Vec<MailAddress>,
|
|
|
|
+}
|
|
|
|
+impl GetThreadResponse{
|
|
|
|
+ pub fn new() -> Self{
|
|
|
|
+ GetThreadResponse{
|
|
|
|
+ id: 0,
|
|
|
|
+ messages: vec![],
|
|
|
|
+ subject: "".to_string(),
|
|
|
|
+ date: Default::default(),
|
|
|
|
+ from_name: "".to_string(),
|
|
|
|
+ from_address: "".to_string(),
|
|
|
|
+ to: vec![],
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+async fn get_thread_handle(query: GetThreadQuery) -> Result<impl warp::Reply, warp::Rejection> {
|
|
|
|
+ let result: GetThreadResponse = serde_json::from_str(&*get_thread(query.id).await).unwrap();
|
|
|
|
+ Ok(warp::reply::json(&result))
|
|
|
|
+}
|
|
|
|
+
|
|
#[derive(Deserialize)]
|
|
#[derive(Deserialize)]
|
|
struct GetThreadMessagesQuery {
|
|
struct GetThreadMessagesQuery {
|
|
id: u32,
|
|
id: u32,
|