This commit is contained in:
Stefan Schwarz 2020-05-03 16:51:20 +02:00
parent 867a2c8ebf
commit e99de57edc
24 changed files with 11772 additions and 187 deletions

View file

@ -9,6 +9,7 @@ use ammonia;
use async_std::sync::{Arc, Mutex};
use mailparse::body::Body;
use notmuch;
use percent_encoding;
use serde::Serialize;
#[derive(Clone)]
@ -33,9 +34,13 @@ async fn main() -> std::io::Result<()> {
App::new()
.data(data.clone())
.route("/", web::get().to(index))
.route("/autocomplete/{kind}", web::get().to(autocomplete))
.route("/autocomplete/{kind}/", web::get().to(autocomplete))
.route("/autocomplete/{kind}/{query}", web::get().to(autocomplete))
.route("/search/{query}", web::get().to(search))
.route("/search/{query}/", web::get().to(search))
.route("/search/{query}/{start}", web::get().to(search))
.route("/search/{query}/{start}/", web::get().to(search))
.route("/search/{query}/{start}/{count}", web::get().to(search))
.route("/thread/{thread_id}", web::get().to(thread))
.route("/message/{message_id}", web::get().to(message))
@ -76,7 +81,7 @@ impl From<Vec<String>> for AutocompleteResults {
async fn autocomplete(data: web::Data<Data>, req: HttpRequest) -> impl Responder {
let kind = Autocomplete::from(req.match_info().get("kind").unwrap());
let query = req.match_info().get("query").unwrap(); // TODO: use
let query = req.match_info().get("query").unwrap_or(""); // TODO: use
let mut results = HashSet::new();
let db = data.db.lock().await;
match kind {
@ -89,7 +94,7 @@ async fn autocomplete(data: web::Data<Data>, req: HttpRequest) -> impl Responder
.take(1000)
.for_each(|msg| {
msg.tags().for_each(|tag| {
results.insert(tag);
results.insert(format!("tag:{}", tag));
})
}),
Autocomplete::From => db
@ -209,7 +214,9 @@ struct ThreadSpec {
impl From<&notmuch::Thread<'_, '_>> for ThreadSpec {
fn from(thread: &notmuch::Thread) -> Self {
let t = Thread::from(thread);
let message_ids = thread.messages().map(|msg| msg.id().to_string()).collect();
let mut message_ids: Vec<String> =
thread.messages().map(|msg| msg.id().to_string()).collect();
message_ids.reverse();
ThreadSpec {
thread_id: t.thread_id,
count: t.count,
@ -237,6 +244,7 @@ struct Message {
bcc: String,
date: i64,
subject: String,
tags: Vec<String>,
body: String,
attachments: Vec<String>,
}
@ -274,14 +282,16 @@ where
_ => panic!("unsupported body"),
};
//let body = ammonia::clean(&body);
let body = ammonia::Builder::new()
let mut body = ammonia::Builder::new()
.attribute_filter(|tag, attr, val| match (tag, attr) {
("img", "src") => None,
_ => Some(val.into()),
})
.clean(&body)
.to_string();
let body = format!("<div style=\"white-space: pre-wrap\">{}</div>", body);
if mail.ctype.mimetype != "text/html" {
body = format!("<div style=\"white-space: pre-wrap\">{}</div>", body);
}
Message {
from: message.header("from").unwrap().unwrap().to_string(),
to: message.header("to").unwrap().unwrap().to_string(),
@ -297,6 +307,7 @@ where
.to_string(),
date: message.date(),
subject: message.header("subject").unwrap().unwrap().to_string(),
tags: message.tags().collect(),
body: body,
attachments: Vec::new(),
}
@ -305,14 +316,13 @@ where
async fn message(data: web::Data<Data>, req: HttpRequest) -> impl Responder {
let message_id = req.match_info().get("message_id").unwrap();
println!("mid:{}", message_id);
let message_id = percent_encoding::percent_decode_str(&message_id).decode_utf8_lossy();
let db = data.db.lock().await;
let query = db.create_query(&format!("mid:{}", message_id)).unwrap();
let message = query.search_messages().unwrap().next().unwrap();
//HttpResponse::Ok().json(Message::from(&message))
HttpResponse::Ok()
.content_type("text/html;charset=utf-8")
.body(Message::from(&message).body)
.json(Message::from(&message))
}
async fn index() -> impl Responder {