Implementation of all JMAP Mail methods.

main
Mauro D 2022-05-10 15:22:13 +00:00
parent cd74566ca3
commit 17cecbdb63
27 changed files with 2501 additions and 99 deletions

View File

@ -15,7 +15,7 @@ pub struct CopyBlobRequest {
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct CopyBlobResponse<U> { pub struct CopyBlobResponse {
#[serde(rename = "fromAccountId")] #[serde(rename = "fromAccountId")]
from_account_id: String, from_account_id: String,
#[serde(rename = "accountId")] #[serde(rename = "accountId")]
@ -23,5 +23,48 @@ pub struct CopyBlobResponse<U> {
#[serde(rename = "copied")] #[serde(rename = "copied")]
copied: Option<HashMap<String, String>>, copied: Option<HashMap<String, String>>,
#[serde(rename = "notCopied")] #[serde(rename = "notCopied")]
not_copied: Option<HashMap<String, SetError<U>>>, not_copied: Option<HashMap<String, SetError<String>>>,
}
impl CopyBlobRequest {
pub fn new(from_account_id: String, account_id: String) -> Self {
CopyBlobRequest {
from_account_id,
account_id,
blob_ids: vec![],
}
}
pub fn blob_id(&mut self, blob_id: String) -> &mut Self {
self.blob_ids.push(blob_id);
self
}
}
impl CopyBlobResponse {
pub fn from_account_id(&self) -> &str {
&self.from_account_id
}
pub fn account_id(&self) -> &str {
&self.account_id
}
pub fn copied(&self) -> Option<impl Iterator<Item = &String>> {
self.copied.as_ref().map(|map| map.keys())
}
pub fn copied_details(&self, id: &str) -> Option<&str> {
self.copied
.as_ref()
.and_then(|map| map.get(id).map(|s| s.as_str()))
}
pub fn not_copied(&self) -> Option<impl Iterator<Item = &String>> {
self.not_copied.as_ref().map(|map| map.keys())
}
pub fn not_copied_reason(&self, id: &str) -> Option<&SetError<String>> {
self.not_copied.as_ref().and_then(|map| map.get(id))
}
} }

61
src/client.rs Normal file
View File

@ -0,0 +1,61 @@
use std::time::Duration;
use crate::core::request::Request;
const DEFAULT_TIMEOUT_MS: u64 = 10 * 1000;
pub struct Client {
client: reqwest::ClientBuilder,
default_account_id: String,
}
impl Client {
pub fn connect(url: &str) -> Self {
Client {
client: reqwest::Client::builder().timeout(Duration::from_millis(DEFAULT_TIMEOUT_MS)),
default_account_id: "co".to_string(),
}
}
pub fn default_account_id(&self) -> &str {
&self.default_account_id
}
pub fn request(&self) -> Request<'_> {
Request::new(self)
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_serialize() {
/*let mut client = Client::connect("coco");
client.request().email_set().create(
"coco",
Email::new()
.from(["Pepe"])
.subject("Hello world!")
.sent_at(342374),
);*/
/*let query: QueryRequest<EmailFilter, EmailComparator, email::QueryArguments> =
QueryRequest::new("coco".to_string())
.filter(Filter::or([
Filter::and([
EmailFilter::in_mailbox("peperino"),
EmailFilter::in_mailbox_other_than(["coco", "miel"]),
EmailFilter::from("comoro"),
]),
Filter::not([EmailFilter::after(428374234)]),
]))
.sort([
EmailComparator::has_keyword("cocomiel"),
EmailComparator::size(),
]);
println!("{}", serde_json::to_string_pretty(&query).unwrap());*/
}
}

View File

@ -11,7 +11,7 @@ pub struct ChangesRequest {
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct ChangesResponse { pub struct ChangesResponse<A> {
#[serde(rename = "accountId")] #[serde(rename = "accountId")]
account_id: String, account_id: String,
#[serde(rename = "oldState")] #[serde(rename = "oldState")]
@ -23,4 +23,61 @@ pub struct ChangesResponse {
created: Vec<String>, created: Vec<String>,
updated: Vec<String>, updated: Vec<String>,
destroyed: Vec<String>, destroyed: Vec<String>,
#[serde(flatten)]
arguments: A,
}
impl ChangesRequest {
pub fn new(account_id: String, since_state: String) -> Self {
ChangesRequest {
account_id,
since_state,
max_changes: None,
}
}
pub fn account_id(&mut self, account_id: impl Into<String>) -> &mut Self {
self.account_id = account_id.into();
self
}
pub fn max_changes(&mut self, max_changes: usize) -> &mut Self {
self.max_changes = Some(max_changes);
self
}
}
impl<A> ChangesResponse<A> {
pub fn account_id(&self) -> &str {
&self.account_id
}
pub fn old_state(&self) -> &str {
&self.old_state
}
pub fn new_state(&self) -> &str {
&self.new_state
}
pub fn has_more_changes(&self) -> bool {
self.has_more_changes
}
pub fn created(&self) -> &[String] {
&self.created
}
pub fn updated(&self) -> &[String] {
&self.updated
}
pub fn destroyed(&self) -> &[String] {
&self.destroyed
}
pub fn arguments(&self) -> &A {
&self.arguments
}
} }

View File

@ -8,16 +8,22 @@ use super::set::SetError;
pub struct CopyRequest<T> { pub struct CopyRequest<T> {
#[serde(rename = "fromAccountId")] #[serde(rename = "fromAccountId")]
from_account_id: String, from_account_id: String,
#[serde(rename = "ifFromInState")] #[serde(rename = "ifFromInState")]
if_from_in_state: Option<String>, if_from_in_state: Option<String>,
#[serde(rename = "accountId")] #[serde(rename = "accountId")]
account_id: String, account_id: String,
#[serde(rename = "ifInState")] #[serde(rename = "ifInState")]
if_in_state: Option<String>, if_in_state: Option<String>,
#[serde(rename = "create")] #[serde(rename = "create")]
create: HashMap<String, T>, create: HashMap<String, T>,
#[serde(rename = "onSuccessDestroyOriginal")] #[serde(rename = "onSuccessDestroyOriginal")]
on_success_destroy_original: bool, on_success_destroy_original: bool,
#[serde(rename = "destroyFromIfInState")] #[serde(rename = "destroyFromIfInState")]
destroy_from_if_in_state: Option<String>, destroy_from_if_in_state: Option<String>,
} }
@ -37,3 +43,78 @@ pub struct CopyResponse<T, U> {
#[serde(rename = "notCreated")] #[serde(rename = "notCreated")]
not_created: Option<HashMap<String, SetError<U>>>, not_created: Option<HashMap<String, SetError<U>>>,
} }
impl<T> CopyRequest<T> {
pub fn new(from_account_id: String, account_id: String) -> Self {
CopyRequest {
from_account_id,
if_from_in_state: None,
account_id,
if_in_state: None,
create: HashMap::new(),
on_success_destroy_original: false,
destroy_from_if_in_state: None,
}
}
pub fn account_id(&mut self, account_id: impl Into<String>) -> &mut Self {
self.account_id = account_id.into();
self
}
pub fn if_from_in_state(&mut self, if_from_in_state: impl Into<String>) -> &mut Self {
self.if_from_in_state = Some(if_from_in_state.into());
self
}
pub fn if_in_state(&mut self, if_in_state: impl Into<String>) -> &mut Self {
self.if_in_state = Some(if_in_state.into());
self
}
pub fn create(&mut self, id: impl Into<String>, value: T) -> &mut Self {
self.create.insert(id.into(), value);
self
}
pub fn on_success_destroy_original(&mut self, on_success_destroy_original: bool) -> &mut Self {
self.on_success_destroy_original = on_success_destroy_original;
self
}
pub fn destroy_from_if_in_state(
&mut self,
destroy_from_if_in_state: impl Into<String>,
) -> &mut Self {
self.destroy_from_if_in_state = Some(destroy_from_if_in_state.into());
self
}
}
impl<T, U> CopyResponse<T, U> {
pub fn from_account_id(&self) -> &str {
&self.from_account_id
}
pub fn account_id(&self) -> &str {
&self.account_id
}
pub fn old_state(&self) -> Option<&str> {
self.old_state.as_deref()
}
pub fn new_state(&self) -> &str {
&self.new_state
}
pub fn created(&self, id: &str) -> Option<&T> {
self.created.as_ref().and_then(|created| created.get(id))
}
pub fn not_created(&self, id: &str) -> Option<&SetError<U>> {
self.not_created
.as_ref()
.and_then(|not_created| not_created.get(id))
}
}

View File

@ -1,4 +1,4 @@
use serde::{Deserialize, Serialize}; use serde::Deserialize;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct ProblemDetails { pub struct ProblemDetails {
@ -71,3 +71,31 @@ pub enum MethodErrorType {
#[serde(rename = "tooManyChanges")] #[serde(rename = "tooManyChanges")]
TooManyChanges, TooManyChanges,
} }
impl ProblemDetails {
pub fn error(&self) -> &ProblemType {
&self.p_type
}
pub fn status(&self) -> Option<u32> {
self.status
}
pub fn title(&self) -> Option<&str> {
self.title.as_deref()
}
pub fn detail(&self) -> Option<&str> {
self.detail.as_deref()
}
pub fn limit(&self) -> Option<usize> {
self.limit
}
}
impl MethodError {
pub fn error(&self) -> &MethodErrorType {
&self.p_type
}
}

View File

@ -1,11 +1,14 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct GetRequest<T> { pub struct GetRequest<T, A: Default> {
#[serde(rename = "accountId")] #[serde(rename = "accountId")]
account_id: String, account_id: String,
ids: Option<Vec<String>>, ids: Option<Vec<String>>,
properties: Option<Vec<T>>, properties: Option<Vec<T>>,
#[serde(flatten)]
arguments: A,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -17,3 +20,63 @@ pub struct GetResponse<T> {
#[serde(rename = "notFound")] #[serde(rename = "notFound")]
not_found: Vec<String>, not_found: Vec<String>,
} }
impl<T, A: Default> GetRequest<T, A> {
pub fn new(account_id: String) -> Self {
GetRequest {
account_id,
ids: None,
properties: None,
arguments: A::default(),
}
}
pub fn account_id(&mut self, account_id: impl Into<String>) -> &mut Self {
self.account_id = account_id.into();
self
}
pub fn ids<U, V>(&mut self, ids: U) -> &mut Self
where
U: IntoIterator<Item = V>,
V: Into<String>,
{
self.ids = Some(ids.into_iter().map(|v| v.into()).collect());
self
}
pub fn properties(&mut self, properties: impl IntoIterator<Item = T>) -> &mut Self {
self.properties = Some(properties.into_iter().collect());
self
}
pub fn arguments(&mut self) -> &mut A {
&mut self.arguments
}
}
impl<T> GetResponse<T> {
pub fn account_id(&self) -> &str {
&self.account_id
}
pub fn state(&self) -> &str {
&self.state
}
pub fn list(&self) -> &[T] {
&self.list
}
pub fn not_found(&self) -> &[String] {
&self.not_found
}
pub fn unwrap_list(&mut self) -> Vec<T> {
std::mem::take(&mut self.list)
}
pub fn unwrap_not_found(&mut self) -> Vec<String> {
std::mem::take(&mut self.not_found)
}
}

View File

@ -1,23 +1,33 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct QueryRequest<T, U> { pub struct QueryRequest<F, S, A: Default> {
#[serde(rename = "accountId")] #[serde(rename = "accountId")]
account_id: String, account_id: String,
#[serde(rename = "filter")] #[serde(rename = "filter")]
filter: Option<Filter<T>>, filter: Option<Filter<F>>,
#[serde(rename = "sort")] #[serde(rename = "sort")]
sort: Option<Vec<U>>, sort: Option<Vec<Comparator<S>>>,
#[serde(rename = "position")] #[serde(rename = "position")]
position: i32, position: i32,
#[serde(rename = "anchor")] #[serde(rename = "anchor")]
anchor: Option<String>, anchor: Option<String>,
#[serde(rename = "anchorOffset")] #[serde(rename = "anchorOffset")]
anchor_offset: i32, anchor_offset: i32,
#[serde(rename = "limit")] #[serde(rename = "limit")]
limit: Option<usize>, limit: Option<usize>,
#[serde(rename = "calculateTotal")] #[serde(rename = "calculateTotal")]
calculate_total: bool, calculate_total: bool,
#[serde(flatten)]
arguments: A,
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
@ -44,27 +54,189 @@ pub enum Operator {
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct Comparator<T> { pub struct Comparator<A> {
property: T,
#[serde(rename = "isAscending")] #[serde(rename = "isAscending")]
is_ascending: bool, is_ascending: bool,
#[serde(skip_serializing_if = "Option::is_none")]
collation: Option<String>, collation: Option<String>,
#[serde(flatten)]
arguments: A,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct QueryResponse { pub struct QueryResponse {
#[serde(rename = "accountId")] #[serde(rename = "accountId")]
account_id: String, account_id: String,
#[serde(rename = "queryState")] #[serde(rename = "queryState")]
query_state: String, query_state: String,
#[serde(rename = "canCalculateChanges")] #[serde(rename = "canCalculateChanges")]
can_calculate_changes: bool, can_calculate_changes: bool,
#[serde(rename = "position")] #[serde(rename = "position")]
position: i32, position: i32,
#[serde(rename = "ids")] #[serde(rename = "ids")]
ids: Vec<String>, ids: Vec<String>,
#[serde(rename = "total")] #[serde(rename = "total")]
total: Option<usize>, total: Option<usize>,
#[serde(rename = "limit")] #[serde(rename = "limit")]
limit: Option<usize>, limit: Option<usize>,
} }
impl<F, S, A: Default> QueryRequest<F, S, A> {
pub fn new(account_id: String) -> Self {
QueryRequest {
account_id,
filter: None,
sort: None,
position: 0,
anchor: None,
anchor_offset: 0,
limit: None,
calculate_total: false,
arguments: A::default(),
}
}
pub fn account_id(&mut self, account_id: impl Into<String>) -> &mut Self {
self.account_id = account_id.into();
self
}
pub fn filter(&mut self, filter: impl Into<Filter<F>>) -> &mut Self {
self.filter = Some(filter.into());
self
}
pub fn sort(&mut self, sort: impl IntoIterator<Item = Comparator<S>>) -> &mut Self {
self.sort = Some(sort.into_iter().collect());
self
}
pub fn position(&mut self, position: i32) -> &mut Self {
self.position = position;
self
}
pub fn anchor(&mut self, anchor: impl Into<String>) -> &mut Self {
self.anchor = Some(anchor.into());
self
}
pub fn anchor_offset(&mut self, anchor_offset: i32) -> &mut Self {
self.anchor_offset = anchor_offset;
self
}
pub fn limit(&mut self, limit: usize) -> &mut Self {
self.limit = Some(limit);
self
}
pub fn arguments(&mut self) -> &mut A {
&mut self.arguments
}
}
impl QueryResponse {
pub fn account_id(&self) -> &str {
&self.account_id
}
pub fn ids(&self) -> &[String] {
&self.ids
}
pub fn total(&self) -> Option<usize> {
self.total
}
pub fn limit(&self) -> Option<usize> {
self.limit
}
pub fn position(&self) -> i32 {
self.position
}
pub fn query_state(&self) -> &str {
&self.query_state
}
pub fn can_calculate_changes(&self) -> bool {
self.can_calculate_changes
}
}
impl<A> Comparator<A> {
pub fn new(arguments: A) -> Self {
Comparator {
is_ascending: true,
collation: None,
arguments,
}
}
pub fn is_ascending(mut self, is_ascending: bool) -> Self {
self.is_ascending = is_ascending;
self
}
pub fn collation(mut self, collation: String) -> Self {
self.collation = Some(collation);
self
}
}
impl<T> From<FilterOperator<T>> for Filter<T> {
fn from(filter: FilterOperator<T>) -> Self {
Filter::FilterOperator(filter)
}
}
impl<T> From<T> for Filter<T> {
fn from(filter: T) -> Self {
Filter::FilterCondition(filter)
}
}
impl<T> Filter<T> {
pub fn and<U, V>(conditions: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<Filter<T>>,
{
Filter::FilterOperator(FilterOperator {
operator: Operator::And,
conditions: conditions.into_iter().map(|t| t.into()).collect(),
})
}
pub fn or<U, V>(conditions: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<Filter<T>>,
{
Filter::FilterOperator(FilterOperator {
operator: Operator::Or,
conditions: conditions.into_iter().map(|t| t.into()).collect(),
})
}
pub fn not<U, V>(conditions: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<Filter<T>>,
{
Filter::FilterOperator(FilterOperator {
operator: Operator::Not,
conditions: conditions.into_iter().map(|t| t.into()).collect(),
})
}
}

View File

@ -1,15 +1,15 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::query::Filter; use super::query::{Comparator, Filter};
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct QueryChangesRequest<T, U> { pub struct QueryChangesRequest<F, S, A: Default> {
#[serde(rename = "accountId")] #[serde(rename = "accountId")]
account_id: String, account_id: String,
#[serde(rename = "filter")] #[serde(rename = "filter")]
filter: Option<Filter<T>>, filter: Option<Filter<F>>,
#[serde(rename = "sort")] #[serde(rename = "sort")]
sort: Option<Vec<U>>, sort: Option<Vec<Comparator<S>>>,
#[serde(rename = "sinceQueryState")] #[serde(rename = "sinceQueryState")]
since_query_state: String, since_query_state: String,
#[serde(rename = "maxChanges")] #[serde(rename = "maxChanges")]
@ -18,6 +18,9 @@ pub struct QueryChangesRequest<T, U> {
up_to_id: Option<String>, up_to_id: Option<String>,
#[serde(rename = "calculateTotal")] #[serde(rename = "calculateTotal")]
calculate_total: bool, calculate_total: bool,
#[serde(flatten)]
arguments: A,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -41,3 +44,88 @@ pub struct AddedItem {
id: String, id: String,
index: usize, index: usize,
} }
impl<F, S, A: Default> QueryChangesRequest<F, S, A> {
pub fn new(account_id: String, since_query_state: String) -> Self {
QueryChangesRequest {
account_id,
filter: None,
sort: None,
since_query_state,
max_changes: None,
up_to_id: None,
calculate_total: false,
arguments: A::default(),
}
}
pub fn account_id(&mut self, account_id: impl Into<String>) -> &mut Self {
self.account_id = account_id.into();
self
}
pub fn filter(&mut self, filter: impl Into<Filter<F>>) -> &mut Self {
self.filter = Some(filter.into());
self
}
pub fn sort(&mut self, sort: impl IntoIterator<Item = Comparator<S>>) -> &mut Self {
self.sort = Some(sort.into_iter().collect());
self
}
pub fn max_changes(&mut self, max_changes: usize) -> &mut Self {
self.max_changes = Some(max_changes);
self
}
pub fn up_to_id(&mut self, up_to_id: impl Into<String>) -> &mut Self {
self.up_to_id = Some(up_to_id.into());
self
}
pub fn calculate_total(&mut self, calculate_total: bool) -> &mut Self {
self.calculate_total = calculate_total;
self
}
pub fn arguments(&mut self) -> &mut A {
&mut self.arguments
}
}
impl QueryChangesResponse {
pub fn account_id(&self) -> &str {
&self.account_id
}
pub fn old_query_state(&self) -> &str {
&self.old_query_state
}
pub fn new_query_state(&self) -> &str {
&self.new_query_state
}
pub fn total(&self) -> Option<usize> {
self.total
}
pub fn removed(&self) -> &[String] {
&self.removed
}
pub fn added(&self) -> &[AddedItem] {
&self.added
}
}
impl AddedItem {
pub fn id(&self) -> &str {
&self.id
}
pub fn index(&self) -> usize {
self.index
}
}

View File

@ -2,10 +2,29 @@ use std::collections::HashMap;
use serde::Serialize; use serde::Serialize;
use crate::{Method, URI}; use crate::{
blob::copy::CopyBlobRequest,
client::Client,
email::{self, import::EmailImportRequest, parse::EmailParseRequest, Email},
email_submission::{self, EmailSubmission},
identity::{self, Identity},
mailbox::{self, Mailbox},
push_subscription::{self, PushSubscription},
thread,
vacation_response::{self, VacationResponse},
Method, Set, URI,
};
use super::{
changes::ChangesRequest, copy::CopyRequest, get::GetRequest, query::QueryRequest,
query_changes::QueryChangesRequest, set::SetRequest,
};
#[derive(Serialize)]
pub struct Request<'x> {
#[serde(skip)]
client: &'x Client,
#[derive(Debug, Clone, Serialize)]
pub struct Request {
using: Vec<URI>, using: Vec<URI>,
#[serde(rename = "methodCalls")] #[serde(rename = "methodCalls")]
method_calls: Vec<(Method, Arguments, String)>, method_calls: Vec<(Method, Arguments, String)>,
@ -23,4 +42,650 @@ pub struct ResultReference {
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct Arguments {} #[serde(untagged)]
pub enum Arguments {
Changes(ChangesRequest),
PushGet(GetRequest<push_subscription::Property, ()>),
PushSet(SetRequest<PushSubscription<Set>, ()>),
BlobCopy(CopyBlobRequest),
MailboxGet(GetRequest<mailbox::Property, ()>),
MailboxQuery(
QueryRequest<mailbox::query::Filter, mailbox::query::Comparator, mailbox::QueryArguments>,
),
MailboxQueryChanges(
QueryChangesRequest<
mailbox::query::Filter,
mailbox::query::Comparator,
mailbox::QueryArguments,
>,
),
MailboxSet(SetRequest<Mailbox<Set>, mailbox::SetArguments>),
ThreadGet(GetRequest<thread::Property, ()>),
EmailGet(GetRequest<email::Property, email::GetArguments>),
EmailQuery(QueryRequest<email::query::Filter, email::query::Comparator, email::QueryArguments>),
EmailQueryChanges(
QueryChangesRequest<email::query::Filter, email::query::Comparator, email::QueryArguments>,
),
EmailSet(SetRequest<Email<Set>, ()>),
EmailCopy(CopyRequest<Email<Set>>),
EmailImport(EmailImportRequest),
EmailParse(EmailParseRequest),
IdentityGet(GetRequest<identity::Property, ()>),
IdentitySet(SetRequest<Identity<Set>, ()>),
EmailSubmissionGet(GetRequest<email_submission::Property, ()>),
EmailSubmissionQuery(
QueryRequest<email_submission::query::Filter, email_submission::query::Comparator, ()>,
),
EmailSubmissionQueryChanges(
QueryChangesRequest<
email_submission::query::Filter,
email_submission::query::Comparator,
(),
>,
),
EmailSubmissionSet(SetRequest<EmailSubmission<Set>, email_submission::SetArguments>),
VacationResponseGet(GetRequest<vacation_response::Property, ()>),
VacationResponseSet(SetRequest<VacationResponse<Set>, ()>),
}
impl Arguments {
pub fn changes(account_id: String, since_state: String) -> Self {
Arguments::Changes(ChangesRequest::new(account_id, since_state))
}
pub fn push_get(account_id: String) -> Self {
Arguments::PushGet(GetRequest::new(account_id))
}
pub fn push_set(account_id: String) -> Self {
Arguments::PushSet(SetRequest::new(account_id))
}
pub fn blob_copy(from_account_id: String, account_id: String) -> Self {
Arguments::BlobCopy(CopyBlobRequest::new(from_account_id, account_id))
}
pub fn mailbox_get(account_id: String) -> Self {
Arguments::MailboxGet(GetRequest::new(account_id))
}
pub fn mailbox_query(account_id: String) -> Self {
Arguments::MailboxQuery(QueryRequest::new(account_id))
}
pub fn mailbox_query_changes(account_id: String, since_query_state: String) -> Self {
Arguments::MailboxQueryChanges(QueryChangesRequest::new(account_id, since_query_state))
}
pub fn mailbox_set(account_id: String) -> Self {
Arguments::MailboxSet(SetRequest::new(account_id))
}
pub fn thread_get(account_id: String) -> Self {
Arguments::ThreadGet(GetRequest::new(account_id))
}
pub fn email_get(account_id: String) -> Self {
Arguments::EmailGet(GetRequest::new(account_id))
}
pub fn email_query(account_id: String) -> Self {
Arguments::EmailQuery(QueryRequest::new(account_id))
}
pub fn email_query_changes(account_id: String, since_query_state: String) -> Self {
Arguments::EmailQueryChanges(QueryChangesRequest::new(account_id, since_query_state))
}
pub fn email_set(account_id: String) -> Self {
Arguments::EmailSet(SetRequest::new(account_id))
}
pub fn email_copy(from_account_id: String, account_id: String) -> Self {
Arguments::EmailCopy(CopyRequest::new(from_account_id, account_id))
}
pub fn email_import(account_id: String) -> Self {
Arguments::EmailImport(EmailImportRequest::new(account_id))
}
pub fn email_parse(account_id: String) -> Self {
Arguments::EmailParse(EmailParseRequest::new(account_id))
}
pub fn identity_get(account_id: String) -> Self {
Arguments::IdentityGet(GetRequest::new(account_id))
}
pub fn identity_set(account_id: String) -> Self {
Arguments::IdentitySet(SetRequest::new(account_id))
}
pub fn email_submission_get(account_id: String) -> Self {
Arguments::EmailSubmissionGet(GetRequest::new(account_id))
}
pub fn email_submission_query(account_id: String) -> Self {
Arguments::EmailSubmissionQuery(QueryRequest::new(account_id))
}
pub fn email_submission_query_changes(account_id: String, since_query_state: String) -> Self {
Arguments::EmailSubmissionQueryChanges(QueryChangesRequest::new(
account_id,
since_query_state,
))
}
pub fn email_submission_set(account_id: String) -> Self {
Arguments::EmailSubmissionSet(SetRequest::new(account_id))
}
pub fn vacation_response_get(account_id: String) -> Self {
Arguments::VacationResponseGet(GetRequest::new(account_id))
}
pub fn vacation_response_set(account_id: String) -> Self {
Arguments::VacationResponseSet(SetRequest::new(account_id))
}
pub fn changes_mut(&mut self) -> &mut ChangesRequest {
match self {
Arguments::Changes(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn push_get_mut(&mut self) -> &mut GetRequest<push_subscription::Property, ()> {
match self {
Arguments::PushGet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn push_set_mut(&mut self) -> &mut SetRequest<PushSubscription<Set>, ()> {
match self {
Arguments::PushSet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn blob_copy_mut(&mut self) -> &mut CopyBlobRequest {
match self {
Arguments::BlobCopy(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn mailbox_get_mut(&mut self) -> &mut GetRequest<mailbox::Property, ()> {
match self {
Arguments::MailboxGet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn mailbox_query_mut(
&mut self,
) -> &mut QueryRequest<
mailbox::query::Filter,
mailbox::query::Comparator,
mailbox::QueryArguments,
> {
match self {
Arguments::MailboxQuery(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn mailbox_query_changes_mut(
&mut self,
) -> &mut QueryChangesRequest<
mailbox::query::Filter,
mailbox::query::Comparator,
mailbox::QueryArguments,
> {
match self {
Arguments::MailboxQueryChanges(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn mailbox_set_mut(&mut self) -> &mut SetRequest<Mailbox<Set>, mailbox::SetArguments> {
match self {
Arguments::MailboxSet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn thread_get_mut(&mut self) -> &mut GetRequest<thread::Property, ()> {
match self {
Arguments::ThreadGet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_get_mut(&mut self) -> &mut GetRequest<email::Property, email::GetArguments> {
match self {
Arguments::EmailGet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_query_mut(
&mut self,
) -> &mut QueryRequest<email::query::Filter, email::query::Comparator, email::QueryArguments>
{
match self {
Arguments::EmailQuery(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_query_changes_mut(
&mut self,
) -> &mut QueryChangesRequest<
email::query::Filter,
email::query::Comparator,
email::QueryArguments,
> {
match self {
Arguments::EmailQueryChanges(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_set_mut(&mut self) -> &mut SetRequest<Email<Set>, ()> {
match self {
Arguments::EmailSet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_copy_mut(&mut self) -> &mut CopyRequest<Email<Set>> {
match self {
Arguments::EmailCopy(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_import_mut(&mut self) -> &mut EmailImportRequest {
match self {
Arguments::EmailImport(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_parse_mut(&mut self) -> &mut EmailParseRequest {
match self {
Arguments::EmailParse(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn identity_get_mut(&mut self) -> &mut GetRequest<identity::Property, ()> {
match self {
Arguments::IdentityGet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn identity_set_mut(&mut self) -> &mut SetRequest<Identity<Set>, ()> {
match self {
Arguments::IdentitySet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_submission_get_mut(&mut self) -> &mut GetRequest<email_submission::Property, ()> {
match self {
Arguments::EmailSubmissionGet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_submission_query_mut(
&mut self,
) -> &mut QueryRequest<email_submission::query::Filter, email_submission::query::Comparator, ()>
{
match self {
Arguments::EmailSubmissionQuery(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_submission_query_changes_mut(
&mut self,
) -> &mut QueryChangesRequest<
email_submission::query::Filter,
email_submission::query::Comparator,
(),
> {
match self {
Arguments::EmailSubmissionQueryChanges(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn email_submission_set_mut(
&mut self,
) -> &mut SetRequest<EmailSubmission<Set>, email_submission::SetArguments> {
match self {
Arguments::EmailSubmissionSet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn vacation_response_get_mut(
&mut self,
) -> &mut GetRequest<vacation_response::Property, ()> {
match self {
Arguments::VacationResponseGet(ref mut r) => r,
_ => unreachable!(),
}
}
pub fn vacation_response_set_mut(&mut self) -> &mut SetRequest<VacationResponse<Set>, ()> {
match self {
Arguments::VacationResponseSet(ref mut r) => r,
_ => unreachable!(),
}
}
}
impl<'x> Request<'x> {
pub fn new(client: &'x Client) -> Self {
Request {
using: vec![URI::Core, URI::Mail],
method_calls: vec![],
created_ids: None,
client,
}
}
fn add_method_call(&mut self, method: Method, arguments: Arguments) -> &mut Arguments {
let call_id = format!("s{}", self.method_calls.len());
self.method_calls.push((method, arguments, call_id));
&mut self.method_calls.last_mut().unwrap().1
}
pub fn get_push(&mut self) -> &mut GetRequest<push_subscription::Property, ()> {
self.add_method_call(
Method::GetPushSubscription,
Arguments::push_get(self.client.default_account_id().to_string()),
)
.push_get_mut()
}
pub fn set_push(&mut self) -> &mut SetRequest<PushSubscription<Set>, ()> {
self.add_method_call(
Method::SetPushSubscription,
Arguments::push_set(self.client.default_account_id().to_string()),
)
.push_set_mut()
}
pub fn copy_blob(
&mut self,
from_account_id: impl Into<String>,
account_id: impl Into<String>,
) -> &mut CopyBlobRequest {
self.add_method_call(
Method::CopyBlob,
Arguments::blob_copy(from_account_id.into(), account_id.into()),
)
.blob_copy_mut()
}
pub fn get_mailbox(&mut self) -> &mut GetRequest<mailbox::Property, ()> {
self.add_method_call(
Method::GetMailbox,
Arguments::mailbox_get(self.client.default_account_id().to_string()),
)
.mailbox_get_mut()
}
pub fn changes_mailbox(&mut self, since_state: impl Into<String>) -> &mut ChangesRequest {
self.add_method_call(
Method::ChangesMailbox,
Arguments::changes(
self.client.default_account_id().to_string(),
since_state.into(),
),
)
.changes_mut()
}
pub fn query_mailbox(
&mut self,
) -> &mut QueryRequest<
mailbox::query::Filter,
mailbox::query::Comparator,
mailbox::QueryArguments,
> {
self.add_method_call(
Method::QueryMailbox,
Arguments::mailbox_query(self.client.default_account_id().to_string()),
)
.mailbox_query_mut()
}
pub fn query_mailbox_changes(
&mut self,
since_query_state: impl Into<String>,
) -> &mut QueryChangesRequest<
mailbox::query::Filter,
mailbox::query::Comparator,
mailbox::QueryArguments,
> {
self.add_method_call(
Method::QueryChangesMailbox,
Arguments::mailbox_query_changes(
self.client.default_account_id().to_string(),
since_query_state.into(),
),
)
.mailbox_query_changes_mut()
}
pub fn set_mailbox(&mut self) -> &mut SetRequest<Mailbox<Set>, mailbox::SetArguments> {
self.add_method_call(
Method::SetMailbox,
Arguments::mailbox_set(self.client.default_account_id().to_string()),
)
.mailbox_set_mut()
}
pub fn get_thread(&mut self) -> &mut GetRequest<thread::Property, ()> {
self.add_method_call(
Method::GetThread,
Arguments::thread_get(self.client.default_account_id().to_string()),
)
.thread_get_mut()
}
pub fn changes_thread(&mut self, since_state: impl Into<String>) -> &mut ChangesRequest {
self.add_method_call(
Method::ChangesThread,
Arguments::changes(
self.client.default_account_id().to_string(),
since_state.into(),
),
)
.changes_mut()
}
pub fn get_email(&mut self) -> &mut GetRequest<email::Property, email::GetArguments> {
self.add_method_call(
Method::GetEmail,
Arguments::email_get(self.client.default_account_id().to_string()),
)
.email_get_mut()
}
pub fn changes_email(&mut self, since_state: impl Into<String>) -> &mut ChangesRequest {
self.add_method_call(
Method::ChangesEmail,
Arguments::changes(
self.client.default_account_id().to_string(),
since_state.into(),
),
)
.changes_mut()
}
pub fn query_email(
&mut self,
) -> &mut QueryRequest<email::query::Filter, email::query::Comparator, email::QueryArguments>
{
self.add_method_call(
Method::QueryEmail,
Arguments::email_query(self.client.default_account_id().to_string()),
)
.email_query_mut()
}
pub fn query_email_changes(
&mut self,
since_query_state: impl Into<String>,
) -> &mut QueryChangesRequest<
email::query::Filter,
email::query::Comparator,
email::QueryArguments,
> {
self.add_method_call(
Method::QueryChangesEmail,
Arguments::email_query_changes(
self.client.default_account_id().to_string(),
since_query_state.into(),
),
)
.email_query_changes_mut()
}
pub fn set_email(&mut self) -> &mut SetRequest<Email<Set>, ()> {
self.add_method_call(
Method::SetEmail,
Arguments::email_set(self.client.default_account_id().to_string()),
)
.email_set_mut()
}
pub fn copy_email(
&mut self,
from_account_id: impl Into<String>,
account_id: impl Into<String>,
) -> &mut CopyRequest<Email<Set>> {
self.add_method_call(
Method::CopyEmail,
Arguments::email_copy(from_account_id.into(), account_id.into()),
)
.email_copy_mut()
}
pub fn import_email(&mut self) -> &mut EmailImportRequest {
self.add_method_call(
Method::ImportEmail,
Arguments::email_import(self.client.default_account_id().to_string()),
)
.email_import_mut()
}
pub fn parse_email(&mut self) -> &mut EmailParseRequest {
self.add_method_call(
Method::ParseEmail,
Arguments::email_parse(self.client.default_account_id().to_string()),
)
.email_parse_mut()
}
pub fn get_identity(&mut self) -> &mut GetRequest<identity::Property, ()> {
self.add_method_call(
Method::GetIdentity,
Arguments::identity_get(self.client.default_account_id().to_string()),
)
.identity_get_mut()
}
pub fn set_identity(&mut self) -> &mut SetRequest<Identity<Set>, ()> {
self.add_method_call(
Method::SetIdentity,
Arguments::identity_set(self.client.default_account_id().to_string()),
)
.identity_set_mut()
}
pub fn get_email_submission(&mut self) -> &mut GetRequest<email_submission::Property, ()> {
self.add_method_call(
Method::GetEmailSubmission,
Arguments::email_submission_get(self.client.default_account_id().to_string()),
)
.email_submission_get_mut()
}
pub fn changes_email_submission(
&mut self,
since_state: impl Into<String>,
) -> &mut ChangesRequest {
self.add_method_call(
Method::ChangesEmailSubmission,
Arguments::changes(
self.client.default_account_id().to_string(),
since_state.into(),
),
)
.changes_mut()
}
pub fn query_email_submission(
&mut self,
) -> &mut QueryRequest<email_submission::query::Filter, email_submission::query::Comparator, ()>
{
self.add_method_call(
Method::QueryEmailSubmission,
Arguments::email_submission_query(self.client.default_account_id().to_string()),
)
.email_submission_query_mut()
}
pub fn query_email_submission_changes(
&mut self,
since_query_state: impl Into<String>,
) -> &mut QueryChangesRequest<
email_submission::query::Filter,
email_submission::query::Comparator,
(),
> {
self.add_method_call(
Method::QueryChangesEmailSubmission,
Arguments::email_submission_query_changes(
self.client.default_account_id().to_string(),
since_query_state.into(),
),
)
.email_submission_query_changes_mut()
}
pub fn set_email_submission(
&mut self,
) -> &mut SetRequest<EmailSubmission<Set>, email_submission::SetArguments> {
self.add_method_call(
Method::SetEmailSubmission,
Arguments::email_submission_set(self.client.default_account_id().to_string()),
)
.email_submission_set_mut()
}
pub fn get_vacation_response(&mut self) -> &mut GetRequest<vacation_response::Property, ()> {
self.add_method_call(
Method::GetVacationResponse,
Arguments::vacation_response_get(self.client.default_account_id().to_string()),
)
.vacation_response_get_mut()
}
pub fn set_vacation_response(&mut self) -> &mut SetRequest<VacationResponse<Set>, ()> {
self.add_method_call(
Method::SetVacationResponse,
Arguments::vacation_response_set(self.client.default_account_id().to_string()),
)
.vacation_response_set_mut()
}
}

View File

@ -5,7 +5,7 @@ use serde::Deserialize;
use crate::Method; use crate::Method;
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct Request { pub struct Response {
#[serde(rename = "methodResponses")] #[serde(rename = "methodResponses")]
method_calls: Vec<(Method, Result, String)>, method_calls: Vec<(Method, Result, String)>,
#[serde(rename = "createdIds")] #[serde(rename = "createdIds")]

View File

@ -2,24 +2,34 @@ use std::collections::HashMap;
use serde::Deserialize; use serde::Deserialize;
use crate::email::{MailCapabilities, SubmissionCapabilities};
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct Session { pub struct Session {
#[serde(rename = "capabilities")] #[serde(rename = "capabilities")]
capabilities: HashMap<String, Capabilities>, capabilities: HashMap<String, Capabilities>,
#[serde(rename = "accounts")] #[serde(rename = "accounts")]
accounts: HashMap<String, Account>, accounts: HashMap<String, Account>,
#[serde(rename = "primaryAccounts")] #[serde(rename = "primaryAccounts")]
primary_accounts: HashMap<String, String>, primary_accounts: HashMap<String, String>,
#[serde(rename = "username")] #[serde(rename = "username")]
username: String, username: String,
#[serde(rename = "apiUrl")] #[serde(rename = "apiUrl")]
api_url: String, api_url: String,
#[serde(rename = "downloadUrl")] #[serde(rename = "downloadUrl")]
download_url: String, download_url: String,
#[serde(rename = "uploadUrl")] #[serde(rename = "uploadUrl")]
upload_url: String, upload_url: String,
#[serde(rename = "eventSourceUrl")] #[serde(rename = "eventSourceUrl")]
event_source_url: String, event_source_url: String,
#[serde(rename = "state")] #[serde(rename = "state")]
state: String, state: String,
} }
@ -28,21 +38,24 @@ pub struct Session {
pub struct Account { pub struct Account {
#[serde(rename = "name")] #[serde(rename = "name")]
name: String, name: String,
#[serde(rename = "isPersonal")] #[serde(rename = "isPersonal")]
is_personal: bool, is_personal: bool,
#[serde(rename = "isReadOnly")] #[serde(rename = "isReadOnly")]
is_read_only: bool, is_read_only: bool,
#[serde(rename = "accountCapabilities")] #[serde(rename = "accountCapabilities")]
account_capabilities: HashMap<String, Capabilities>, account_capabilities: HashMap<String, Capabilities>,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
enum Capabilities { pub enum Capabilities {
Core(CoreCapabilities), Core(CoreCapabilities),
Mail(MailCapabilities), Mail(MailCapabilities),
Submission(SubmissionCapabilities), Submission(SubmissionCapabilities),
EmptyCapabilities(EmptyCapabilities), Empty(EmptyCapabilities),
Other(serde_json::Value), Other(serde_json::Value),
} }
@ -50,45 +63,134 @@ enum Capabilities {
pub struct CoreCapabilities { pub struct CoreCapabilities {
#[serde(rename = "maxSizeUpload")] #[serde(rename = "maxSizeUpload")]
max_size_upload: usize, max_size_upload: usize,
#[serde(rename = "maxConcurrentUpload")] #[serde(rename = "maxConcurrentUpload")]
max_concurrent_upload: usize, max_concurrent_upload: usize,
#[serde(rename = "maxSizeRequest")] #[serde(rename = "maxSizeRequest")]
max_size_request: usize, max_size_request: usize,
#[serde(rename = "maxConcurrentRequests")] #[serde(rename = "maxConcurrentRequests")]
max_concurrent_requests: usize, max_concurrent_requests: usize,
#[serde(rename = "maxCallsInRequest")] #[serde(rename = "maxCallsInRequest")]
max_calls_in_request: usize, max_calls_in_request: usize,
#[serde(rename = "maxObjectsInGet")] #[serde(rename = "maxObjectsInGet")]
max_objects_in_get: usize, max_objects_in_get: usize,
#[serde(rename = "maxObjectsInSet")] #[serde(rename = "maxObjectsInSet")]
max_objects_in_set: usize, max_objects_in_set: usize,
#[serde(rename = "collationAlgorithms")] #[serde(rename = "collationAlgorithms")]
collation_algorithms: Vec<String>, collation_algorithms: Vec<String>,
} }
#[derive(Debug, Clone, Deserialize)]
pub struct MailCapabilities {
#[serde(rename = "maxMailboxesPerEmail")]
max_mailboxes_per_email: Option<usize>,
#[serde(rename = "maxMailboxDepth")]
max_mailbox_depth: usize,
#[serde(rename = "maxSizeMailboxName")]
max_size_mailbox_name: usize,
#[serde(rename = "maxSizeAttachmentsPerEmail")]
max_size_attachments_per_email: usize,
#[serde(rename = "emailQuerySortOptions")]
email_query_sort_options: Vec<String>,
#[serde(rename = "mayCreateTopLevelMailbox")]
may_create_top_level_mailbox: bool,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SubmissionCapabilities {
#[serde(rename = "maxDelayedSend")]
max_delayed_send: usize,
#[serde(rename = "submissionExtensions")]
submission_extensions: Vec<String>,
}
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct EmptyCapabilities {} pub struct EmptyCapabilities {}
impl Session {
pub fn capabilities(&self) -> impl Iterator<Item = &String> {
self.capabilities.keys()
}
pub fn capability(&self, capability: &str) -> Option<&Capabilities> {
self.capabilities.get(capability)
}
pub fn accounts(&self) -> impl Iterator<Item = &String> {
self.accounts.keys()
}
pub fn account(&self, account: &str) -> Option<&Account> {
self.accounts.get(account)
}
pub fn primary_accounts(&self) -> impl Iterator<Item = &String> {
self.primary_accounts.keys()
}
pub fn primary_account(&self, account: &str) -> Option<&String> {
self.primary_accounts.get(account)
}
pub fn username(&self) -> &str {
&self.username
}
pub fn api_url(&self) -> &str {
&self.api_url
}
pub fn download_url(&self) -> &str {
&self.download_url
}
pub fn upload_url(&self) -> &str {
&self.upload_url
}
pub fn event_source_url(&self) -> &str {
&self.event_source_url
}
pub fn state(&self) -> &str {
&self.state
}
}
impl Account {
pub fn name(&self) -> &str {
&self.name
}
pub fn is_personal(&self) -> bool {
self.is_personal
}
pub fn is_read_only(&self) -> bool {
self.is_read_only
}
pub fn capabilities(&self) -> impl Iterator<Item = &String> {
self.account_capabilities.keys()
}
pub fn capability(&self, capability: &str) -> Option<&Capabilities> {
self.account_capabilities.get(capability)
}
}
impl CoreCapabilities {
pub fn max_size_upload(&self) -> usize {
self.max_size_upload
}
pub fn max_concurrent_upload(&self) -> usize {
self.max_concurrent_upload
}
pub fn max_size_request(&self) -> usize {
self.max_size_request
}
pub fn max_concurrent_requests(&self) -> usize {
self.max_concurrent_requests
}
pub fn max_calls_in_request(&self) -> usize {
self.max_calls_in_request
}
pub fn max_objects_in_get(&self) -> usize {
self.max_objects_in_get
}
pub fn max_objects_in_set(&self) -> usize {
self.max_objects_in_set
}
pub fn collation_algorithms(&self) -> &[String] {
&self.collation_algorithms
}
}

View File

@ -1,20 +1,19 @@
use chrono::{DateTime, NaiveDateTime, Utc}; use chrono::{DateTime, NaiveDateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::Hash;
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct SetRequest<T, U> pub struct SetRequest<T, A: Default> {
where
U: Eq + Hash,
{
#[serde(rename = "accountId")] #[serde(rename = "accountId")]
account_id: String, account_id: String,
#[serde(rename = "ifInState")] #[serde(rename = "ifInState")]
if_in_state: Option<String>, if_in_state: Option<String>,
create: Option<HashMap<String, T>>, create: Option<HashMap<String, T>>,
update: Option<HashMap<String, HashMap<U, serde_json::Value>>>, update: Option<HashMap<String, T>>,
destroy: Option<Vec<String>>, destroy: Option<Vec<String>>,
#[serde(flatten)]
arguments: A,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -110,3 +109,121 @@ pub fn date_not_set(date: &Option<DateTime<Utc>>) -> bool {
pub fn list_not_set<T>(list: &Option<Vec<T>>) -> bool { pub fn list_not_set<T>(list: &Option<Vec<T>>) -> bool {
matches!(list, Some(list) if list.is_empty() ) matches!(list, Some(list) if list.is_empty() )
} }
impl<T, A: Default> SetRequest<T, A> {
pub fn new(account_id: String) -> Self {
Self {
account_id,
if_in_state: None,
create: None,
update: None,
destroy: None,
arguments: Default::default(),
}
}
pub fn account_id(&mut self, account_id: impl Into<String>) -> &mut Self {
self.account_id = account_id.into();
self
}
pub fn if_in_state(&mut self, if_in_state: impl Into<String>) -> &mut Self {
self.if_in_state = Some(if_in_state.into());
self
}
pub fn create(&mut self, id: impl Into<String>, value: T) -> &mut Self {
self.create
.get_or_insert_with(HashMap::new)
.insert(id.into(), value);
self
}
pub fn update(&mut self, id: impl Into<String>, value: T) -> &mut Self {
self.update
.get_or_insert_with(HashMap::new)
.insert(id.into(), value);
self
}
pub fn destroy(&mut self, id: impl Into<String>) -> &mut Self {
self.destroy.get_or_insert_with(Vec::new).push(id.into());
self
}
pub fn arguments(&mut self) -> &mut A {
&mut self.arguments
}
}
impl<T, U> SetResponse<T, U> {
pub fn account_id(&self) -> &str {
&self.account_id
}
pub fn old_state(&self) -> Option<&str> {
self.old_state.as_deref()
}
pub fn new_state(&self) -> &str {
&self.new_state
}
pub fn created(&self) -> Option<impl Iterator<Item = &String>> {
self.created.as_ref().map(|map| map.keys())
}
pub fn updated(&self) -> Option<impl Iterator<Item = &String>> {
self.updated.as_ref().map(|map| map.keys())
}
pub fn destroyed(&self) -> Option<&[String]> {
self.destroyed.as_deref()
}
pub fn not_created(&self) -> Option<impl Iterator<Item = &String>> {
self.not_created.as_ref().map(|map| map.keys())
}
pub fn not_updated(&self) -> Option<impl Iterator<Item = &String>> {
self.not_updated.as_ref().map(|map| map.keys())
}
pub fn not_destroyed(&self) -> Option<impl Iterator<Item = &String>> {
self.not_destroyed.as_ref().map(|map| map.keys())
}
pub fn not_created_reason(&self, id: &str) -> Option<&SetError<U>> {
self.not_created.as_ref().and_then(|map| map.get(id))
}
pub fn not_updated_reason(&self, id: &str) -> Option<&SetError<U>> {
self.not_updated.as_ref().and_then(|map| map.get(id))
}
pub fn not_destroyed_reason(&self, id: &str) -> Option<&SetError<U>> {
self.not_destroyed.as_ref().and_then(|map| map.get(id))
}
pub fn created_details(&self, id: &str) -> Option<&T> {
self.created.as_ref().and_then(|map| map.get(id))
}
pub fn updated_details(&self, id: &str) -> Option<&T> {
self.updated.as_ref().and_then(|map| map.get(id))?.as_ref()
}
}
impl<U> SetError<U> {
pub fn error(&self) -> &SetErrorType {
&self.type_
}
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
pub fn properties(&self) -> Option<&[U]> {
self.properties.as_deref()
}
}

124
src/email/import.rs Normal file
View File

@ -0,0 +1,124 @@
use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::core::set::{from_timestamp, SetError};
use super::{Email, Property};
#[derive(Debug, Clone, Serialize)]
pub struct EmailImportRequest {
#[serde(rename = "accountId")]
account_id: String,
#[serde(rename = "ifInState")]
if_in_state: Option<String>,
emails: HashMap<String, EmailImport>,
}
#[derive(Debug, Clone, Serialize)]
pub struct EmailImport {
#[serde(rename = "blobId")]
blob_id: String,
#[serde(rename = "mailboxIds")]
mailbox_ids: HashMap<String, bool>,
#[serde(rename = "keywords")]
keywords: HashMap<String, bool>,
#[serde(rename = "receivedAt")]
#[serde(skip_serializing_if = "Option::is_none")]
received_at: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct EmailImportResponse {
#[serde(rename = "accountId")]
account_id: String,
#[serde(rename = "oldState")]
old_state: Option<String>,
#[serde(rename = "newState")]
new_state: String,
#[serde(rename = "created")]
created: Option<HashMap<String, Email>>,
#[serde(rename = "notCreated")]
not_created: Option<HashMap<String, SetError<Property>>>,
}
impl EmailImportRequest {
pub fn new(account_id: String) -> Self {
EmailImportRequest {
account_id,
if_in_state: None,
emails: HashMap::new(),
}
}
pub fn if_in_state(&mut self, if_in_state: String) -> &mut Self {
self.if_in_state = Some(if_in_state);
self
}
pub fn add_email(&mut self, id: String, email_import: EmailImport) -> &mut Self {
self.emails.insert(id, email_import);
self
}
}
impl EmailImport {
pub fn new(blob_id: String) -> Self {
EmailImport {
blob_id,
mailbox_ids: HashMap::new(),
keywords: HashMap::new(),
received_at: None,
}
}
pub fn mailbox_id(mut self, mailbox_id: String) -> Self {
self.mailbox_ids.insert(mailbox_id, true);
self
}
pub fn keyword(mut self, keyword: String) -> Self {
self.keywords.insert(keyword, true);
self
}
pub fn received_at(mut self, received_at: i64) -> Self {
self.received_at = Some(from_timestamp(received_at));
self
}
}
impl EmailImportResponse {
pub fn account_id(&self) -> &str {
&self.account_id
}
pub fn old_state(&self) -> Option<&str> {
self.old_state.as_deref()
}
pub fn new_state(&self) -> &str {
&self.new_state
}
pub fn created(&self) -> Option<impl Iterator<Item = &String>> {
self.created.as_ref().map(|map| map.keys())
}
pub fn not_created(&self) -> Option<impl Iterator<Item = &String>> {
self.not_created.as_ref().map(|map| map.keys())
}
pub fn created_details(&self, id: &str) -> Option<&Email> {
self.created.as_ref().and_then(|map| map.get(id))
}
pub fn not_created_reason(&self, id: &str) -> Option<&SetError<Property>> {
self.not_created.as_ref().and_then(|map| map.get(id))
}
}

View File

@ -1,4 +1,8 @@
pub mod get; pub mod get;
pub mod import;
pub mod parse;
pub mod query;
pub mod search_snippet;
pub mod set; pub mod set;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
@ -225,7 +229,7 @@ pub struct EmailHeader<State = Get> {
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EmailProperty { pub enum Property {
#[serde(rename = "id")] #[serde(rename = "id")]
Id, Id,
#[serde(rename = "blobId")] #[serde(rename = "blobId")]
@ -279,7 +283,7 @@ pub enum EmailProperty {
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EmailBodyProperty { pub enum BodyProperty {
#[serde(rename = "partId")] #[serde(rename = "partId")]
PartId, PartId,
#[serde(rename = "blobId")] #[serde(rename = "blobId")]
@ -305,3 +309,126 @@ pub enum EmailBodyProperty {
#[serde(rename = "subParts")] #[serde(rename = "subParts")]
SubParts, SubParts,
} }
#[derive(Debug, Clone, Deserialize)]
pub struct MailCapabilities {
#[serde(rename = "maxMailboxesPerEmail")]
max_mailboxes_per_email: Option<usize>,
#[serde(rename = "maxMailboxDepth")]
max_mailbox_depth: usize,
#[serde(rename = "maxSizeMailboxName")]
max_size_mailbox_name: usize,
#[serde(rename = "maxSizeAttachmentsPerEmail")]
max_size_attachments_per_email: usize,
#[serde(rename = "emailQuerySortOptions")]
email_query_sort_options: Vec<String>,
#[serde(rename = "mayCreateTopLevelMailbox")]
may_create_top_level_mailbox: bool,
}
#[derive(Debug, Clone, Deserialize)]
pub struct SubmissionCapabilities {
#[serde(rename = "maxDelayedSend")]
max_delayed_send: usize,
#[serde(rename = "submissionExtensions")]
submission_extensions: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct QueryArguments {
#[serde(rename = "collapseThreads")]
collapse_threads: bool,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct GetArguments {
#[serde(rename = "bodyProperties")]
#[serde(skip_serializing_if = "Option::is_none")]
body_properties: Option<Vec<BodyProperty>>,
#[serde(rename = "fetchTextBodyValues")]
fetch_text_body_values: bool,
#[serde(rename = "fetchHTMLBodyValues")]
fetch_html_body_values: bool,
#[serde(rename = "fetchAllBodyValues")]
fetch_all_body_values: bool,
#[serde(rename = "maxBodyValueBytes")]
max_body_value_bytes: usize,
}
impl QueryArguments {
pub fn collapse_threads(&mut self, collapse_threads: bool) {
self.collapse_threads = collapse_threads;
}
}
impl GetArguments {
pub fn body_properties(
&mut self,
body_properties: impl IntoIterator<Item = BodyProperty>,
) -> &mut Self {
self.body_properties = Some(body_properties.into_iter().collect());
self
}
pub fn fetch_text_body_values(&mut self, fetch_text_body_values: bool) -> &mut Self {
self.fetch_text_body_values = fetch_text_body_values;
self
}
pub fn fetch_html_body_values(&mut self, fetch_html_body_values: bool) -> &mut Self {
self.fetch_html_body_values = fetch_html_body_values;
self
}
pub fn fetch_all_body_values(&mut self, fetch_all_body_values: bool) -> &mut Self {
self.fetch_all_body_values = fetch_all_body_values;
self
}
pub fn max_body_value_bytes(&mut self, max_body_value_bytes: usize) -> &mut Self {
self.max_body_value_bytes = max_body_value_bytes;
self
}
}
impl MailCapabilities {
pub fn max_mailboxes_per_email(&self) -> Option<usize> {
self.max_mailboxes_per_email
}
pub fn max_mailbox_depth(&self) -> usize {
self.max_mailbox_depth
}
pub fn max_size_mailbox_name(&self) -> usize {
self.max_size_mailbox_name
}
pub fn max_size_attachments_per_email(&self) -> usize {
self.max_size_attachments_per_email
}
pub fn email_query_sort_options(&self) -> &[String] {
&self.email_query_sort_options
}
pub fn may_create_top_level_mailbox(&self) -> bool {
self.may_create_top_level_mailbox
}
}
impl SubmissionCapabilities {
pub fn max_delayed_send(&self) -> usize {
self.max_delayed_send
}
pub fn submission_extensions(&self) -> &[String] {
&self.submission_extensions
}
}

126
src/email/parse.rs Normal file
View File

@ -0,0 +1,126 @@
use std::collections::HashMap;
use serde::Serialize;
use super::{BodyProperty, Email, Property};
#[derive(Debug, Clone, Serialize)]
pub struct EmailParseRequest {
#[serde(rename = "accountId")]
account_id: String,
#[serde(rename = "blobIds")]
blob_ids: Vec<String>,
#[serde(rename = "properties")]
properties: Vec<Property>,
#[serde(rename = "bodyProperties")]
body_properties: Vec<BodyProperty>,
#[serde(rename = "fetchTextBodyValues")]
fetch_text_body_values: bool,
#[serde(rename = "fetchHTMLBodyValues")]
fetch_html_body_values: bool,
#[serde(rename = "fetchAllBodyValues")]
fetch_all_body_values: bool,
#[serde(rename = "maxBodyValueBytes")]
max_body_value_bytes: usize,
}
#[derive(Debug, Clone, Serialize)]
pub struct EmailParseResponse {
#[serde(rename = "accountId")]
account_id: String,
#[serde(rename = "parsed")]
parsed: Option<HashMap<String, Email>>,
#[serde(rename = "notParsable")]
not_parsable: Option<Vec<String>>,
#[serde(rename = "notFound")]
not_found: Option<Vec<String>>,
}
impl EmailParseRequest {
pub fn new(account_id: String) -> Self {
EmailParseRequest {
account_id,
blob_ids: Vec::new(),
properties: Vec::new(),
body_properties: Vec::new(),
fetch_text_body_values: false,
fetch_html_body_values: false,
fetch_all_body_values: false,
max_body_value_bytes: 0,
}
}
pub fn blob_ids<U, V>(&mut self, blob_ids: U) -> &mut Self
where
U: IntoIterator<Item = V>,
V: Into<String>,
{
self.blob_ids = blob_ids.into_iter().map(|v| v.into()).collect();
self
}
pub fn properties(&mut self, properties: impl IntoIterator<Item = Property>) -> &mut Self {
self.properties = properties.into_iter().collect();
self
}
pub fn body_properties(
&mut self,
body_properties: impl IntoIterator<Item = BodyProperty>,
) -> &mut Self {
self.body_properties = body_properties.into_iter().collect();
self
}
pub fn fetch_text_body_values(&mut self, fetch_text_body_values: bool) -> &mut Self {
self.fetch_text_body_values = fetch_text_body_values;
self
}
pub fn fetch_html_body_values(&mut self, fetch_html_body_values: bool) -> &mut Self {
self.fetch_html_body_values = fetch_html_body_values;
self
}
pub fn fetch_all_body_values(&mut self, fetch_all_body_values: bool) -> &mut Self {
self.fetch_all_body_values = fetch_all_body_values;
self
}
pub fn max_body_value_bytes(&mut self, max_body_value_bytes: usize) -> &mut Self {
self.max_body_value_bytes = max_body_value_bytes;
self
}
}
impl EmailParseResponse {
pub fn account_id(&self) -> &str {
&self.account_id
}
pub fn parsed(&self) -> Option<impl Iterator<Item = &String>> {
self.parsed.as_ref().map(|map| map.keys())
}
pub fn parsed_details(&self, id: &str) -> Option<&Email> {
self.parsed.as_ref().and_then(|map| map.get(id))
}
pub fn not_parsable(&self) -> Option<&[String]> {
self.not_parsable.as_deref()
}
pub fn not_found(&self) -> Option<&[String]> {
self.not_found.as_deref()
}
}

282
src/email/query.rs Normal file
View File

@ -0,0 +1,282 @@
use chrono::{DateTime, Utc};
use serde::Serialize;
use crate::core::{query, set::from_timestamp};
#[derive(Serialize, Clone, Debug)]
#[serde(untagged)]
pub enum Filter {
InMailbox {
#[serde(rename = "inMailbox")]
value: String,
},
InMailboxOtherThan {
#[serde(rename = "inMailboxOtherThan")]
value: Vec<String>,
},
Before {
#[serde(rename = "before")]
value: DateTime<Utc>,
},
After {
#[serde(rename = "after")]
value: DateTime<Utc>,
},
MinSize {
#[serde(rename = "minSize")]
value: u32,
},
MaxSize {
#[serde(rename = "maxSize")]
value: u32,
},
AllInThreadHaveKeyword {
#[serde(rename = "allInThreadHaveKeyword")]
value: String,
},
SomeInThreadHaveKeyword {
#[serde(rename = "someInThreadHaveKeyword")]
value: String,
},
NoneInThreadHaveKeyword {
#[serde(rename = "noneInThreadHaveKeyword")]
value: String,
},
HasKeyword {
#[serde(rename = "hasKeyword")]
value: String,
},
NotKeyword {
#[serde(rename = "notKeyword")]
value: String,
},
HasAttachment {
#[serde(rename = "hasAttachment")]
value: bool,
},
Text {
#[serde(rename = "text")]
value: String,
},
From {
#[serde(rename = "from")]
value: String,
},
To {
#[serde(rename = "to")]
value: String,
},
Cc {
#[serde(rename = "cc")]
value: String,
},
Bcc {
#[serde(rename = "bcc")]
value: String,
},
Subject {
#[serde(rename = "subject")]
value: String,
},
Body {
#[serde(rename = "body")]
value: String,
},
Header {
#[serde(rename = "header")]
value: Vec<String>,
},
}
#[derive(Serialize, Debug, Clone)]
#[serde(tag = "property")]
pub enum Comparator {
#[serde(rename = "receivedAt")]
ReceivedAt,
#[serde(rename = "size")]
Size,
#[serde(rename = "from")]
From,
#[serde(rename = "to")]
To,
#[serde(rename = "subject")]
Subject,
#[serde(rename = "sentAt")]
SentAt,
#[serde(rename = "hasKeyword")]
HasKeyword { keyword: String },
#[serde(rename = "allInThreadHaveKeyword")]
AllInThreadHaveKeyword { keyword: String },
#[serde(rename = "someInThreadHaveKeyword")]
SomeInThreadHaveKeyword { keyword: String },
}
impl Filter {
pub fn in_mailbox(value: impl Into<String>) -> Self {
Filter::InMailbox {
value: value.into(),
}
}
pub fn in_mailbox_other_than<U, V>(value: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<String>,
{
Filter::InMailboxOtherThan {
value: value.into_iter().map(|v| v.into()).collect(),
}
}
pub fn before(value: i64) -> Self {
Filter::Before {
value: from_timestamp(value),
}
}
pub fn after(value: i64) -> Self {
Filter::After {
value: from_timestamp(value),
}
}
pub fn min_size(value: u32) -> Self {
Filter::MinSize { value }
}
pub fn max_size(value: u32) -> Self {
Filter::MaxSize { value }
}
pub fn all_in_thread_have_keyword(value: impl Into<String>) -> Self {
Filter::AllInThreadHaveKeyword {
value: value.into(),
}
}
pub fn some_in_thread_have_keyword(value: impl Into<String>) -> Self {
Filter::SomeInThreadHaveKeyword {
value: value.into(),
}
}
pub fn none_in_thread_have_keyword(value: impl Into<String>) -> Self {
Filter::NoneInThreadHaveKeyword {
value: value.into(),
}
}
pub fn has_keyword(value: impl Into<String>) -> Self {
Filter::HasKeyword {
value: value.into(),
}
}
pub fn not_keyword(value: impl Into<String>) -> Self {
Filter::NotKeyword {
value: value.into(),
}
}
pub fn has_attachment(value: bool) -> Self {
Filter::HasAttachment { value }
}
pub fn text(value: impl Into<String>) -> Self {
Filter::Text {
value: value.into(),
}
}
pub fn from(value: impl Into<String>) -> Self {
Filter::From {
value: value.into(),
}
}
pub fn to(value: impl Into<String>) -> Self {
Filter::To {
value: value.into(),
}
}
pub fn cc(value: impl Into<String>) -> Self {
Filter::Cc {
value: value.into(),
}
}
pub fn bcc(value: impl Into<String>) -> Self {
Filter::Bcc {
value: value.into(),
}
}
pub fn subject(value: impl Into<String>) -> Self {
Filter::Subject {
value: value.into(),
}
}
pub fn body(value: impl Into<String>) -> Self {
Filter::Body {
value: value.into(),
}
}
pub fn header<U, V>(value: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<String>,
{
Filter::Header {
value: value.into_iter().map(|v| v.into()).collect(),
}
}
}
impl Comparator {
pub fn received_at() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::ReceivedAt)
}
pub fn size() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::Size)
}
pub fn from() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::From)
}
pub fn to() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::To)
}
pub fn subject() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::Subject)
}
pub fn sent_at() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::SentAt)
}
pub fn has_keyword(keyword: impl Into<String>) -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::HasKeyword {
keyword: keyword.into(),
})
}
pub fn all_in_thread_have_keyword(keyword: impl Into<String>) -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::AllInThreadHaveKeyword {
keyword: keyword.into(),
})
}
pub fn some_in_thread_have_keyword(
keyword: impl Into<String>,
) -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::SomeInThreadHaveKeyword {
keyword: keyword.into(),
})
}
}

View File

View File

@ -7,8 +7,12 @@ use super::{
}; };
impl Email<Set> { impl Email<Set> {
pub fn mailbox_ids(mut self, mailbox_ids: impl Iterator<Item = String>) -> Self { pub fn mailbox_ids<T, U>(mut self, mailbox_ids: T) -> Self
self.mailbox_ids = Some(mailbox_ids.into_iter().map(|s| (s, true)).collect()); where
T: IntoIterator<Item = U>,
U: Into<String>,
{
self.mailbox_ids = Some(mailbox_ids.into_iter().map(|s| (s.into(), true)).collect());
self self
} }
@ -21,8 +25,12 @@ impl Email<Set> {
self self
} }
pub fn keywords(mut self, keywords: impl Iterator<Item = String>) -> Self { pub fn keywords<T, U>(mut self, keywords: T) -> Self
self.keywords = Some(keywords.into_iter().map(|s| (s, true)).collect()); where
T: IntoIterator<Item = U>,
U: Into<String>,
{
self.keywords = Some(keywords.into_iter().map(|s| (s.into(), true)).collect());
self self
} }
@ -33,77 +41,89 @@ impl Email<Set> {
self self
} }
pub fn message_id(mut self, message_id: impl Iterator<Item = String>) -> Self { pub fn message_id<T, U>(mut self, message_id: T) -> Self
self.message_id = Some(message_id.into_iter().collect()); where
T: IntoIterator<Item = U>,
U: Into<String>,
{
self.message_id = Some(message_id.into_iter().map(|v| v.into()).collect());
self self
} }
pub fn in_reply_to(mut self, in_reply_to: impl Iterator<Item = String>) -> Self { pub fn in_reply_to<T, U>(mut self, in_reply_to: T) -> Self
self.in_reply_to = Some(in_reply_to.into_iter().collect()); where
T: IntoIterator<Item = U>,
U: Into<String>,
{
self.in_reply_to = Some(in_reply_to.into_iter().map(|v| v.into()).collect());
self self
} }
pub fn references(mut self, references: impl Iterator<Item = String>) -> Self { pub fn references<T, U>(mut self, references: T) -> Self
self.references = Some(references.into_iter().collect()); where
T: IntoIterator<Item = U>,
U: Into<String>,
{
self.references = Some(references.into_iter().map(|v| v.into()).collect());
self self
} }
pub fn sender<T, U>(mut self, sender: T) -> Self pub fn sender<T, U>(mut self, sender: T) -> Self
where where
T: Iterator<Item = U>, T: IntoIterator<Item = U>,
U: Into<EmailAddress>, U: Into<EmailAddress>,
{ {
self.sender = Some(sender.map(|s| s.into()).collect()); self.sender = Some(sender.into_iter().map(|s| s.into()).collect());
self self
} }
pub fn from<T, U>(mut self, from: T) -> Self pub fn from<T, U>(mut self, from: T) -> Self
where where
T: Iterator<Item = U>, T: IntoIterator<Item = U>,
U: Into<EmailAddress>, U: Into<EmailAddress>,
{ {
self.from = Some(from.map(|s| s.into()).collect()); self.from = Some(from.into_iter().map(|s| s.into()).collect());
self self
} }
pub fn to<T, U>(mut self, to: T) -> Self pub fn to<T, U>(mut self, to: T) -> Self
where where
T: Iterator<Item = U>, T: IntoIterator<Item = U>,
U: Into<EmailAddress>, U: Into<EmailAddress>,
{ {
self.to = Some(to.map(|s| s.into()).collect()); self.to = Some(to.into_iter().map(|s| s.into()).collect());
self self
} }
pub fn cc<T, U>(mut self, cc: T) -> Self pub fn cc<T, U>(mut self, cc: T) -> Self
where where
T: Iterator<Item = U>, T: IntoIterator<Item = U>,
U: Into<EmailAddress>, U: Into<EmailAddress>,
{ {
self.cc = Some(cc.map(|s| s.into()).collect()); self.cc = Some(cc.into_iter().map(|s| s.into()).collect());
self self
} }
pub fn bcc<T, U>(mut self, bcc: T) -> Self pub fn bcc<T, U>(mut self, bcc: T) -> Self
where where
T: Iterator<Item = U>, T: IntoIterator<Item = U>,
U: Into<EmailAddress>, U: Into<EmailAddress>,
{ {
self.bcc = Some(bcc.map(|s| s.into()).collect()); self.bcc = Some(bcc.into_iter().map(|s| s.into()).collect());
self self
} }
pub fn reply_to<T, U>(mut self, reply_to: T) -> Self pub fn reply_to<T, U>(mut self, reply_to: T) -> Self
where where
T: Iterator<Item = U>, T: IntoIterator<Item = U>,
U: Into<EmailAddress>, U: Into<EmailAddress>,
{ {
self.reply_to = Some(reply_to.map(|s| s.into()).collect()); self.reply_to = Some(reply_to.into_iter().map(|s| s.into()).collect());
self self
} }
pub fn subject(mut self, subject: String) -> Self { pub fn subject(mut self, subject: impl Into<String>) -> Self {
self.subject = Some(subject); self.subject = Some(subject.into());
self self
} }
@ -202,38 +222,42 @@ impl EmailBodyPart {
} }
impl EmailBodyPart<Set> { impl EmailBodyPart<Set> {
pub fn part_id(mut self, part_id: String) -> Self { pub fn part_id(mut self, part_id: impl Into<String>) -> Self {
self.part_id = Some(part_id); self.part_id = Some(part_id.into());
self self
} }
pub fn blob_id(mut self, blob_id: String) -> Self { pub fn blob_id(mut self, blob_id: impl Into<String>) -> Self {
self.blob_id = Some(blob_id); self.blob_id = Some(blob_id.into());
self self
} }
pub fn name(mut self, name: String) -> Self { pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name); self.name = Some(name.into());
self self
} }
pub fn content_type(mut self, content_type: String) -> Self { pub fn content_type(mut self, content_type: impl Into<String>) -> Self {
self.type_ = Some(content_type); self.type_ = Some(content_type.into());
self self
} }
pub fn content_id(mut self, content_id: String) -> Self { pub fn content_id(mut self, content_id: impl Into<String>) -> Self {
self.cid = Some(content_id); self.cid = Some(content_id.into());
self self
} }
pub fn content_language(mut self, content_language: impl Iterator<Item = String>) -> Self { pub fn content_language<T, U>(mut self, content_language: T) -> Self
self.language = Some(content_language.into_iter().collect()); where
T: IntoIterator<Item = U>,
U: Into<String>,
{
self.language = Some(content_language.into_iter().map(|v| v.into()).collect());
self self
} }
pub fn content_location(mut self, content_location: String) -> Self { pub fn content_location(mut self, content_location: impl Into<String>) -> Self {
self.location = Some(content_location); self.location = Some(content_location.into());
self self
} }
@ -333,8 +357,8 @@ impl EmailAddressGroup {
} }
impl EmailAddressGroup<Set> { impl EmailAddressGroup<Set> {
pub fn name(mut self, name: String) -> Self { pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name); self.name = Some(name.into());
self self
} }

View File

@ -1,4 +1,5 @@
pub mod get; pub mod get;
pub mod query;
pub mod set; pub mod set;
use std::collections::HashMap; use std::collections::HashMap;
@ -6,7 +7,15 @@ use std::collections::HashMap;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::Get; use crate::{email::Email, Get};
#[derive(Debug, Clone, Serialize, Default)]
pub struct SetArguments {
#[serde(rename = "onSuccessUpdateEmail")]
on_success_update_email: Option<HashMap<String, Email>>,
#[serde(rename = "onSuccessDestroyEmail")]
on_success_destroy_email: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmailSubmission<State = Get> { pub struct EmailSubmission<State = Get> {
@ -115,7 +124,7 @@ pub enum Displayed {
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EmailSubmissionProperty { pub enum Property {
#[serde(rename = "id")] #[serde(rename = "id")]
Id, Id,
#[serde(rename = "identityId")] #[serde(rename = "identityId")]

View File

@ -0,0 +1,108 @@
use chrono::{DateTime, Utc};
use serde::Serialize;
use crate::core::{query, set::from_timestamp};
use super::UndoStatus;
#[derive(Serialize, Clone, Debug)]
#[serde(untagged)]
pub enum Filter {
IdentityIds {
#[serde(rename = "identityIds")]
value: Vec<String>,
},
EmailIds {
#[serde(rename = "emailIds")]
value: Vec<String>,
},
ThreadIds {
#[serde(rename = "threadIds")]
value: Vec<String>,
},
UndoStatus {
#[serde(rename = "undoStatus")]
value: UndoStatus,
},
Before {
#[serde(rename = "before")]
value: DateTime<Utc>,
},
After {
#[serde(rename = "after")]
value: DateTime<Utc>,
},
}
#[derive(Serialize, Debug, Clone)]
#[serde(tag = "property")]
pub enum Comparator {
#[serde(rename = "emailId")]
EmailId,
#[serde(rename = "threadId")]
ThreadId,
#[serde(rename = "sentAt")]
SentAt,
}
impl Filter {
pub fn identity_ids<U, V>(value: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<String>,
{
Filter::IdentityIds {
value: value.into_iter().map(|v| v.into()).collect(),
}
}
pub fn email_ids<U, V>(value: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<String>,
{
Filter::EmailIds {
value: value.into_iter().map(|v| v.into()).collect(),
}
}
pub fn thread_ids<U, V>(value: U) -> Self
where
U: IntoIterator<Item = V>,
V: Into<String>,
{
Filter::ThreadIds {
value: value.into_iter().map(|v| v.into()).collect(),
}
}
pub fn undo_status(value: UndoStatus) -> Self {
Filter::UndoStatus { value }
}
pub fn before(value: i64) -> Self {
Filter::Before {
value: from_timestamp(value),
}
}
pub fn after(value: i64) -> Self {
Filter::After {
value: from_timestamp(value),
}
}
}
impl Comparator {
pub fn email_id() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::EmailId)
}
pub fn thread_id() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::ThreadId)
}
pub fn sent_at() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::SentAt)
}
}

View File

@ -44,7 +44,7 @@ pub struct Identity<State = Get> {
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum IdentityProperty { pub enum Property {
#[serde(rename = "id")] #[serde(rename = "id")]
Id, Id,
#[serde(rename = "name")] #[serde(rename = "name")]

View File

@ -3,6 +3,7 @@ use std::collections::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod blob; pub mod blob;
pub mod client;
pub mod core; pub mod core;
pub mod email; pub mod email;
pub mod email_submission; pub mod email_submission;
@ -29,7 +30,7 @@ pub enum URI {
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
enum Method { pub enum Method {
#[serde(rename = "Core/echo")] #[serde(rename = "Core/echo")]
Echo, Echo,
#[serde(rename = "Blob/copy")] #[serde(rename = "Blob/copy")]

View File

@ -1,4 +1,5 @@
pub mod get; pub mod get;
pub mod query;
pub mod set; pub mod set;
use crate::core::set::string_not_set; use crate::core::set::string_not_set;
@ -6,6 +7,20 @@ use crate::mailbox::set::role_not_set;
use crate::Get; use crate::Get;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Default)]
pub struct SetArguments {
#[serde(rename = "onDestroyRemoveEmails")]
on_destroy_remove_emails: bool,
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct QueryArguments {
#[serde(rename = "sortAsTree")]
sort_as_tree: bool,
#[serde(rename = "filterAsTree")]
filter_as_tree: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Mailbox<State = Get> { pub struct Mailbox<State = Get> {
#[serde(skip)] #[serde(skip)]
@ -100,7 +115,7 @@ pub struct MailboxRights {
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MailboxProperty { pub enum Property {
#[serde(rename = "id")] #[serde(rename = "id")]
Id, Id,
#[serde(rename = "name")] #[serde(rename = "name")]

83
src/mailbox/query.rs Normal file
View File

@ -0,0 +1,83 @@
use serde::Serialize;
use crate::core::query::{self};
use super::Role;
#[derive(Serialize, Clone, Debug)]
#[serde(untagged)]
pub enum Filter {
ParentId {
#[serde(rename = "parentId")]
value: Option<String>,
},
Name {
#[serde(rename = "name")]
value: String,
},
Role {
#[serde(rename = "role")]
value: Option<Role>,
},
HasAnyRole {
#[serde(rename = "hasAnyRole")]
value: bool,
},
IsSubscribed {
#[serde(rename = "isSubscribed")]
value: bool,
},
}
#[derive(Serialize, Debug, Clone)]
#[serde(tag = "property")]
pub enum Comparator {
#[serde(rename = "name")]
Name,
#[serde(rename = "sortOrder")]
SortOrder,
#[serde(rename = "parentId")]
ParentId,
}
impl Filter {
pub fn parent_id(value: Option<String>) -> Self {
Filter::ParentId { value }
}
pub fn name(value: String) -> Self {
Filter::Name { value }
}
pub fn role(value: Role) -> Self {
Filter::Role {
value: if !matches!(value, Role::None) {
value.into()
} else {
None
},
}
}
pub fn has_any_role(value: bool) -> Self {
Filter::HasAnyRole { value }
}
pub fn is_subscribed(value: bool) -> Self {
Filter::IsSubscribed { value }
}
}
impl Comparator {
pub fn name() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::Name)
}
pub fn sort_order() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::SortOrder)
}
pub fn parent_id() -> query::Comparator<Comparator> {
query::Comparator::new(Comparator::ParentId)
}
}

View File

@ -42,7 +42,7 @@ pub struct PushSubscription<State = Get> {
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PushSubscriptionProperty { pub enum Property {
#[serde(rename = "id")] #[serde(rename = "id")]
Id, Id,
#[serde(rename = "deviceClientId")] #[serde(rename = "deviceClientId")]

View File

@ -8,3 +8,11 @@ pub struct Thread {
#[serde(rename = "emailIds")] #[serde(rename = "emailIds")]
email_ids: Vec<String>, email_ids: Vec<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Property {
#[serde(rename = "id")]
Id,
#[serde(rename = "emailIds")]
EmailIds,
}

View File

@ -40,3 +40,21 @@ pub struct VacationResponse<State = Get> {
#[serde(skip_serializing_if = "string_not_set")] #[serde(skip_serializing_if = "string_not_set")]
html_body: Option<String>, html_body: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Property {
#[serde(rename = "id")]
Id,
#[serde(rename = "isEnabled")]
IsEnabled,
#[serde(rename = "fromDate")]
FromDate,
#[serde(rename = "toDate")]
ToDate,
#[serde(rename = "subject")]
Subject,
#[serde(rename = "textBody")]
TextBody,
#[serde(rename = "htmlBody")]
HtmlBody,
}