Initial tests.

main
Mauro D 2022-05-12 14:48:26 +00:00
parent e10834ecaa
commit a23d97e3a4
21 changed files with 929 additions and 326 deletions

View File

@ -16,7 +16,6 @@ serde = { version = "1.0", features = ["derive"]}
serde_json = "1.0" serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"]} chrono = { version = "0.4", features = ["serde"]}
reqwest = "0.11" reqwest = "0.11"
ece = "2.2"
base64 = "0.13" base64 = "0.13"
#[dev-dependencies] #[dev-dependencies]

View File

@ -82,4 +82,8 @@ impl UploadResponse {
pub fn size(&self) -> usize { pub fn size(&self) -> usize {
self.size self.size
} }
pub fn unwrap_blob_id(self) -> String {
self.blob_id
}
} }

View File

@ -4,11 +4,13 @@ use reqwest::{
header::{self}, header::{self},
Response, Response,
}; };
use serde::de::DeserializeOwned;
use crate::{ use crate::{
blob, blob,
core::{ core::{
request::Request, request::{self, Request},
response,
session::{Session, URLPart}, session::{Session, URLPart},
}, },
event_source, Error, event_source, Error,
@ -58,7 +60,7 @@ impl Client {
let default_account_id = session let default_account_id = session
.primary_accounts() .primary_accounts()
.next() .next()
.map(|a| a.0.to_string()) .map(|a| a.1.to_string())
.unwrap_or_default(); .unwrap_or_default();
headers.insert( headers.insert(
@ -94,8 +96,30 @@ impl Client {
&self.headers &self.headers
} }
pub async fn update_session(&mut self, new_state: &str) -> crate::Result<()> { pub async fn send<R>(
if new_state != self.session.state() { &mut self,
request: &request::Request<'_>,
) -> crate::Result<response::Response<R>>
where
R: DeserializeOwned,
{
let response: response::Response<R> = serde_json::from_slice(
&Client::handle_error(
reqwest::Client::builder()
.timeout(Duration::from_millis(self.timeout))
.default_headers(self.headers.clone())
.build()?
.post(self.session.api_url())
.body(serde_json::to_string(&request)?)
.send()
.await?,
)
.await?
.bytes()
.await?,
)?;
if response.session_state() != self.session.state() {
let session: Session = serde_json::from_slice( let session: Session = serde_json::from_slice(
&Client::handle_error( &Client::handle_error(
reqwest::Client::builder() reqwest::Client::builder()
@ -115,7 +139,8 @@ impl Client {
self.event_source_url = URLPart::parse(session.event_source_url())?; self.event_source_url = URLPart::parse(session.event_source_url())?;
self.session = session; self.session = session;
} }
Ok(())
Ok(response)
} }
pub fn set_default_account_id(&mut self, defaul_account_id: impl Into<String>) { pub fn set_default_account_id(&mut self, defaul_account_id: impl Into<String>) {
@ -126,7 +151,7 @@ impl Client {
&self.default_account_id &self.default_account_id
} }
pub fn request(&mut self) -> Request<'_> { pub fn build(&mut self) -> Request<'_> {
Request::new(self) Request::new(self)
} }
@ -154,18 +179,28 @@ impl Client {
&response.bytes().await?, &response.bytes().await?,
)?)) )?))
} else { } else {
Err(Error::ServerError(format!("{}", response.status()))) Err(Error::Server(format!("{}", response.status())))
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::core::response::Response;
#[test] fn _test_serialize() {
fn test_serialize() {
let r: Response = serde_json::from_slice( /*let coco = request
.send()
.await
.unwrap()
.unwrap_method_responses()
.pop()
.unwrap()
.unwrap_get_email()
.unwrap();*/
//coco.list().first().unwrap().subject().unwrap();
/*let r: Response = serde_json::from_slice(
br#"{"sessionState": "123", "methodResponses": [[ "Email/query", { br#"{"sessionState": "123", "methodResponses": [[ "Email/query", {
"accountId": "A1", "accountId": "A1",
"queryState": "abcdefg", "queryState": "abcdefg",
@ -202,9 +237,9 @@ mod tests {
"notFound": [] "notFound": []
}, "t2" ]]}"#, }, "t2" ]]}"#,
) )
.unwrap(); .unwrap();*/
println!("{:?}", r); //println!("{:?}", r);
/*let mut client = Client::connect("coco"); /*let mut client = Client::connect("coco");
let mut request = client.request(); let mut request = client.request();

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::{collections::HashMap, fmt::Display};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -32,7 +32,7 @@ pub struct CopyRequest<T: Create> {
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct CopyResponse<T, U> { pub struct CopyResponse<T, U: Display> {
#[serde(rename = "fromAccountId")] #[serde(rename = "fromAccountId")]
from_account_id: String, from_account_id: String,
@ -102,7 +102,7 @@ impl<T: Create> CopyRequest<T> {
} }
} }
impl<T, U> CopyResponse<T, U> { impl<T, U: Display> CopyResponse<T, U> {
pub fn from_account_id(&self) -> &str { pub fn from_account_id(&self) -> &str {
&self.from_account_id &self.from_account_id
} }

View File

@ -102,6 +102,37 @@ impl MethodError {
} }
} }
impl Display for MethodError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.p_type {
MethodErrorType::ServerUnavailable => write!(f, "Server unavailable"),
MethodErrorType::ServerFail => write!(f, "Server fail"),
MethodErrorType::ServerPartialFail => write!(f, "Server partial fail"),
MethodErrorType::UnknownMethod => write!(f, "Unknown method"),
MethodErrorType::InvalidArguments => write!(f, "Invalid arguments"),
MethodErrorType::InvalidResultReference => write!(f, "Invalid result reference"),
MethodErrorType::Forbidden => write!(f, "Forbidden"),
MethodErrorType::AccountNotFound => write!(f, "Account not found"),
MethodErrorType::AccountNotSupportedByMethod => {
write!(f, "Account not supported by method")
}
MethodErrorType::AccountReadOnly => write!(f, "Account read only"),
MethodErrorType::RequestTooLarge => write!(f, "Request too large"),
MethodErrorType::CannotCalculateChanges => write!(f, "Cannot calculate changes"),
MethodErrorType::StateMismatch => write!(f, "State mismatch"),
MethodErrorType::AlreadyExists => write!(f, "Already exists"),
MethodErrorType::FromAccountNotFound => write!(f, "From account not found"),
MethodErrorType::FromAccountNotSupportedByMethod => {
write!(f, "From account not supported by method")
}
MethodErrorType::AnchorNotFound => write!(f, "Anchor not found"),
MethodErrorType::UnsupportedSort => write!(f, "Unsupported sort"),
MethodErrorType::UnsupportedFilter => write!(f, "Unsupported filter"),
MethodErrorType::TooManyChanges => write!(f, "Too many changes"),
}
}
}
impl Display for ProblemDetails { impl Display for ProblemDetails {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.p_type { match self.p_type {

View File

@ -1,6 +1,6 @@
use std::{collections::HashMap, time::Duration}; use std::collections::HashMap;
use serde::Serialize; use serde::{de::DeserializeOwned, Serialize};
use crate::{ use crate::{
blob::copy::CopyBlobRequest, blob::copy::CopyBlobRequest,
@ -12,18 +12,25 @@ use crate::{
push_subscription::{self, PushSubscription}, push_subscription::{self, PushSubscription},
thread, thread,
vacation_response::{self, VacationResponse}, vacation_response::{self, VacationResponse},
Method, Set, URI, Error, Method, Set, URI,
}; };
use super::{ use super::{
changes::ChangesRequest, copy::CopyRequest, get::GetRequest, query::QueryRequest, changes::ChangesRequest,
query_changes::QueryChangesRequest, response::Response, set::SetRequest, copy::CopyRequest,
get::GetRequest,
query::QueryRequest,
query_changes::QueryChangesRequest,
response::{MethodResponse, Response, SingleMethodResponse},
set::SetRequest,
}; };
#[derive(Serialize)] #[derive(Serialize)]
pub struct Request<'x> { pub struct Request<'x> {
#[serde(skip)] #[serde(skip)]
client: &'x mut Client, client: Option<&'x mut Client>,
#[serde(skip)]
default_account_id: String,
using: Vec<URI>, using: Vec<URI>,
@ -399,28 +406,29 @@ impl<'x> Request<'x> {
using: vec![URI::Core, URI::Mail], using: vec![URI::Core, URI::Mail],
method_calls: vec![], method_calls: vec![],
created_ids: None, created_ids: None,
client, default_account_id: client.default_account_id().to_string(),
client: client.into(),
} }
} }
pub async fn send(&mut self) -> crate::Result<Response> { pub async fn send(mut self) -> crate::Result<Response<MethodResponse>> {
let response: Response = serde_json::from_slice( Option::take(&mut self.client).unwrap().send(&self).await
&Client::handle_error( }
reqwest::Client::builder()
.timeout(Duration::from_millis(self.client.timeout())) pub async fn send_single<T>(mut self) -> crate::Result<T>
.default_headers(self.client.headers().clone()) where
.build()? T: DeserializeOwned,
.post(self.client.session().api_url()) {
.body(serde_json::to_string(&self)?) let response: Response<SingleMethodResponse<T>> =
.send() Option::take(&mut self.client).unwrap().send(&self).await?;
.await?, match response
) .unwrap_method_responses()
.await? .pop()
.bytes() .ok_or_else(|| Error::Internal("Server returned no results".to_string()))?
.await?, {
)?; SingleMethodResponse::Ok((_, response, _)) => Ok(response),
self.client.update_session(response.session_state()).await?; SingleMethodResponse::Error((_, err, _)) => Err(err.into()),
Ok(response) }
} }
fn add_method_call(&mut self, method: Method, arguments: Arguments) -> &mut Arguments { fn add_method_call(&mut self, method: Method, arguments: Arguments) -> &mut Arguments {
@ -432,7 +440,7 @@ impl<'x> Request<'x> {
pub fn get_push(&mut self) -> &mut GetRequest<push_subscription::Property, ()> { pub fn get_push(&mut self) -> &mut GetRequest<push_subscription::Property, ()> {
self.add_method_call( self.add_method_call(
Method::GetPushSubscription, Method::GetPushSubscription,
Arguments::push_get(self.client.default_account_id().to_string()), Arguments::push_get(self.default_account_id.clone()),
) )
.push_get_mut() .push_get_mut()
} }
@ -440,7 +448,7 @@ impl<'x> Request<'x> {
pub fn set_push(&mut self) -> &mut SetRequest<PushSubscription<Set>, ()> { pub fn set_push(&mut self) -> &mut SetRequest<PushSubscription<Set>, ()> {
self.add_method_call( self.add_method_call(
Method::SetPushSubscription, Method::SetPushSubscription,
Arguments::push_set(self.client.default_account_id().to_string()), Arguments::push_set(self.default_account_id.clone()),
) )
.push_set_mut() .push_set_mut()
} }
@ -460,7 +468,7 @@ impl<'x> Request<'x> {
pub fn get_mailbox(&mut self) -> &mut GetRequest<mailbox::Property, ()> { pub fn get_mailbox(&mut self) -> &mut GetRequest<mailbox::Property, ()> {
self.add_method_call( self.add_method_call(
Method::GetMailbox, Method::GetMailbox,
Arguments::mailbox_get(self.client.default_account_id().to_string()), Arguments::mailbox_get(self.default_account_id.clone()),
) )
.mailbox_get_mut() .mailbox_get_mut()
} }
@ -468,10 +476,7 @@ impl<'x> Request<'x> {
pub fn changes_mailbox(&mut self, since_state: impl Into<String>) -> &mut ChangesRequest { pub fn changes_mailbox(&mut self, since_state: impl Into<String>) -> &mut ChangesRequest {
self.add_method_call( self.add_method_call(
Method::ChangesMailbox, Method::ChangesMailbox,
Arguments::changes( Arguments::changes(self.default_account_id.clone(), since_state.into()),
self.client.default_account_id().to_string(),
since_state.into(),
),
) )
.changes_mut() .changes_mut()
} }
@ -485,7 +490,7 @@ impl<'x> Request<'x> {
> { > {
self.add_method_call( self.add_method_call(
Method::QueryMailbox, Method::QueryMailbox,
Arguments::mailbox_query(self.client.default_account_id().to_string()), Arguments::mailbox_query(self.default_account_id.clone()),
) )
.mailbox_query_mut() .mailbox_query_mut()
} }
@ -501,7 +506,7 @@ impl<'x> Request<'x> {
self.add_method_call( self.add_method_call(
Method::QueryChangesMailbox, Method::QueryChangesMailbox,
Arguments::mailbox_query_changes( Arguments::mailbox_query_changes(
self.client.default_account_id().to_string(), self.default_account_id.clone(),
since_query_state.into(), since_query_state.into(),
), ),
) )
@ -511,7 +516,7 @@ impl<'x> Request<'x> {
pub fn set_mailbox(&mut self) -> &mut SetRequest<Mailbox<Set>, mailbox::SetArguments> { pub fn set_mailbox(&mut self) -> &mut SetRequest<Mailbox<Set>, mailbox::SetArguments> {
self.add_method_call( self.add_method_call(
Method::SetMailbox, Method::SetMailbox,
Arguments::mailbox_set(self.client.default_account_id().to_string()), Arguments::mailbox_set(self.default_account_id.clone()),
) )
.mailbox_set_mut() .mailbox_set_mut()
} }
@ -519,7 +524,7 @@ impl<'x> Request<'x> {
pub fn get_thread(&mut self) -> &mut GetRequest<thread::Property, ()> { pub fn get_thread(&mut self) -> &mut GetRequest<thread::Property, ()> {
self.add_method_call( self.add_method_call(
Method::GetThread, Method::GetThread,
Arguments::thread_get(self.client.default_account_id().to_string()), Arguments::thread_get(self.default_account_id.clone()),
) )
.thread_get_mut() .thread_get_mut()
} }
@ -527,17 +532,14 @@ impl<'x> Request<'x> {
pub fn changes_thread(&mut self, since_state: impl Into<String>) -> &mut ChangesRequest { pub fn changes_thread(&mut self, since_state: impl Into<String>) -> &mut ChangesRequest {
self.add_method_call( self.add_method_call(
Method::ChangesThread, Method::ChangesThread,
Arguments::changes( Arguments::changes(self.default_account_id.clone(), since_state.into()),
self.client.default_account_id().to_string(),
since_state.into(),
),
) )
.changes_mut() .changes_mut()
} }
pub fn get_email(&mut self) -> &mut GetRequest<email::Property, email::GetArguments> { pub fn get_email(&mut self) -> &mut GetRequest<email::Property, email::GetArguments> {
self.add_method_call( self.add_method_call(
Method::GetEmail, Method::GetEmail,
Arguments::email_get(self.client.default_account_id().to_string()), Arguments::email_get(self.default_account_id.clone()),
) )
.email_get_mut() .email_get_mut()
} }
@ -545,10 +547,7 @@ impl<'x> Request<'x> {
pub fn changes_email(&mut self, since_state: impl Into<String>) -> &mut ChangesRequest { pub fn changes_email(&mut self, since_state: impl Into<String>) -> &mut ChangesRequest {
self.add_method_call( self.add_method_call(
Method::ChangesEmail, Method::ChangesEmail,
Arguments::changes( Arguments::changes(self.default_account_id.clone(), since_state.into()),
self.client.default_account_id().to_string(),
since_state.into(),
),
) )
.changes_mut() .changes_mut()
} }
@ -559,7 +558,7 @@ impl<'x> Request<'x> {
{ {
self.add_method_call( self.add_method_call(
Method::QueryEmail, Method::QueryEmail,
Arguments::email_query(self.client.default_account_id().to_string()), Arguments::email_query(self.default_account_id.clone()),
) )
.email_query_mut() .email_query_mut()
} }
@ -575,7 +574,7 @@ impl<'x> Request<'x> {
self.add_method_call( self.add_method_call(
Method::QueryChangesEmail, Method::QueryChangesEmail,
Arguments::email_query_changes( Arguments::email_query_changes(
self.client.default_account_id().to_string(), self.default_account_id.clone(),
since_query_state.into(), since_query_state.into(),
), ),
) )
@ -585,7 +584,7 @@ impl<'x> Request<'x> {
pub fn set_email(&mut self) -> &mut SetRequest<Email<Set>, ()> { pub fn set_email(&mut self) -> &mut SetRequest<Email<Set>, ()> {
self.add_method_call( self.add_method_call(
Method::SetEmail, Method::SetEmail,
Arguments::email_set(self.client.default_account_id().to_string()), Arguments::email_set(self.default_account_id.clone()),
) )
.email_set_mut() .email_set_mut()
} }
@ -605,7 +604,7 @@ impl<'x> Request<'x> {
pub fn import_email(&mut self) -> &mut EmailImportRequest { pub fn import_email(&mut self) -> &mut EmailImportRequest {
self.add_method_call( self.add_method_call(
Method::ImportEmail, Method::ImportEmail,
Arguments::email_import(self.client.default_account_id().to_string()), Arguments::email_import(self.default_account_id.clone()),
) )
.email_import_mut() .email_import_mut()
} }
@ -613,7 +612,7 @@ impl<'x> Request<'x> {
pub fn parse_email(&mut self) -> &mut EmailParseRequest { pub fn parse_email(&mut self) -> &mut EmailParseRequest {
self.add_method_call( self.add_method_call(
Method::ParseEmail, Method::ParseEmail,
Arguments::email_parse(self.client.default_account_id().to_string()), Arguments::email_parse(self.default_account_id.clone()),
) )
.email_parse_mut() .email_parse_mut()
} }
@ -621,7 +620,7 @@ impl<'x> Request<'x> {
pub fn get_identity(&mut self) -> &mut GetRequest<identity::Property, ()> { pub fn get_identity(&mut self) -> &mut GetRequest<identity::Property, ()> {
self.add_method_call( self.add_method_call(
Method::GetIdentity, Method::GetIdentity,
Arguments::identity_get(self.client.default_account_id().to_string()), Arguments::identity_get(self.default_account_id.clone()),
) )
.identity_get_mut() .identity_get_mut()
} }
@ -629,7 +628,7 @@ impl<'x> Request<'x> {
pub fn set_identity(&mut self) -> &mut SetRequest<Identity<Set>, ()> { pub fn set_identity(&mut self) -> &mut SetRequest<Identity<Set>, ()> {
self.add_method_call( self.add_method_call(
Method::SetIdentity, Method::SetIdentity,
Arguments::identity_set(self.client.default_account_id().to_string()), Arguments::identity_set(self.default_account_id.clone()),
) )
.identity_set_mut() .identity_set_mut()
} }
@ -640,7 +639,7 @@ impl<'x> Request<'x> {
} }
self.add_method_call( self.add_method_call(
Method::GetEmailSubmission, Method::GetEmailSubmission,
Arguments::email_submission_get(self.client.default_account_id().to_string()), Arguments::email_submission_get(self.default_account_id.clone()),
) )
.email_submission_get_mut() .email_submission_get_mut()
} }
@ -654,10 +653,7 @@ impl<'x> Request<'x> {
} }
self.add_method_call( self.add_method_call(
Method::ChangesEmailSubmission, Method::ChangesEmailSubmission,
Arguments::changes( Arguments::changes(self.default_account_id.clone(), since_state.into()),
self.client.default_account_id().to_string(),
since_state.into(),
),
) )
.changes_mut() .changes_mut()
} }
@ -671,7 +667,7 @@ impl<'x> Request<'x> {
} }
self.add_method_call( self.add_method_call(
Method::QueryEmailSubmission, Method::QueryEmailSubmission,
Arguments::email_submission_query(self.client.default_account_id().to_string()), Arguments::email_submission_query(self.default_account_id.clone()),
) )
.email_submission_query_mut() .email_submission_query_mut()
} }
@ -690,7 +686,7 @@ impl<'x> Request<'x> {
self.add_method_call( self.add_method_call(
Method::QueryChangesEmailSubmission, Method::QueryChangesEmailSubmission,
Arguments::email_submission_query_changes( Arguments::email_submission_query_changes(
self.client.default_account_id().to_string(), self.default_account_id.clone(),
since_query_state.into(), since_query_state.into(),
), ),
) )
@ -705,7 +701,7 @@ impl<'x> Request<'x> {
} }
self.add_method_call( self.add_method_call(
Method::SetEmailSubmission, Method::SetEmailSubmission,
Arguments::email_submission_set(self.client.default_account_id().to_string()), Arguments::email_submission_set(self.default_account_id.clone()),
) )
.email_submission_set_mut() .email_submission_set_mut()
} }
@ -716,7 +712,7 @@ impl<'x> Request<'x> {
} }
self.add_method_call( self.add_method_call(
Method::GetVacationResponse, Method::GetVacationResponse,
Arguments::vacation_response_get(self.client.default_account_id().to_string()), Arguments::vacation_response_get(self.default_account_id.clone()),
) )
.vacation_response_get_mut() .vacation_response_get_mut()
} }
@ -727,7 +723,7 @@ impl<'x> Request<'x> {
} }
self.add_method_call( self.add_method_call(
Method::SetVacationResponse, Method::SetVacationResponse,
Arguments::vacation_response_set(self.client.default_account_id().to_string()), Arguments::vacation_response_set(self.default_account_id.clone()),
) )
.vacation_response_set_mut() .vacation_response_set_mut()
} }

View File

@ -20,9 +20,9 @@ use super::{
}; };
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct Response { pub struct Response<T> {
#[serde(rename = "methodResponses")] #[serde(rename = "methodResponses")]
method_responses: Vec<MethodResponse>, method_responses: Vec<T>,
#[serde(rename = "createdIds")] #[serde(rename = "createdIds")]
created_ids: Option<HashMap<String, String>>, created_ids: Option<HashMap<String, String>>,
@ -31,15 +31,13 @@ pub struct Response {
session_state: String, session_state: String,
} }
impl Response { impl<T> Response<T> {
pub fn method_responses(&self) -> &[MethodResponse] { pub fn method_responses(&self) -> &[T] {
self.method_responses.as_ref() self.method_responses.as_ref()
} }
pub fn method_response(&self, id: &str) -> Option<&MethodResponse> { pub fn unwrap_method_responses(self) -> Vec<T> {
self.method_responses self.method_responses
.iter()
.find(|response| response.call_id() == id)
} }
pub fn created_ids(&self) -> Option<impl Iterator<Item = (&String, &String)>> { pub fn created_ids(&self) -> Option<impl Iterator<Item = (&String, &String)>> {
@ -51,92 +49,82 @@ impl Response {
} }
} }
impl Response<MethodResponse> {
pub fn method_response(&self, id: &str) -> Option<&MethodResponse> {
self.method_responses
.iter()
.find(|response| response.call_id() == id)
}
}
#[derive(Debug, Deserialize)]
#[serde(untagged)]
pub enum SingleMethodResponse<T> {
Error((Error, MethodError, String)),
Ok((String, T, String)),
}
pub type PushSubscriptionSetResponse =
SetResponse<PushSubscription<Get>, push_subscription::Property>;
pub type PushSubscriptionGetResponse = GetResponse<PushSubscription<Get>>;
pub type MaiboxChangesResponse = ChangesResponse<mailbox::ChangesResponse>;
pub type MailboxSetResponse = SetResponse<Mailbox<Get>, mailbox::Property>;
pub type MailboxGetResponse = GetResponse<Mailbox<Get>>;
pub type ThreadGetResponse = GetResponse<Thread>;
pub type ThreadChangesResponse = ChangesResponse<()>;
pub type EmailGetResponse = GetResponse<Email<Get>>;
pub type EmailSetResponse = SetResponse<Email<Get>, email::Property>;
pub type EmailCopyResponse = CopyResponse<Email<Get>, email::Property>;
pub type EmailChangesResponse = ChangesResponse<()>;
pub type SearchSnippetGetResponse = GetResponse<String>;
pub type IdentitySetResponse = SetResponse<Identity<Get>, identity::Property>;
pub type IdentityGetResponse = GetResponse<Identity<Get>>;
pub type IdentityChangesResponse = ChangesResponse<()>;
pub type EmailSubmissionSetResponse = SetResponse<EmailSubmission<Get>, email_submission::Property>;
pub type EmailSubmissionGetResponse = GetResponse<EmailSubmission<Get>>;
pub type EmailSubmissionChangesResponse = ChangesResponse<()>;
pub type VacationResponseGetResponse = GetResponse<VacationResponse<Get>>;
pub type VacationResponseSetResponse =
SetResponse<VacationResponse<Get>, vacation_response::Property>;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum MethodResponse { pub enum MethodResponse {
CopyBlob((CopyBlob, CopyBlobResponse, String)), CopyBlob((CopyBlob, CopyBlobResponse, String)),
GetPushSubscription( GetPushSubscription((GetPushSubscription, PushSubscriptionGetResponse, String)),
( SetPushSubscription((SetPushSubscription, PushSubscriptionSetResponse, String)),
GetPushSubscription, GetMailbox((GetMailbox, MailboxGetResponse, String)),
GetResponse<PushSubscription<Get>>, ChangesMailbox((ChangesMailbox, MaiboxChangesResponse, String)),
String,
),
),
SetPushSubscription(
(
SetPushSubscription,
SetResponse<PushSubscription<Get>, push_subscription::Property>,
String,
),
),
GetMailbox((GetMailbox, GetResponse<Mailbox<Get>>, String)),
ChangesMailbox(
(
ChangesMailbox,
ChangesResponse<mailbox::ChangesResponse>,
String,
),
),
QueryMailbox((QueryMailbox, QueryResponse, String)), QueryMailbox((QueryMailbox, QueryResponse, String)),
QueryChangesMailbox((QueryChangesMailbox, QueryChangesResponse, String)), QueryChangesMailbox((QueryChangesMailbox, QueryChangesResponse, String)),
SetMailbox( SetMailbox((SetMailbox, MailboxSetResponse, String)),
( GetThread((GetThread, ThreadGetResponse, String)),
SetMailbox, ChangesThread((ChangesThread, ThreadChangesResponse, String)),
SetResponse<Mailbox<Get>, mailbox::Property>, GetEmail((GetEmail, EmailGetResponse, String)),
String, ChangesEmail((ChangesEmail, EmailChangesResponse, String)),
),
),
GetThread((GetThread, GetResponse<Thread>, String)),
ChangesThread((ChangesThread, ChangesResponse<()>, String)),
GetEmail((GetEmail, GetResponse<Email<Get>>, String)),
ChangesEmail((ChangesEmail, ChangesResponse<()>, String)),
QueryEmail((QueryEmail, QueryResponse, String)), QueryEmail((QueryEmail, QueryResponse, String)),
QueryChangesEmail((QueryChangesEmail, QueryChangesResponse, String)), QueryChangesEmail((QueryChangesEmail, QueryChangesResponse, String)),
SetEmail((SetEmail, SetResponse<Email<Get>, email::Property>, String)), SetEmail((SetEmail, EmailSetResponse, String)),
CopyEmail((CopyEmail, CopyResponse<Email<Get>, email::Property>, String)), CopyEmail((CopyEmail, EmailCopyResponse, String)),
ImportEmail((ImportEmail, EmailImportResponse, String)), ImportEmail((ImportEmail, EmailImportResponse, String)),
ParseEmail((ParseEmail, EmailParseResponse, String)), ParseEmail((ParseEmail, EmailParseResponse, String)),
GetSearchSnippet((GetSearchSnippet, GetResponse<String>, String)), GetSearchSnippet((GetSearchSnippet, SearchSnippetGetResponse, String)),
GetIdentity((GetIdentity, GetResponse<Identity<Get>>, String)), GetIdentity((GetIdentity, IdentityGetResponse, String)),
ChangesIdentity((ChangesIdentity, ChangesResponse<()>, String)), ChangesIdentity((ChangesIdentity, IdentityChangesResponse, String)),
SetIdentity( SetIdentity((SetIdentity, IdentitySetResponse, String)),
GetEmailSubmission((GetEmailSubmission, EmailSubmissionGetResponse, String)),
ChangesEmailSubmission(
( (
SetIdentity, ChangesEmailSubmission,
SetResponse<Identity<Get>, identity::Property>, EmailSubmissionChangesResponse,
String, String,
), ),
), ),
GetEmailSubmission(
(
GetEmailSubmission,
GetResponse<EmailSubmission<Get>>,
String,
),
),
ChangesEmailSubmission((ChangesEmailSubmission, ChangesResponse<()>, String)),
QueryEmailSubmission((QueryEmailSubmission, QueryResponse, String)), QueryEmailSubmission((QueryEmailSubmission, QueryResponse, String)),
QueryChangesEmailSubmission((QueryChangesEmailSubmission, QueryChangesResponse, String)), QueryChangesEmailSubmission((QueryChangesEmailSubmission, QueryChangesResponse, String)),
SetEmailSubmission( SetEmailSubmission((SetEmailSubmission, EmailSubmissionSetResponse, String)),
( GetVacationResponse((GetVacationResponse, VacationResponseGetResponse, String)),
SetEmailSubmission, SetVacationResponse((SetVacationResponse, VacationResponseSetResponse, String)),
SetResponse<EmailSubmission<Get>, email_submission::Property>,
String,
),
),
GetVacationResponse(
(
GetVacationResponse,
GetResponse<VacationResponse<Get>>,
String,
),
),
SetVacationResponse(
(
SetVacationResponse,
SetResponse<VacationResponse<Get>, vacation_response::Property>,
String,
),
),
Echo((Echo, serde_json::Value, String)), Echo((Echo, serde_json::Value, String)),
Error((Error, MethodError, String)), Error((Error, MethodError, String)),
} }
@ -221,226 +209,243 @@ impl MethodResponse {
) )
} }
pub fn as_copy_copy(&self) -> Option<&CopyBlobResponse> { pub fn unwrap_copy_blob(self) -> crate::Result<CopyBlobResponse> {
match self { match self {
Self::CopyBlob((_, response, _)) => response.into(), Self::CopyBlob((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_get_push_subscription(&self) -> Option<&GetResponse<PushSubscription<Get>>> { pub fn unwrap_get_push_subscription(self) -> crate::Result<PushSubscriptionGetResponse> {
match self { match self {
Self::GetPushSubscription((_, response, _)) => response.into(), Self::GetPushSubscription((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_set_push_subscription( pub fn unwrap_set_push_subscription(self) -> crate::Result<PushSubscriptionSetResponse> {
&self,
) -> Option<&SetResponse<PushSubscription<Get>, push_subscription::Property>> {
match self { match self {
Self::SetPushSubscription((_, response, _)) => response.into(), Self::SetPushSubscription((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_get_mailbox(&self) -> Option<&GetResponse<Mailbox<Get>>> { pub fn unwrap_get_mailbox(self) -> crate::Result<MailboxGetResponse> {
match self { match self {
Self::GetMailbox((_, response, _)) => response.into(), Self::GetMailbox((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_changes_mailbox(&self) -> Option<&ChangesResponse<mailbox::ChangesResponse>> { pub fn unwrap_changes_mailbox(self) -> crate::Result<MaiboxChangesResponse> {
match self { match self {
Self::ChangesMailbox((_, response, _)) => response.into(), Self::ChangesMailbox((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_query_mailbox(&self) -> Option<&QueryResponse> { pub fn unwrap_query_mailbox(self) -> crate::Result<QueryResponse> {
match self { match self {
Self::QueryMailbox((_, response, _)) => response.into(), Self::QueryMailbox((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_query_changes_mailbox(&self) -> Option<&QueryChangesResponse> { pub fn unwrap_query_changes_mailbox(self) -> crate::Result<QueryChangesResponse> {
match self { match self {
Self::QueryChangesMailbox((_, response, _)) => response.into(), Self::QueryChangesMailbox((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_set_mailbox(&self) -> Option<&SetResponse<Mailbox<Get>, mailbox::Property>> { pub fn unwrap_set_mailbox(self) -> crate::Result<MailboxSetResponse> {
match self { match self {
Self::SetMailbox((_, response, _)) => response.into(), Self::SetMailbox((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_get_thread(&self) -> Option<&GetResponse<Thread>> { pub fn unwrap_get_thread(self) -> crate::Result<ThreadGetResponse> {
match self { match self {
Self::GetThread((_, response, _)) => response.into(), Self::GetThread((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_changes_thread(&self) -> Option<&ChangesResponse<()>> { pub fn unwrap_changes_thread(self) -> crate::Result<ThreadChangesResponse> {
match self { match self {
Self::ChangesThread((_, response, _)) => response.into(), Self::ChangesThread((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_get_email(&self) -> Option<&GetResponse<Email>> { pub fn unwrap_get_email(self) -> crate::Result<EmailGetResponse> {
match self { match self {
Self::GetEmail((_, response, _)) => response.into(), Self::GetEmail((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_changes_email(&self) -> Option<&ChangesResponse<()>> { pub fn unwrap_changes_email(self) -> crate::Result<EmailChangesResponse> {
match self { match self {
Self::ChangesEmail((_, response, _)) => response.into(), Self::ChangesEmail((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_query_email(&self) -> Option<&QueryResponse> { pub fn unwrap_query_email(self) -> crate::Result<QueryResponse> {
match self { match self {
Self::QueryEmail((_, response, _)) => response.into(), Self::QueryEmail((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_query_changes_email(&self) -> Option<&QueryChangesResponse> { pub fn unwrap_query_changes_email(self) -> crate::Result<QueryChangesResponse> {
match self { match self {
Self::QueryChangesEmail((_, response, _)) => response.into(), Self::QueryChangesEmail((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_set_email(&self) -> Option<&SetResponse<Email, email::Property>> { pub fn unwrap_set_email(self) -> crate::Result<EmailSetResponse> {
match self { match self {
Self::SetEmail((_, response, _)) => response.into(), Self::SetEmail((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_copy_email(&self) -> Option<&CopyResponse<Email<Get>, email::Property>> { pub fn unwrap_copy_email(self) -> crate::Result<EmailCopyResponse> {
match self { match self {
Self::CopyEmail((_, response, _)) => response.into(), Self::CopyEmail((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_import_email(&self) -> Option<&EmailImportResponse> { pub fn unwrap_import_email(self) -> crate::Result<EmailImportResponse> {
match self { match self {
Self::ImportEmail((_, response, _)) => response.into(), Self::ImportEmail((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_parse_email(&self) -> Option<&EmailParseResponse> { pub fn unwrap_parse_email(self) -> crate::Result<EmailParseResponse> {
match self { match self {
Self::ParseEmail((_, response, _)) => response.into(), Self::ParseEmail((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_get_search_snippet(&self) -> Option<&GetResponse<String>> { pub fn unwrap_get_search_snippet(self) -> crate::Result<SearchSnippetGetResponse> {
match self { match self {
Self::GetSearchSnippet((_, response, _)) => response.into(), Self::GetSearchSnippet((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_get_identity(&self) -> Option<&GetResponse<Identity>> { pub fn unwrap_get_identity(self) -> crate::Result<IdentityGetResponse> {
match self { match self {
Self::GetIdentity((_, response, _)) => response.into(), Self::GetIdentity((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_changes_identity(&self) -> Option<&ChangesResponse<()>> { pub fn unwrap_changes_identity(self) -> crate::Result<IdentityChangesResponse> {
match self { match self {
Self::ChangesIdentity((_, response, _)) => response.into(), Self::ChangesIdentity((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_set_identity(&self) -> Option<&SetResponse<Identity, identity::Property>> { pub fn unwrap_set_identity(self) -> crate::Result<IdentitySetResponse> {
match self { match self {
Self::SetIdentity((_, response, _)) => response.into(), Self::SetIdentity((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_get_email_submission(&self) -> Option<&GetResponse<EmailSubmission>> { pub fn unwrap_get_email_submission(self) -> crate::Result<EmailSubmissionGetResponse> {
match self { match self {
Self::GetEmailSubmission((_, response, _)) => response.into(), Self::GetEmailSubmission((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_changes_email_submission(&self) -> Option<&ChangesResponse<()>> { pub fn unwrap_changes_email_submission(self) -> crate::Result<EmailSubmissionChangesResponse> {
match self { match self {
Self::ChangesEmailSubmission((_, response, _)) => response.into(), Self::ChangesEmailSubmission((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_set_email_submission( pub fn unwrap_set_email_submission(self) -> crate::Result<EmailSubmissionSetResponse> {
&self,
) -> Option<&SetResponse<EmailSubmission, email_submission::Property>> {
match self { match self {
Self::SetEmailSubmission((_, response, _)) => response.into(), Self::SetEmailSubmission((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_query_email_submission(&self) -> Option<&QueryResponse> { pub fn unwrap_query_email_submission(self) -> crate::Result<QueryResponse> {
match self { match self {
Self::QueryEmailSubmission((_, response, _)) => response.into(), Self::QueryEmailSubmission((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_query_changes_email_submission(&self) -> Option<&QueryChangesResponse> { pub fn unwrap_query_changes_email_submission(self) -> crate::Result<QueryChangesResponse> {
match self { match self {
Self::QueryChangesEmailSubmission((_, response, _)) => response.into(), Self::QueryChangesEmailSubmission((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_get_vacation_response(&self) -> Option<&GetResponse<VacationResponse>> { pub fn unwrap_get_vacation_response(self) -> crate::Result<VacationResponseGetResponse> {
match self { match self {
Self::GetVacationResponse((_, response, _)) => response.into(), Self::GetVacationResponse((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_set_vacation_response( pub fn unwrap_set_vacation_response(self) -> crate::Result<VacationResponseSetResponse> {
&self,
) -> Option<&SetResponse<VacationResponse, vacation_response::Property>> {
match self { match self {
Self::SetVacationResponse((_, response, _)) => response.into(), Self::SetVacationResponse((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
_ => Err("Response type mismatch".into()),
} }
} }
pub fn as_echo(&self) -> Option<&serde_json::Value> { pub fn unwrap_echo(self) -> crate::Result<serde_json::Value> {
match self { match self {
Self::Echo((_, response, _)) => response.into(), Self::Echo((_, response, _)) => Ok(response),
_ => None, Self::Error((_, err, _)) => Err(err.into()),
} _ => Err("Response type mismatch".into()),
}
pub fn as_error(&self) -> Option<&MethodError> {
match self {
Self::Error((_, response, _)) => response.into(),
_ => None,
} }
} }

View File

@ -1,10 +1,10 @@
use std::collections::HashMap; use std::collections::HashMap;
use serde::Deserialize; use serde::{Deserialize, Serialize};
use crate::email::{MailCapabilities, SubmissionCapabilities}; use crate::email::{MailCapabilities, SubmissionCapabilities};
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Session { pub struct Session {
#[serde(rename = "capabilities")] #[serde(rename = "capabilities")]
capabilities: HashMap<String, Capabilities>, capabilities: HashMap<String, Capabilities>,
@ -34,7 +34,7 @@ pub struct Session {
state: String, state: String,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Account { pub struct Account {
#[serde(rename = "name")] #[serde(rename = "name")]
name: String, name: String,
@ -49,7 +49,7 @@ pub struct Account {
account_capabilities: HashMap<String, Capabilities>, account_capabilities: HashMap<String, Capabilities>,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum Capabilities { pub enum Capabilities {
Core(CoreCapabilities), Core(CoreCapabilities),
@ -59,7 +59,7 @@ pub enum Capabilities {
Other(serde_json::Value), Other(serde_json::Value),
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoreCapabilities { pub struct CoreCapabilities {
#[serde(rename = "maxSizeUpload")] #[serde(rename = "maxSizeUpload")]
max_size_upload: usize, max_size_upload: usize,
@ -86,7 +86,7 @@ pub struct CoreCapabilities {
collation_algorithms: Vec<String>, collation_algorithms: Vec<String>,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmptyCapabilities {} pub struct EmptyCapabilities {}
impl Session { impl Session {
@ -235,6 +235,14 @@ impl<T: URLParser> URLPart<T> {
} }
} }
if !buf.is_empty() {
if !in_parameter {
parts.push(URLPart::Value(buf.clone()));
} else {
return Err(crate::Error::Internal(format!("Invalid URL: {}", url)));
}
}
Ok(parts) Ok(parts)
} }
} }

View File

@ -1,6 +1,11 @@
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,
fmt::{self, Display, Formatter},
};
use crate::Error;
use super::request::ResultReference; use super::request::ResultReference;
@ -32,7 +37,7 @@ pub struct SetRequest<T: Create, A: Default> {
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct SetResponse<T, U> { pub struct SetResponse<T, U: Display> {
#[serde(rename = "accountId")] #[serde(rename = "accountId")]
account_id: String, account_id: String,
@ -62,7 +67,10 @@ pub struct SetResponse<T, U> {
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
pub struct SetError<U> { pub struct SetError<U>
where
U: Display,
{
#[serde(rename = "type")] #[serde(rename = "type")]
type_: SetErrorType, type_: SetErrorType,
description: Option<String>, description: Option<String>,
@ -189,7 +197,7 @@ impl<T: Create, A: Default> SetRequest<T, A> {
} }
} }
impl<T, U> SetResponse<T, U> { impl<T, U: Display> SetResponse<T, U> {
pub fn account_id(&self) -> &str { pub fn account_id(&self) -> &str {
&self.account_id &self.account_id
} }
@ -202,52 +210,66 @@ impl<T, U> SetResponse<T, U> {
&self.new_state &self.new_state
} }
pub fn created(&self) -> Option<impl Iterator<Item = (&String, &T)>> { pub fn created(&mut self, id: &str) -> crate::Result<T> {
self.created.as_ref().map(|map| map.iter()) if let Some(result) = self.created.as_mut().and_then(|r| r.remove(id)) {
Ok(result)
} else if let Some(error) = self.not_created.as_mut().and_then(|r| r.remove(id)) {
Err(error.to_string_error().into())
} else {
Err(Error::Internal(format!("Id {} not found.", id)))
}
} }
pub fn updated(&self) -> Option<impl Iterator<Item = (&String, &Option<T>)>> { pub fn updated(&mut self, id: &str) -> crate::Result<Option<T>> {
self.updated.as_ref().map(|map| map.iter()) if let Some(result) = self.updated.as_mut().and_then(|r| r.remove(id)) {
Ok(result)
} else if let Some(error) = self.not_updated.as_mut().and_then(|r| r.remove(id)) {
Err(error.to_string_error().into())
} else {
Err(Error::Internal(format!("Id {} not found.", id)))
}
} }
pub fn destroyed(&self) -> Option<&[String]> { pub fn destroyed(&mut self, id: &str) -> crate::Result<()> {
self.destroyed.as_deref() if self
.destroyed
.as_ref()
.map_or(false, |r| r.iter().any(|i| i == id))
{
Ok(())
} else if let Some(error) = self.not_destroyed.as_mut().and_then(|r| r.remove(id)) {
Err(error.to_string_error().into())
} else {
Err(Error::Internal(format!("Id {} not found.", id)))
}
} }
pub fn not_created(&self) -> Option<impl Iterator<Item = (&String, &SetError<U>)>> { pub fn created_ids(&self) -> Option<impl Iterator<Item = &String>> {
self.not_created.as_ref().map(|map| map.iter()) self.created.as_ref().map(|map| map.keys())
} }
pub fn not_updated(&self) -> Option<impl Iterator<Item = (&String, &SetError<U>)>> { pub fn updated_ids(&self) -> Option<impl Iterator<Item = &String>> {
self.not_updated.as_ref().map(|map| map.iter()) self.updated.as_ref().map(|map| map.keys())
} }
pub fn not_destroyed(&self) -> Option<impl Iterator<Item = (&String, &SetError<U>)>> { pub fn destroyed_ids(&self) -> Option<impl Iterator<Item = &String>> {
self.not_destroyed.as_ref().map(|map| map.iter()) self.destroyed.as_ref().map(|list| list.iter())
} }
pub fn created_details(&self, id: &str) -> Option<&T> { pub fn not_created_ids(&self) -> Option<impl Iterator<Item = &String>> {
self.created.as_ref().and_then(|map| map.get(id)) self.not_created.as_ref().map(|map| map.keys())
} }
pub fn updated_details(&self, id: &str) -> Option<&T> { pub fn not_updated_ids(&self) -> Option<impl Iterator<Item = &String>> {
self.updated.as_ref().and_then(|map| map.get(id))?.as_ref() self.not_updated.as_ref().map(|map| map.keys())
} }
pub fn not_created_details(&self, id: &str) -> Option<&SetError<U>> { pub fn not_destroyed_ids(&self) -> Option<impl Iterator<Item = &String>> {
self.not_created.as_ref().and_then(|map| map.get(id)) self.not_destroyed.as_ref().map(|map| map.keys())
}
pub fn not_updated_details(&self, id: &str) -> Option<&SetError<U>> {
self.not_updated.as_ref().and_then(|map| map.get(id))
}
pub fn not_destroyed_details(&self, id: &str) -> Option<&SetError<U>> {
self.not_destroyed.as_ref().and_then(|map| map.get(id))
} }
} }
impl<U> SetError<U> { impl<U: Display> SetError<U> {
pub fn error(&self) -> &SetErrorType { pub fn error(&self) -> &SetErrorType {
&self.type_ &self.type_
} }
@ -259,6 +281,67 @@ impl<U> SetError<U> {
pub fn properties(&self) -> Option<&[U]> { pub fn properties(&self) -> Option<&[U]> {
self.properties.as_deref() self.properties.as_deref()
} }
pub fn to_string_error(&self) -> SetError<String> {
SetError {
type_: self.type_.clone(),
description: self.description.as_ref().map(|s| s.to_string()),
properties: self
.properties
.as_ref()
.map(|s| s.iter().map(|s| s.to_string()).collect()),
}
}
}
impl<U: Display> Display for SetError<U> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.type_.fmt(f)?;
if let Some(description) = &self.description {
write!(f, ": {}", description)?;
}
if let Some(properties) = &self.properties {
write!(
f,
" (properties: {})",
properties
.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>()
.join(", ")
)?;
}
Ok(())
}
}
impl Display for SetErrorType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
SetErrorType::Forbidden => write!(f, "Forbidden"),
SetErrorType::OverQuota => write!(f, "OverQuota"),
SetErrorType::TooLarge => write!(f, "TooLarge"),
SetErrorType::RateLimit => write!(f, "RateLimit"),
SetErrorType::NotFound => write!(f, "NotFound"),
SetErrorType::InvalidPatch => write!(f, "InvalidPatch"),
SetErrorType::WillDestroy => write!(f, "WillDestroy"),
SetErrorType::InvalidProperties => write!(f, "InvalidProperties"),
SetErrorType::Singleton => write!(f, "Singleton"),
SetErrorType::MailboxHasChild => write!(f, "MailboxHasChild"),
SetErrorType::MailboxHasEmail => write!(f, "MailboxHasEmail"),
SetErrorType::BlobNotFound => write!(f, "BlobNotFound"),
SetErrorType::TooManyKeywords => write!(f, "TooManyKeywords"),
SetErrorType::TooManyMailboxes => write!(f, "TooManyMailboxes"),
SetErrorType::ForbiddenFrom => write!(f, "ForbiddenFrom"),
SetErrorType::InvalidEmail => write!(f, "InvalidEmail"),
SetErrorType::TooManyRecipients => write!(f, "TooManyRecipients"),
SetErrorType::NoRecipients => write!(f, "NoRecipients"),
SetErrorType::InvalidRecipients => write!(f, "InvalidRecipients"),
SetErrorType::ForbiddenMailFrom => write!(f, "ForbiddenMailFrom"),
SetErrorType::ForbiddenToSend => write!(f, "ForbiddenToSend"),
SetErrorType::CannotUnsend => write!(f, "CannotUnsend"),
}
}
} }
pub fn from_timestamp(timestamp: i64) -> DateTime<Utc> { pub fn from_timestamp(timestamp: i64) -> DateTime<Utc> {

138
src/email/helpers.rs Normal file
View File

@ -0,0 +1,138 @@
use crate::{
client::Client,
core::{
query::{Comparator, Filter, QueryResponse},
response::{EmailGetResponse, EmailSetResponse},
},
};
use super::{import::EmailImportResponse, Email, Property};
impl Client {
pub async fn email_import<T, U>(
&mut self,
raw_message: Vec<u8>,
mailbox_ids: T,
keywords: Option<T>,
received_at: Option<i64>,
) -> crate::Result<Email>
where
T: IntoIterator<Item = U>,
U: Into<String>,
{
let blob_id = self
.upload(self.default_account_id(), None, raw_message)
.await?
.unwrap_blob_id();
let mut request = self.build();
let import_request = request
.import_email()
.email(blob_id)
.mailbox_ids(mailbox_ids);
if let Some(keywords) = keywords {
import_request.keywords(keywords);
}
if let Some(received_at) = received_at {
import_request.received_at(received_at);
}
let id = import_request.create_id();
request
.send_single::<EmailImportResponse>()
.await?
.created(&id)
}
pub async fn email_set_mailbox(
&mut self,
id: &str,
mailbox_id: &str,
set: bool,
) -> crate::Result<Option<Email>> {
let mut request = self.build();
request.set_email().update(id).mailbox_id(mailbox_id, set);
request.send_single::<EmailSetResponse>().await?.updated(id)
}
pub async fn email_set_mailboxes<T, U>(
&mut self,
id: &str,
mailbox_ids: T,
) -> crate::Result<Option<Email>>
where
T: IntoIterator<Item = U>,
U: Into<String>,
{
let mut request = self.build();
request.set_email().update(id).mailbox_ids(mailbox_ids);
request.send_single::<EmailSetResponse>().await?.updated(id)
}
pub async fn email_set_keyword(
&mut self,
id: &str,
keyword: &str,
set: bool,
) -> crate::Result<Option<Email>> {
let mut request = self.build();
request.set_email().update(id).keyword(keyword, set);
request.send_single::<EmailSetResponse>().await?.updated(id)
}
pub async fn email_set_keywords<T, U>(
&mut self,
id: &str,
keywords: T,
) -> crate::Result<Option<Email>>
where
T: IntoIterator<Item = U>,
U: Into<String>,
{
let mut request = self.build();
request.set_email().update(id).keywords(keywords);
request.send_single::<EmailSetResponse>().await?.updated(id)
}
pub async fn email_destroy(&mut self, id: &str) -> crate::Result<()> {
let mut request = self.build();
request.set_email().destroy([id]);
request
.send_single::<EmailSetResponse>()
.await?
.destroyed(id)
}
pub async fn email_get(
&mut self,
id: &str,
properties: Option<Vec<Property>>,
) -> crate::Result<Option<Email>> {
let mut request = self.build();
let get_request = request.get_email().ids([id]);
if let Some(properties) = properties {
get_request.properties(properties.into_iter());
}
request
.send_single::<EmailGetResponse>()
.await
.map(|mut r| r.unwrap_list().pop())
}
pub async fn email_query(
&mut self,
filter: Option<impl Into<Filter<super::query::Filter>>>,
sort: Option<Vec<Comparator<super::query::Comparator>>>,
) -> crate::Result<QueryResponse> {
let mut request = self.build();
let query_request = request.query_email();
if let Some(filter) = filter {
query_request.filter(filter);
}
if let Some(sort) = sort {
query_request.sort(sort.into_iter());
}
request.send_single::<QueryResponse>().await
}
}

View File

@ -3,7 +3,13 @@ use std::collections::HashMap;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::core::set::{from_timestamp, SetError}; use crate::{
core::{
request::ResultReference,
set::{from_timestamp, SetError},
},
Error,
};
use super::{Email, Property}; use super::{Email, Property};
@ -28,7 +34,13 @@ pub struct EmailImport {
blob_id: String, blob_id: String,
#[serde(rename = "mailboxIds")] #[serde(rename = "mailboxIds")]
mailbox_ids: HashMap<String, bool>, #[serde(skip_serializing_if = "Option::is_none")]
mailbox_ids: Option<HashMap<String, bool>>,
#[serde(rename = "#mailboxIds")]
#[serde(skip_deserializing)]
#[serde(skip_serializing_if = "Option::is_none")]
mailbox_ids_ref: Option<ResultReference>,
#[serde(rename = "keywords")] #[serde(rename = "keywords")]
keywords: HashMap<String, bool>, keywords: HashMap<String, bool>,
@ -86,19 +98,35 @@ impl EmailImport {
EmailImport { EmailImport {
create_id, create_id,
blob_id, blob_id,
mailbox_ids: HashMap::new(), mailbox_ids: None,
mailbox_ids_ref: None,
keywords: HashMap::new(), keywords: HashMap::new(),
received_at: None, received_at: None,
} }
} }
pub fn mailbox_id(&mut self, mailbox_id: impl Into<String>) -> &mut Self { pub fn mailbox_ids<T, U>(&mut self, mailbox_ids: T) -> &mut Self
self.mailbox_ids.insert(mailbox_id.into(), true); where
T: IntoIterator<Item = U>,
U: Into<String>,
{
self.mailbox_ids = Some(mailbox_ids.into_iter().map(|s| (s.into(), true)).collect());
self.mailbox_ids_ref = None;
self self
} }
pub fn keyword(&mut self, keyword: impl Into<String>) -> &mut Self { pub fn mailbox_ids_ref(&mut self, reference: ResultReference) -> &mut Self {
self.keywords.insert(keyword.into(), true); self.mailbox_ids_ref = reference.into();
self.mailbox_ids = None;
self
}
pub fn keywords<T, U>(&mut self, keywords: T) -> &mut Self
where
T: IntoIterator<Item = U>,
U: Into<String>,
{
self.keywords = keywords.into_iter().map(|s| (s.into(), true)).collect();
self self
} }
@ -125,19 +153,21 @@ impl EmailImportResponse {
&self.new_state &self.new_state
} }
pub fn created(&self) -> Option<impl Iterator<Item = &String>> { pub fn created(&mut self, id: &str) -> crate::Result<Email> {
if let Some(result) = self.created.as_mut().and_then(|r| r.remove(id)) {
Ok(result)
} else if let Some(error) = self.not_created.as_mut().and_then(|r| r.remove(id)) {
Err(error.to_string_error().into())
} else {
Err(Error::Internal(format!("Id {} not found.", id)))
}
}
pub fn created_ids(&self) -> Option<impl Iterator<Item = &String>> {
self.created.as_ref().map(|map| map.keys()) self.created.as_ref().map(|map| map.keys())
} }
pub fn not_created(&self) -> Option<impl Iterator<Item = &String>> { pub fn not_created_ids(&self) -> Option<impl Iterator<Item = &String>> {
self.not_created.as_ref().map(|map| map.keys()) 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,5 @@
pub mod get; pub mod get;
pub mod helpers;
pub mod import; pub mod import;
pub mod parse; pub mod parse;
pub mod query; pub mod query;
@ -7,7 +8,10 @@ pub mod set;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::{
collections::HashMap,
fmt::{self, Display, Formatter},
};
use crate::{core::request::ResultReference, Get}; use crate::{core::request::ResultReference, Get};
@ -318,7 +322,39 @@ pub enum BodyProperty {
SubParts, SubParts,
} }
#[derive(Debug, Clone, Deserialize)] impl Display for Property {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Property::Id => write!(f, "id"),
Property::BlobId => write!(f, "blobId"),
Property::ThreadId => write!(f, "threadId"),
Property::MailboxIds => write!(f, "mailboxIds"),
Property::Keywords => write!(f, "keywords"),
Property::Size => write!(f, "size"),
Property::ReceivedAt => write!(f, "receivedAt"),
Property::MessageId => write!(f, "messageId"),
Property::InReplyTo => write!(f, "inReplyTo"),
Property::References => write!(f, "references"),
Property::Sender => write!(f, "sender"),
Property::From => write!(f, "from"),
Property::To => write!(f, "to"),
Property::Cc => write!(f, "cc"),
Property::Bcc => write!(f, "bcc"),
Property::ReplyTo => write!(f, "replyTo"),
Property::Subject => write!(f, "subject"),
Property::SentAt => write!(f, "sentAt"),
Property::BodyStructure => write!(f, "bodyStructure"),
Property::BodyValues => write!(f, "bodyValues"),
Property::TextBody => write!(f, "textBody"),
Property::HtmlBody => write!(f, "htmlBody"),
Property::Attachments => write!(f, "attachments"),
Property::HasAttachment => write!(f, "hasAttachment"),
Property::Preview => write!(f, "preview"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MailCapabilities { pub struct MailCapabilities {
#[serde(rename = "maxMailboxesPerEmail")] #[serde(rename = "maxMailboxesPerEmail")]
max_mailboxes_per_email: Option<usize>, max_mailboxes_per_email: Option<usize>,
@ -339,7 +375,7 @@ pub struct MailCapabilities {
may_create_top_level_mailbox: bool, may_create_top_level_mailbox: bool,
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubmissionCapabilities { pub struct SubmissionCapabilities {
#[serde(rename = "maxDelayedSend")] #[serde(rename = "maxDelayedSend")]
max_delayed_send: usize, max_delayed_send: usize,

View File

@ -2,7 +2,7 @@ pub mod get;
pub mod query; pub mod query;
pub mod set; pub mod set;
use std::collections::HashMap; use std::{collections::HashMap, fmt::Display};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -149,3 +149,20 @@ pub enum Property {
#[serde(rename = "mdnBlobIds")] #[serde(rename = "mdnBlobIds")]
MdnBlobIds, MdnBlobIds,
} }
impl Display for Property {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Property::Id => write!(f, "id"),
Property::IdentityId => write!(f, "identityId"),
Property::EmailId => write!(f, "emailId"),
Property::ThreadId => write!(f, "threadId"),
Property::Envelope => write!(f, "envelope"),
Property::SendAt => write!(f, "sendAt"),
Property::UndoStatus => write!(f, "undoStatus"),
Property::DeliveryStatus => write!(f, "deliveryStatus"),
Property::DsnBlobIds => write!(f, "dsnBlobIds"),
Property::MdnBlobIds => write!(f, "mdnBlobIds"),
}
}
}

View File

@ -1,6 +1,8 @@
pub mod get; pub mod get;
pub mod set; pub mod set;
use std::fmt::Display;
use crate::core::set::list_not_set; use crate::core::set::list_not_set;
use crate::{email::EmailAddress, Get}; use crate::{email::EmailAddress, Get};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -65,3 +67,18 @@ pub enum Property {
#[serde(rename = "mayDelete")] #[serde(rename = "mayDelete")]
MayDelete, MayDelete,
} }
impl Display for Property {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Property::Id => write!(f, "id"),
Property::Name => write!(f, "name"),
Property::Email => write!(f, "email"),
Property::ReplyTo => write!(f, "replyTo"),
Property::Bcc => write!(f, "bcc"),
Property::TextSignature => write!(f, "textSignature"),
Property::HtmlSignature => write!(f, "htmlSignature"),
Property::MayDelete => write!(f, "mayDelete"),
}
}
}

View File

@ -1,4 +1,6 @@
use crate::core::error::MethodError;
use crate::core::error::ProblemDetails; use crate::core::error::ProblemDetails;
use crate::core::set::SetError;
use std::{collections::HashMap, fmt::Display}; use std::{collections::HashMap, fmt::Display};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -130,12 +132,15 @@ pub struct Set;
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error { pub enum Error {
Transport(reqwest::Error), Transport(reqwest::Error),
Parse(serde_json::Error), Parse(serde_json::Error),
Internal(String), Internal(String),
Problem(ProblemDetails), Problem(ProblemDetails),
ServerError(String), Server(String),
Method(MethodError),
Set(SetError<String>),
} }
impl From<reqwest::Error> for Error { impl From<reqwest::Error> for Error {
@ -150,6 +155,24 @@ impl From<serde_json::Error> for Error {
} }
} }
impl From<MethodError> for Error {
fn from(e: MethodError) -> Self {
Error::Method(e)
}
}
impl From<SetError<String>> for Error {
fn from(e: SetError<String>) -> Self {
Error::Set(e)
}
}
impl From<&str> for Error {
fn from(s: &str) -> Self {
Error::Internal(s.to_string())
}
}
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
@ -157,7 +180,9 @@ impl Display for Error {
Error::Parse(e) => write!(f, "Parse error: {}", e), Error::Parse(e) => write!(f, "Parse error: {}", e),
Error::Internal(e) => write!(f, "Internal error: {}", e), Error::Internal(e) => write!(f, "Internal error: {}", e),
Error::Problem(e) => write!(f, "Problem details: {}", e), Error::Problem(e) => write!(f, "Problem details: {}", e),
Error::ServerError(e) => write!(f, "Server error: {}", e), Error::Server(e) => write!(f, "Server error: {}", e),
Error::Method(e) => write!(f, "Method error: {}", e),
Error::Set(e) => write!(f, "Set error: {}", e),
} }
} }
} }

130
src/mailbox/helpers.rs Normal file
View File

@ -0,0 +1,130 @@
use crate::{
client::Client,
core::{
query::{Comparator, Filter, QueryResponse},
response::{MailboxGetResponse, MailboxSetResponse},
set::Create,
},
};
use super::{Mailbox, Property, Role};
impl Client {
pub async fn mailbox_create(
&mut self,
name: impl Into<String>,
parent_id: Option<impl Into<String>>,
role: Role,
) -> crate::Result<Mailbox> {
let mut request = self.build();
let id = request
.set_mailbox()
.create()
.name(name)
.role(role)
.parent_id(parent_id)
.create_id()
.unwrap();
request
.send_single::<MailboxSetResponse>()
.await?
.created(&id)
}
pub async fn mailbox_rename(
&mut self,
id: &str,
name: impl Into<String>,
) -> crate::Result<Option<Mailbox>> {
let mut request = self.build();
request.set_mailbox().update(id).name(name);
request
.send_single::<MailboxSetResponse>()
.await?
.updated(id)
}
pub async fn mailbox_move(
&mut self,
id: &str,
parent_id: Option<impl Into<String>>,
) -> crate::Result<Option<Mailbox>> {
let mut request = self.build();
request.set_mailbox().update(id).parent_id(parent_id);
request
.send_single::<MailboxSetResponse>()
.await?
.updated(id)
}
pub async fn mailbox_update_role(
&mut self,
id: &str,
role: Role,
) -> crate::Result<Option<Mailbox>> {
let mut request = self.build();
request.set_mailbox().update(id).role(role);
request
.send_single::<MailboxSetResponse>()
.await?
.updated(id)
}
pub async fn mailbox_update_sort_order(
&mut self,
id: &str,
sort_order: u32,
) -> crate::Result<Option<Mailbox>> {
let mut request = self.build();
request.set_mailbox().update(id).sort_order(sort_order);
request
.send_single::<MailboxSetResponse>()
.await?
.updated(id)
}
pub async fn mailbox_destroy(&mut self, id: &str, delete_emails: bool) -> crate::Result<()> {
let mut request = self.build();
request
.set_mailbox()
.destroy([id])
.arguments()
.on_destroy_remove_emails(delete_emails);
request
.send_single::<MailboxSetResponse>()
.await?
.destroyed(id)
}
pub async fn mailbox_get(
&mut self,
id: &str,
properties: Option<Vec<Property>>,
) -> crate::Result<Option<Mailbox>> {
let mut request = self.build();
let get_request = request.get_mailbox().ids([id]);
if let Some(properties) = properties {
get_request.properties(properties.into_iter());
}
request
.send_single::<MailboxGetResponse>()
.await
.map(|mut r| r.unwrap_list().pop())
}
pub async fn mailbox_query(
&mut self,
filter: Option<impl Into<Filter<super::query::Filter>>>,
sort: Option<Vec<Comparator<super::query::Comparator>>>,
) -> crate::Result<QueryResponse> {
let mut request = self.build();
let query_request = request.query_mailbox();
if let Some(filter) = filter {
query_request.filter(filter);
}
if let Some(sort) = sort {
query_request.sort(sort.into_iter());
}
request.send_single::<QueryResponse>().await
}
}

View File

@ -1,7 +1,10 @@
pub mod get; pub mod get;
pub mod helpers;
pub mod query; pub mod query;
pub mod set; pub mod set;
use std::fmt::Display;
use crate::core::set::string_not_set; use crate::core::set::string_not_set;
use crate::mailbox::set::role_not_set; use crate::mailbox::set::role_not_set;
use crate::Get; use crate::Get;
@ -10,7 +13,8 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Default)] #[derive(Debug, Clone, Serialize, Default)]
pub struct SetArguments { pub struct SetArguments {
#[serde(rename = "onDestroyRemoveEmails")] #[serde(rename = "onDestroyRemoveEmails")]
on_destroy_remove_emails: bool, #[serde(skip_serializing_if = "Option::is_none")]
on_destroy_remove_emails: Option<bool>,
} }
#[derive(Debug, Clone, Serialize, Default)] #[derive(Debug, Clone, Serialize, Default)]
@ -149,6 +153,24 @@ pub enum Property {
IsSubscribed, IsSubscribed,
} }
impl Display for Property {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Property::Id => write!(f, "id"),
Property::Name => write!(f, "name"),
Property::ParentId => write!(f, "parentId"),
Property::Role => write!(f, "role"),
Property::SortOrder => write!(f, "sortOrder"),
Property::TotalEmails => write!(f, "totalEmails"),
Property::UnreadEmails => write!(f, "unreadEmails"),
Property::TotalThreads => write!(f, "totalThreads"),
Property::UnreadThreads => write!(f, "unreadThreads"),
Property::MyRights => write!(f, "myRights"),
Property::IsSubscribed => write!(f, "isSubscribed"),
}
}
}
impl ChangesResponse { impl ChangesResponse {
pub fn updated_properties(&self) -> Option<&[Property]> { pub fn updated_properties(&self) -> Option<&[Property]> {
self.updated_properties.as_deref() self.updated_properties.as_deref()

View File

@ -58,7 +58,7 @@ impl Create for Mailbox<Set> {
impl SetArguments { impl SetArguments {
pub fn on_destroy_remove_emails(&mut self, value: bool) -> &mut Self { pub fn on_destroy_remove_emails(&mut self, value: bool) -> &mut Self {
self.on_destroy_remove_emails = value; self.on_destroy_remove_emails = value.into();
self self
} }
} }

View File

@ -1,6 +1,8 @@
pub mod get; pub mod get;
pub mod set; pub mod set;
use std::fmt::Display;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -62,6 +64,20 @@ pub enum Property {
Types, Types,
} }
impl Display for Property {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Property::Id => write!(f, "id"),
Property::DeviceClientId => write!(f, "deviceClientId"),
Property::Url => write!(f, "url"),
Property::Keys => write!(f, "keys"),
Property::VerificationCode => write!(f, "verificationCode"),
Property::Expires => write!(f, "expires"),
Property::Types => write!(f, "types"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Keys { pub struct Keys {
p256dh: String, p256dh: String,

View File

@ -64,9 +64,4 @@ impl Keys {
auth: base64::encode_config(&auth, base64::URL_SAFE), auth: base64::encode_config(&auth, base64::URL_SAFE),
} }
} }
pub fn generate() -> Option<Self> {
let (p256dh, auth) = ece::generate_keypair_and_auth_secret().ok()?;
Self::new(&p256dh.pub_as_raw().ok()?, &auth).into()
}
} }

View File

@ -1,6 +1,8 @@
pub mod get; pub mod get;
pub mod set; pub mod set;
use std::fmt::Display;
use crate::core::set::date_not_set; use crate::core::set::date_not_set;
use crate::core::set::string_not_set; use crate::core::set::string_not_set;
use crate::Get; use crate::Get;
@ -61,3 +63,17 @@ pub enum Property {
#[serde(rename = "htmlBody")] #[serde(rename = "htmlBody")]
HtmlBody, HtmlBody,
} }
impl Display for Property {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Property::Id => write!(f, "id"),
Property::IsEnabled => write!(f, "isEnabled"),
Property::FromDate => write!(f, "fromDate"),
Property::ToDate => write!(f, "toDate"),
Property::Subject => write!(f, "subject"),
Property::TextBody => write!(f, "textBody"),
Property::HtmlBody => write!(f, "htmlBody"),
}
}
}