server: add mutation to mark messages as read
This commit is contained in:
parent
81ed3a8ca2
commit
5451dd2056
@ -2,7 +2,7 @@
|
||||
extern crate rocket;
|
||||
use std::{error::Error, io::Cursor, str::FromStr};
|
||||
|
||||
use async_graphql::{http::GraphiQLSource, EmptyMutation, EmptySubscription, Schema};
|
||||
use async_graphql::{http::GraphiQLSource, EmptySubscription, Schema};
|
||||
use async_graphql_rocket::{GraphQLQuery, GraphQLRequest, GraphQLResponse};
|
||||
use glog::Flags;
|
||||
use notmuch::{Notmuch, NotmuchError, ThreadSet};
|
||||
@ -16,7 +16,7 @@ use rocket::{
|
||||
use rocket_cors::{AllowedHeaders, AllowedOrigins};
|
||||
use server::{
|
||||
error::ServerError,
|
||||
graphql::{GraphqlSchema, QueryRoot},
|
||||
graphql::{GraphqlSchema, Mutation, QueryRoot},
|
||||
};
|
||||
|
||||
#[get("/refresh")]
|
||||
@ -182,7 +182,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
.to_cors()?;
|
||||
|
||||
let schema = Schema::build(QueryRoot, EmptyMutation, EmptySubscription)
|
||||
let schema = Schema::build(QueryRoot, Mutation, EmptySubscription)
|
||||
.data(Notmuch::default())
|
||||
.extension(async_graphql::extensions::Logger)
|
||||
.finish();
|
||||
|
||||
@ -7,8 +7,7 @@ use std::{
|
||||
|
||||
use async_graphql::{
|
||||
connection::{self, Connection, Edge},
|
||||
Context, EmptyMutation, EmptySubscription, Enum, Error, FieldResult, Object, Schema,
|
||||
SimpleObject, Union,
|
||||
Context, EmptySubscription, Enum, Error, FieldResult, Object, Schema, SimpleObject, Union,
|
||||
};
|
||||
use log::{error, info, warn};
|
||||
use mailparse::{parse_mail, MailHeader, MailHeaderMap, ParsedMail};
|
||||
@ -18,8 +17,6 @@ use rocket::time::Instant;
|
||||
|
||||
use crate::{linkify_html, sanitize_html};
|
||||
|
||||
pub struct QueryRoot;
|
||||
|
||||
/// # Number of seconds since the Epoch
|
||||
pub type UnixTime = isize;
|
||||
|
||||
@ -44,6 +41,7 @@ pub struct ThreadSummary {
|
||||
|
||||
#[derive(Debug, SimpleObject)]
|
||||
pub struct Thread {
|
||||
thread_id: String,
|
||||
subject: String,
|
||||
messages: Vec<Message>,
|
||||
}
|
||||
@ -192,6 +190,7 @@ struct Tag {
|
||||
unread: usize,
|
||||
}
|
||||
|
||||
pub struct QueryRoot;
|
||||
#[Object]
|
||||
impl QueryRoot {
|
||||
async fn count<'ctx>(&self, ctx: &Context<'ctx>, query: String) -> Result<usize, Error> {
|
||||
@ -316,13 +315,8 @@ impl QueryRoot {
|
||||
.exists();
|
||||
let mut messages = Vec::new();
|
||||
for (path, id) in std::iter::zip(nm.files(&thread_id)?, nm.message_ids(&thread_id)?) {
|
||||
info!("{id}\nfile: {path}");
|
||||
let msg = nm.show(&format!("id:{id}"))?;
|
||||
let tags = msg.0[0].0[0]
|
||||
.0
|
||||
.as_ref()
|
||||
.map(|m| m.tags.clone())
|
||||
.unwrap_or_else(Vec::default);
|
||||
let tags = nm.tags_for_query(&format!("id:{id}"))?;
|
||||
info!("{id}: {tags:?}\nfile: {path}");
|
||||
let file = File::open(&path)?;
|
||||
let mmap = unsafe { MmapOptions::new().map(&file)? };
|
||||
let m = parse_mail(&mmap)?;
|
||||
@ -401,7 +395,31 @@ impl QueryRoot {
|
||||
.next()
|
||||
.and_then(|m| m.subject.clone())
|
||||
.unwrap_or("(NO SUBJECT)".to_string());
|
||||
Ok(Thread { subject, messages })
|
||||
Ok(Thread {
|
||||
thread_id,
|
||||
subject,
|
||||
messages,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mutation;
|
||||
#[Object]
|
||||
impl Mutation {
|
||||
async fn set_read_status<'ctx>(
|
||||
&self,
|
||||
ctx: &Context<'ctx>,
|
||||
query: String,
|
||||
unread: bool,
|
||||
) -> Result<bool, Error> {
|
||||
let nm = ctx.data_unchecked::<Notmuch>();
|
||||
info!("set_read_status({unread})");
|
||||
if unread {
|
||||
nm.tag_add("unread", &format!("{query}"))?;
|
||||
} else {
|
||||
nm.tag_remove("unread", &format!("{query}"))?;
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -587,7 +605,7 @@ fn render_content_type_tree(m: &ParsedMail) -> String {
|
||||
render_rec(m, 1)
|
||||
}
|
||||
|
||||
pub type GraphqlSchema = Schema<QueryRoot, EmptyMutation, EmptySubscription>;
|
||||
pub type GraphqlSchema = Schema<QueryRoot, Mutation, EmptySubscription>;
|
||||
|
||||
fn email_addresses(path: &str, m: &ParsedMail, header_name: &str) -> Result<Vec<Email>, Error> {
|
||||
let mut addrs = Vec::new();
|
||||
|
||||
@ -19,7 +19,7 @@ pub enum SanitizeError {
|
||||
|
||||
pub fn linkify_html(text: &str) -> String {
|
||||
let mut finder = LinkFinder::new();
|
||||
finder.url_must_have_scheme(false);
|
||||
let finder = finder.url_must_have_scheme(false).kinds(&[LinkKind::Url]);
|
||||
let mut parts = Vec::new();
|
||||
for span in finder.spans(text) {
|
||||
// TODO(wathiede): use Cow<str>?
|
||||
@ -35,7 +35,6 @@ pub fn linkify_html(text: &str) -> String {
|
||||
"http://"
|
||||
};
|
||||
let a = format!(r#"<a href="{schema}{0}">{0}</a>"#, text);
|
||||
log::info!("link {} {a}", span.as_str());
|
||||
parts.push(a);
|
||||
}
|
||||
_ => todo!("unhandled kind: {:?}", span.kind().unwrap()),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user