web & server: implement handling for text and html bodies.
This commit is contained in:
parent
1cdabc348b
commit
11366b6fac
@ -6,6 +6,7 @@ use std::{
|
|||||||
use async_graphql::{
|
use async_graphql::{
|
||||||
connection::{self, Connection, Edge},
|
connection::{self, Connection, Edge},
|
||||||
Context, EmptyMutation, EmptySubscription, Error, FieldResult, Object, Schema, SimpleObject,
|
Context, EmptyMutation, EmptySubscription, Error, FieldResult, Object, Schema, SimpleObject,
|
||||||
|
Union,
|
||||||
};
|
};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use mailparse::{parse_mail, MailHeaderMap, ParsedMail};
|
use mailparse::{parse_mail, MailHeaderMap, ParsedMail};
|
||||||
@ -55,6 +56,51 @@ pub struct Message {
|
|||||||
pub subject: Option<String>,
|
pub subject: Option<String>,
|
||||||
// Parsed Date header, if found and valid
|
// Parsed Date header, if found and valid
|
||||||
pub timestamp: Option<i64>,
|
pub timestamp: Option<i64>,
|
||||||
|
// The body contents
|
||||||
|
pub body: Body,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct UnhandledContentType {
|
||||||
|
text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Object]
|
||||||
|
impl UnhandledContentType {
|
||||||
|
async fn contents(&self) -> &str {
|
||||||
|
&self.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct PlainText {
|
||||||
|
text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Object]
|
||||||
|
impl PlainText {
|
||||||
|
async fn contents(&self) -> &str {
|
||||||
|
&self.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Html {
|
||||||
|
html: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Object]
|
||||||
|
impl Html {
|
||||||
|
async fn contents(&self) -> &str {
|
||||||
|
&self.html
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Union)]
|
||||||
|
pub enum Body {
|
||||||
|
UnhandledContentType(UnhandledContentType),
|
||||||
|
PlainText(PlainText),
|
||||||
|
Html(Html),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, SimpleObject)]
|
#[derive(Debug, SimpleObject)]
|
||||||
@ -195,12 +241,23 @@ impl QueryRoot {
|
|||||||
.headers
|
.headers
|
||||||
.get_first_value("date")
|
.get_first_value("date")
|
||||||
.and_then(|d| mailparse::dateparse(&d).ok());
|
.and_then(|d| mailparse::dateparse(&d).ok());
|
||||||
|
let body = m.get_body()?;
|
||||||
|
let body = match m.ctype.mimetype.as_str() {
|
||||||
|
"text/plain" => Body::PlainText(PlainText { text: body }),
|
||||||
|
"text/html" => Body::Html(Html { html: body }),
|
||||||
|
_ => {
|
||||||
|
let msg = format!("Unhandled body content type: {}", m.ctype.mimetype);
|
||||||
|
warn!("{}", msg);
|
||||||
|
Body::UnhandledContentType(UnhandledContentType { text: msg })
|
||||||
|
}
|
||||||
|
};
|
||||||
messages.push(Message {
|
messages.push(Message {
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
cc,
|
cc,
|
||||||
subject,
|
subject,
|
||||||
timestamp,
|
timestamp,
|
||||||
|
body,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
messages.reverse();
|
messages.reverse();
|
||||||
|
|||||||
@ -59,6 +59,32 @@
|
|||||||
},
|
},
|
||||||
"subscriptionType": null,
|
"subscriptionType": null,
|
||||||
"types": [
|
"types": [
|
||||||
|
{
|
||||||
|
"description": null,
|
||||||
|
"enumValues": null,
|
||||||
|
"fields": null,
|
||||||
|
"inputFields": null,
|
||||||
|
"interfaces": null,
|
||||||
|
"kind": "UNION",
|
||||||
|
"name": "Body",
|
||||||
|
"possibleTypes": [
|
||||||
|
{
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "UnhandledContentType",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "PlainText",
|
||||||
|
"ofType": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "Html",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "The `Boolean` scalar type represents `true` or `false`.",
|
"description": "The `Boolean` scalar type represents `true` or `false`.",
|
||||||
"enumValues": null,
|
"enumValues": null,
|
||||||
@ -114,6 +140,33 @@
|
|||||||
"name": "Float",
|
"name": "Float",
|
||||||
"possibleTypes": null
|
"possibleTypes": null
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": null,
|
||||||
|
"enumValues": null,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"args": [],
|
||||||
|
"deprecationReason": null,
|
||||||
|
"description": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"name": "contents",
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputFields": null,
|
||||||
|
"interfaces": [],
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "Html",
|
||||||
|
"possibleTypes": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": null,
|
"description": null,
|
||||||
"enumValues": null,
|
"enumValues": null,
|
||||||
@ -221,6 +274,22 @@
|
|||||||
"name": "Int",
|
"name": "Int",
|
||||||
"ofType": null
|
"ofType": null
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"args": [],
|
||||||
|
"deprecationReason": null,
|
||||||
|
"description": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"name": "body",
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "UNION",
|
||||||
|
"name": "Body",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"inputFields": null,
|
"inputFields": null,
|
||||||
@ -296,6 +365,33 @@
|
|||||||
"name": "PageInfo",
|
"name": "PageInfo",
|
||||||
"possibleTypes": null
|
"possibleTypes": null
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": null,
|
||||||
|
"enumValues": null,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"args": [],
|
||||||
|
"deprecationReason": null,
|
||||||
|
"description": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"name": "contents",
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputFields": null,
|
||||||
|
"interfaces": [],
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "PlainText",
|
||||||
|
"possibleTypes": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": null,
|
"description": null,
|
||||||
"enumValues": null,
|
"enumValues": null,
|
||||||
@ -865,6 +961,33 @@
|
|||||||
"name": "ThreadSummaryEdge",
|
"name": "ThreadSummaryEdge",
|
||||||
"possibleTypes": null
|
"possibleTypes": null
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": null,
|
||||||
|
"enumValues": null,
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"args": [],
|
||||||
|
"deprecationReason": null,
|
||||||
|
"description": null,
|
||||||
|
"isDeprecated": false,
|
||||||
|
"name": "contents",
|
||||||
|
"type": {
|
||||||
|
"kind": "NON_NULL",
|
||||||
|
"name": null,
|
||||||
|
"ofType": {
|
||||||
|
"kind": "SCALAR",
|
||||||
|
"name": "String",
|
||||||
|
"ofType": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"inputFields": null,
|
||||||
|
"interfaces": [],
|
||||||
|
"kind": "OBJECT",
|
||||||
|
"name": "UnhandledContentType",
|
||||||
|
"possibleTypes": null
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "A Directive provides a way to describe alternate runtime execution and type\nvalidation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution\nbehavior in ways field arguments will not suffice, such as conditionally\nincluding or skipping a field. Directives provide this by describing\nadditional information to the executor.",
|
"description": "A Directive provides a way to describe alternate runtime execution and type\nvalidation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution\nbehavior in ways field arguments will not suffice, such as conditionally\nincluding or skipping a field. Directives provide this by describing\nadditional information to the executor.",
|
||||||
"enumValues": null,
|
"enumValues": null,
|
||||||
|
|||||||
@ -16,6 +16,18 @@ query ShowThreadQuery($threadId: String!) {
|
|||||||
addr
|
addr
|
||||||
}
|
}
|
||||||
timestamp
|
timestamp
|
||||||
|
body {
|
||||||
|
__typename
|
||||||
|
... on UnhandledContentType {
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
... on PlainText {
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
... on Html {
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tags {
|
tags {
|
||||||
|
|||||||
@ -1054,15 +1054,20 @@ fn view_thread(thread: &ShowThreadQueryThread) -> Node<Msg> {
|
|||||||
.map(|ts| div![C!["header"], "Date: ", human_age(ts)]),
|
.map(|ts| div![C!["header"], "Date: ", human_age(ts)]),
|
||||||
IF!(!msg.to.is_empty() => div![C!["header"], "To: ", view_addresses(&msg.to)]),
|
IF!(!msg.to.is_empty() => div![C!["header"], "To: ", view_addresses(&msg.to)]),
|
||||||
IF!(!msg.cc.is_empty() => div![C!["header"], "CC: ", view_addresses(&msg.cc)]),
|
IF!(!msg.cc.is_empty() => div![C!["header"], "CC: ", view_addresses(&msg.cc)]),
|
||||||
/*
|
|
||||||
div![
|
div![
|
||||||
C!["body"],
|
C!["body"],
|
||||||
match &message.body {
|
match &msg.body {
|
||||||
Some(body) => view_body(body.as_slice()),
|
ShowThreadQueryThreadMessagesBody::UnhandledContentType(
|
||||||
None => div!["<no body>"],
|
ShowThreadQueryThreadMessagesBodyOnUnhandledContentType { contents },
|
||||||
},
|
) => div![C!["error"], contents],
|
||||||
|
ShowThreadQueryThreadMessagesBody::PlainText(
|
||||||
|
ShowThreadQueryThreadMessagesBodyOnPlainText { contents },
|
||||||
|
) => div![C!["view-part-text-plain"], contents],
|
||||||
|
ShowThreadQueryThreadMessagesBody::Html(
|
||||||
|
ShowThreadQueryThreadMessagesBodyOnHtml { contents },
|
||||||
|
) => div![C!["view-part-text-html"], raw![contents]],
|
||||||
|
}
|
||||||
],
|
],
|
||||||
*/
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
div![
|
div![
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user