Complete implementation (untested) except SearchSnippet and EventSource.
parent
17cecbdb63
commit
e10834ecaa
|
@ -0,0 +1,53 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use reqwest::header::CONTENT_TYPE;
|
||||||
|
|
||||||
|
use crate::{client::Client, core::session::URLPart};
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub async fn download(&self, account_id: &str, blob_id: &str) -> crate::Result<Vec<u8>> {
|
||||||
|
let mut download_url = String::with_capacity(
|
||||||
|
self.session().download_url().len() + account_id.len() + blob_id.len(),
|
||||||
|
);
|
||||||
|
|
||||||
|
for part in self.download_url() {
|
||||||
|
match part {
|
||||||
|
URLPart::Value(value) => {
|
||||||
|
download_url.push_str(value);
|
||||||
|
}
|
||||||
|
URLPart::Parameter(param) => match param {
|
||||||
|
super::URLParameter::AccountId => {
|
||||||
|
download_url.push_str(account_id);
|
||||||
|
}
|
||||||
|
super::URLParameter::BlobId => {
|
||||||
|
download_url.push_str(blob_id);
|
||||||
|
}
|
||||||
|
super::URLParameter::Name => {
|
||||||
|
download_url.push_str("none");
|
||||||
|
}
|
||||||
|
super::URLParameter::Type => {
|
||||||
|
download_url.push_str("application/octet-stream");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut headers = self.headers().clone();
|
||||||
|
headers.remove(CONTENT_TYPE);
|
||||||
|
|
||||||
|
Client::handle_error(
|
||||||
|
reqwest::Client::builder()
|
||||||
|
.timeout(Duration::from_millis(self.timeout()))
|
||||||
|
.default_headers(headers)
|
||||||
|
.build()?
|
||||||
|
.get(download_url)
|
||||||
|
.send()
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.bytes()
|
||||||
|
.await
|
||||||
|
.map(|bytes| bytes.to_vec())
|
||||||
|
.map_err(|err| err.into())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +1,24 @@
|
||||||
|
use crate::core::session::URLParser;
|
||||||
|
|
||||||
pub mod copy;
|
pub mod copy;
|
||||||
|
pub mod download;
|
||||||
|
pub mod upload;
|
||||||
|
|
||||||
|
pub enum URLParameter {
|
||||||
|
AccountId,
|
||||||
|
BlobId,
|
||||||
|
Name,
|
||||||
|
Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl URLParser for URLParameter {
|
||||||
|
fn parse(value: &str) -> Option<Self> {
|
||||||
|
match value {
|
||||||
|
"accountId" => Some(URLParameter::AccountId),
|
||||||
|
"blobId" => Some(URLParameter::BlobId),
|
||||||
|
"name" => Some(URLParameter::Name),
|
||||||
|
"type" => Some(URLParameter::Type),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use reqwest::header::CONTENT_TYPE;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::{client::Client, core::session::URLPart};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct UploadResponse {
|
||||||
|
#[serde(rename = "accountId")]
|
||||||
|
account_id: String,
|
||||||
|
|
||||||
|
#[serde(rename = "blobId")]
|
||||||
|
blob_id: String,
|
||||||
|
|
||||||
|
#[serde(rename = "type")]
|
||||||
|
type_: String,
|
||||||
|
|
||||||
|
#[serde(rename = "size")]
|
||||||
|
size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub async fn upload(
|
||||||
|
&self,
|
||||||
|
account_id: &str,
|
||||||
|
content_type: Option<&str>,
|
||||||
|
blob: Vec<u8>,
|
||||||
|
) -> crate::Result<UploadResponse> {
|
||||||
|
let mut upload_url =
|
||||||
|
String::with_capacity(self.session().upload_url().len() + account_id.len());
|
||||||
|
|
||||||
|
for part in self.upload_url() {
|
||||||
|
match part {
|
||||||
|
URLPart::Value(value) => {
|
||||||
|
upload_url.push_str(value);
|
||||||
|
}
|
||||||
|
URLPart::Parameter(param) => {
|
||||||
|
if let super::URLParameter::AccountId = param {
|
||||||
|
upload_url.push_str(account_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serde_json::from_slice::<UploadResponse>(
|
||||||
|
&Client::handle_error(
|
||||||
|
reqwest::Client::builder()
|
||||||
|
.timeout(Duration::from_millis(self.timeout()))
|
||||||
|
.default_headers(self.headers().clone())
|
||||||
|
.build()?
|
||||||
|
.post(upload_url)
|
||||||
|
.header(
|
||||||
|
CONTENT_TYPE,
|
||||||
|
content_type.unwrap_or("application/octet-stream"),
|
||||||
|
)
|
||||||
|
.body(blob)
|
||||||
|
.send()
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.bytes()
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
.map_err(|err| err.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UploadResponse {
|
||||||
|
pub fn account_id(&self) -> &str {
|
||||||
|
&self.account_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blob_id(&self) -> &str {
|
||||||
|
&self.blob_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content_type(&self) -> &str {
|
||||||
|
&self.type_
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
}
|
204
src/client.rs
204
src/client.rs
|
@ -1,36 +1,226 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::core::request::Request;
|
use reqwest::{
|
||||||
|
header::{self},
|
||||||
|
Response,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
blob,
|
||||||
|
core::{
|
||||||
|
request::Request,
|
||||||
|
session::{Session, URLPart},
|
||||||
|
},
|
||||||
|
event_source, Error,
|
||||||
|
};
|
||||||
|
|
||||||
const DEFAULT_TIMEOUT_MS: u64 = 10 * 1000;
|
const DEFAULT_TIMEOUT_MS: u64 = 10 * 1000;
|
||||||
|
static USER_AGENT: &str = concat!("stalwart-jmap/", env!("CARGO_PKG_VERSION"));
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
client: reqwest::ClientBuilder,
|
session: Session,
|
||||||
|
session_url: String,
|
||||||
|
upload_url: Vec<URLPart<blob::URLParameter>>,
|
||||||
|
download_url: Vec<URLPart<blob::URLParameter>>,
|
||||||
|
event_source_url: Vec<URLPart<event_source::URLParameter>>,
|
||||||
|
timeout: u64,
|
||||||
|
headers: header::HeaderMap,
|
||||||
default_account_id: String,
|
default_account_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn connect(url: &str) -> Self {
|
pub async fn connect(url: &str) -> crate::Result<Self> {
|
||||||
Client {
|
let mut headers = header::HeaderMap::new();
|
||||||
client: reqwest::Client::builder().timeout(Duration::from_millis(DEFAULT_TIMEOUT_MS)),
|
headers.insert(
|
||||||
default_account_id: "co".to_string(),
|
header::USER_AGENT,
|
||||||
|
header::HeaderValue::from_static(USER_AGENT),
|
||||||
|
);
|
||||||
|
headers.insert(
|
||||||
|
header::AUTHORIZATION,
|
||||||
|
header::HeaderValue::from_static("Basic test"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let session: Session = serde_json::from_slice(
|
||||||
|
&Client::handle_error(
|
||||||
|
reqwest::Client::builder()
|
||||||
|
.timeout(Duration::from_millis(DEFAULT_TIMEOUT_MS))
|
||||||
|
.default_headers(headers.clone())
|
||||||
|
.build()?
|
||||||
|
.get(url)
|
||||||
|
.send()
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.bytes()
|
||||||
|
.await?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let default_account_id = session
|
||||||
|
.primary_accounts()
|
||||||
|
.next()
|
||||||
|
.map(|a| a.0.to_string())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
headers.insert(
|
||||||
|
header::CONTENT_TYPE,
|
||||||
|
header::HeaderValue::from_static("application/json"),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Client {
|
||||||
|
download_url: URLPart::parse(session.download_url())?,
|
||||||
|
upload_url: URLPart::parse(session.upload_url())?,
|
||||||
|
event_source_url: URLPart::parse(session.event_source_url())?,
|
||||||
|
session,
|
||||||
|
session_url: url.to_string(),
|
||||||
|
timeout: DEFAULT_TIMEOUT_MS,
|
||||||
|
headers,
|
||||||
|
default_account_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_timeout(&mut self, timeout: u64) {
|
||||||
|
self.timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn timeout(&self) -> u64 {
|
||||||
|
self.timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session(&self) -> &Session {
|
||||||
|
&self.session
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn headers(&self) -> &header::HeaderMap {
|
||||||
|
&self.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_session(&mut self, new_state: &str) -> crate::Result<()> {
|
||||||
|
if new_state != self.session.state() {
|
||||||
|
let session: Session = serde_json::from_slice(
|
||||||
|
&Client::handle_error(
|
||||||
|
reqwest::Client::builder()
|
||||||
|
.timeout(Duration::from_millis(DEFAULT_TIMEOUT_MS))
|
||||||
|
.default_headers(self.headers.clone())
|
||||||
|
.build()?
|
||||||
|
.get(&self.session_url)
|
||||||
|
.send()
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.bytes()
|
||||||
|
.await?,
|
||||||
|
)?;
|
||||||
|
self.download_url = URLPart::parse(session.download_url())?;
|
||||||
|
self.upload_url = URLPart::parse(session.upload_url())?;
|
||||||
|
self.event_source_url = URLPart::parse(session.event_source_url())?;
|
||||||
|
self.session = session;
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_default_account_id(&mut self, defaul_account_id: impl Into<String>) {
|
||||||
|
self.default_account_id = defaul_account_id.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_account_id(&self) -> &str {
|
pub fn default_account_id(&self) -> &str {
|
||||||
&self.default_account_id
|
&self.default_account_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request(&self) -> Request<'_> {
|
pub fn request(&mut self) -> Request<'_> {
|
||||||
Request::new(self)
|
Request::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn download_url(&self) -> &[URLPart<blob::URLParameter>] {
|
||||||
|
&self.download_url
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn upload_url(&self) -> &[URLPart<blob::URLParameter>] {
|
||||||
|
&self.upload_url
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event_source_url(&self) -> &[URLPart<event_source::URLParameter>] {
|
||||||
|
&self.event_source_url
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn handle_error(response: Response) -> crate::Result<Response> {
|
||||||
|
if response.status().is_success() {
|
||||||
|
Ok(response)
|
||||||
|
} else if let Some(b"application/problem+json") = response
|
||||||
|
.headers()
|
||||||
|
.get(header::CONTENT_TYPE)
|
||||||
|
.map(|h| h.as_bytes())
|
||||||
|
{
|
||||||
|
Err(Error::Problem(serde_json::from_slice(
|
||||||
|
&response.bytes().await?,
|
||||||
|
)?))
|
||||||
|
} else {
|
||||||
|
Err(Error::ServerError(format!("{}", response.status())))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::core::response::Response;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize() {
|
fn test_serialize() {
|
||||||
|
let r: Response = serde_json::from_slice(
|
||||||
|
br#"{"sessionState": "123", "methodResponses": [[ "Email/query", {
|
||||||
|
"accountId": "A1",
|
||||||
|
"queryState": "abcdefg",
|
||||||
|
"canCalculateChanges": true,
|
||||||
|
"position": 0,
|
||||||
|
"total": 101,
|
||||||
|
"ids": [ "msg1023", "msg223", "msg110", "msg93", "msg91",
|
||||||
|
"msg38", "msg36", "msg33", "msg11", "msg1" ]
|
||||||
|
}, "t0" ],
|
||||||
|
[ "Email/get", {
|
||||||
|
"accountId": "A1",
|
||||||
|
"state": "123456",
|
||||||
|
"list": [{
|
||||||
|
"id": "msg1023",
|
||||||
|
"threadId": "trd194"
|
||||||
|
}, {
|
||||||
|
"id": "msg223",
|
||||||
|
"threadId": "trd114"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"notFound": []
|
||||||
|
}, "t1" ],
|
||||||
|
[ "Thread/get", {
|
||||||
|
"accountId": "A1",
|
||||||
|
"state": "123456",
|
||||||
|
"list": [{
|
||||||
|
"id": "trd194",
|
||||||
|
"emailIds": [ "msg1020", "msg1021", "msg1023" ]
|
||||||
|
}, {
|
||||||
|
"id": "trd114",
|
||||||
|
"emailIds": [ "msg201", "msg223" ]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"notFound": []
|
||||||
|
}, "t2" ]]}"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("{:?}", r);
|
||||||
|
|
||||||
|
/*let mut client = Client::connect("coco");
|
||||||
|
let mut request = client.request();
|
||||||
|
|
||||||
|
let set = request.set_email();
|
||||||
|
set.create().from(["pepe"]).subject("coco");
|
||||||
|
set.update("id").keyword("keyword", true);
|
||||||
|
set.destroy(["1", "2"]);
|
||||||
|
|
||||||
|
let ref_ = request.result_reference("/pepe/1");
|
||||||
|
|
||||||
|
let get = request.get_email();
|
||||||
|
get.ids_ref(ref_);
|
||||||
|
|
||||||
|
println!("{}", serde_json::to_string_pretty(&request).unwrap());*/
|
||||||
|
|
||||||
/*let mut client = Client::connect("coco");
|
/*let mut client = Client::connect("coco");
|
||||||
|
|
||||||
client.request().email_set().create(
|
client.request().email_set().create(
|
||||||
|
|
|
@ -4,9 +4,12 @@ use serde::{Deserialize, Serialize};
|
||||||
pub struct ChangesRequest {
|
pub struct ChangesRequest {
|
||||||
#[serde(rename = "accountId")]
|
#[serde(rename = "accountId")]
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
||||||
#[serde(rename = "sinceState")]
|
#[serde(rename = "sinceState")]
|
||||||
since_state: String,
|
since_state: String,
|
||||||
|
|
||||||
#[serde(rename = "maxChanges")]
|
#[serde(rename = "maxChanges")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
max_changes: Option<usize>,
|
max_changes: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,14 +17,20 @@ pub struct ChangesRequest {
|
||||||
pub struct ChangesResponse<A> {
|
pub struct ChangesResponse<A> {
|
||||||
#[serde(rename = "accountId")]
|
#[serde(rename = "accountId")]
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
||||||
#[serde(rename = "oldState")]
|
#[serde(rename = "oldState")]
|
||||||
old_state: String,
|
old_state: String,
|
||||||
|
|
||||||
#[serde(rename = "newState")]
|
#[serde(rename = "newState")]
|
||||||
new_state: String,
|
new_state: String,
|
||||||
|
|
||||||
#[serde(rename = "hasMoreChanges")]
|
#[serde(rename = "hasMoreChanges")]
|
||||||
has_more_changes: bool,
|
has_more_changes: bool,
|
||||||
|
|
||||||
created: Vec<String>,
|
created: Vec<String>,
|
||||||
|
|
||||||
updated: Vec<String>,
|
updated: Vec<String>,
|
||||||
|
|
||||||
destroyed: Vec<String>,
|
destroyed: Vec<String>,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
|
|
@ -2,20 +2,22 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::set::SetError;
|
use super::set::{Create, SetError};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct CopyRequest<T> {
|
pub struct CopyRequest<T: Create> {
|
||||||
#[serde(rename = "fromAccountId")]
|
#[serde(rename = "fromAccountId")]
|
||||||
from_account_id: String,
|
from_account_id: String,
|
||||||
|
|
||||||
#[serde(rename = "ifFromInState")]
|
#[serde(rename = "ifFromInState")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
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")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
if_in_state: Option<String>,
|
if_in_state: Option<String>,
|
||||||
|
|
||||||
#[serde(rename = "create")]
|
#[serde(rename = "create")]
|
||||||
|
@ -25,6 +27,7 @@ pub struct CopyRequest<T> {
|
||||||
on_success_destroy_original: bool,
|
on_success_destroy_original: bool,
|
||||||
|
|
||||||
#[serde(rename = "destroyFromIfInState")]
|
#[serde(rename = "destroyFromIfInState")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
destroy_from_if_in_state: Option<String>,
|
destroy_from_if_in_state: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,19 +35,24 @@ pub struct CopyRequest<T> {
|
||||||
pub struct CopyResponse<T, U> {
|
pub struct CopyResponse<T, U> {
|
||||||
#[serde(rename = "fromAccountId")]
|
#[serde(rename = "fromAccountId")]
|
||||||
from_account_id: String,
|
from_account_id: String,
|
||||||
|
|
||||||
#[serde(rename = "accountId")]
|
#[serde(rename = "accountId")]
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
||||||
#[serde(rename = "oldState")]
|
#[serde(rename = "oldState")]
|
||||||
old_state: Option<String>,
|
old_state: Option<String>,
|
||||||
|
|
||||||
#[serde(rename = "newState")]
|
#[serde(rename = "newState")]
|
||||||
new_state: String,
|
new_state: String,
|
||||||
|
|
||||||
#[serde(rename = "created")]
|
#[serde(rename = "created")]
|
||||||
created: Option<HashMap<String, T>>,
|
created: Option<HashMap<String, T>>,
|
||||||
|
|
||||||
#[serde(rename = "notCreated")]
|
#[serde(rename = "notCreated")]
|
||||||
not_created: Option<HashMap<String, SetError<U>>>,
|
not_created: Option<HashMap<String, SetError<U>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> CopyRequest<T> {
|
impl<T: Create> CopyRequest<T> {
|
||||||
pub fn new(from_account_id: String, account_id: String) -> Self {
|
pub fn new(from_account_id: String, account_id: String) -> Self {
|
||||||
CopyRequest {
|
CopyRequest {
|
||||||
from_account_id,
|
from_account_id,
|
||||||
|
@ -72,9 +80,12 @@ impl<T> CopyRequest<T> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(&mut self, id: impl Into<String>, value: T) -> &mut Self {
|
pub fn create(&mut self) -> &mut T {
|
||||||
self.create.insert(id.into(), value);
|
let create_id = self.create.len();
|
||||||
self
|
let create_id_str = format!("c{}", create_id);
|
||||||
|
self.create
|
||||||
|
.insert(create_id_str.clone(), T::new(create_id.into()));
|
||||||
|
self.create.get_mut(&create_id_str).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_success_destroy_original(&mut self, on_success_destroy_original: bool) -> &mut Self {
|
pub fn on_success_destroy_original(&mut self, on_success_destroy_original: bool) -> &mut Self {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -99,3 +101,28 @@ impl MethodError {
|
||||||
&self.p_type
|
&self.p_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for ProblemDetails {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self.p_type {
|
||||||
|
ProblemType::UnknownCapability => write!(f, "Unknown capability")?,
|
||||||
|
ProblemType::NotJSON => write!(f, "Not JSON")?,
|
||||||
|
ProblemType::NotRequest => write!(f, "Not request")?,
|
||||||
|
ProblemType::Limit => write!(f, "Limit")?,
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(status) = self.status {
|
||||||
|
write!(f, " (status {})", status)?
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(title) = &self.title {
|
||||||
|
write!(f, ": {}", title)?
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(detail) = &self.detail {
|
||||||
|
write!(f, ". Details: {}", detail)?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::request::ResultReference;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct GetRequest<T, A: Default> {
|
pub struct GetRequest<T, A: Default> {
|
||||||
#[serde(rename = "accountId")]
|
#[serde(rename = "accountId")]
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
ids: Option<Vec<String>>,
|
ids: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[serde(rename = "#ids")]
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
ids_ref: Option<ResultReference>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
properties: Option<Vec<T>>,
|
properties: Option<Vec<T>>,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
@ -15,8 +26,11 @@ pub struct GetRequest<T, A: Default> {
|
||||||
pub struct GetResponse<T> {
|
pub struct GetResponse<T> {
|
||||||
#[serde(rename = "accountId")]
|
#[serde(rename = "accountId")]
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
||||||
state: String,
|
state: String,
|
||||||
|
|
||||||
list: Vec<T>,
|
list: Vec<T>,
|
||||||
|
|
||||||
#[serde(rename = "notFound")]
|
#[serde(rename = "notFound")]
|
||||||
not_found: Vec<String>,
|
not_found: Vec<String>,
|
||||||
}
|
}
|
||||||
|
@ -26,6 +40,7 @@ impl<T, A: Default> GetRequest<T, A> {
|
||||||
GetRequest {
|
GetRequest {
|
||||||
account_id,
|
account_id,
|
||||||
ids: None,
|
ids: None,
|
||||||
|
ids_ref: None,
|
||||||
properties: None,
|
properties: None,
|
||||||
arguments: A::default(),
|
arguments: A::default(),
|
||||||
}
|
}
|
||||||
|
@ -42,6 +57,13 @@ impl<T, A: Default> GetRequest<T, A> {
|
||||||
V: Into<String>,
|
V: Into<String>,
|
||||||
{
|
{
|
||||||
self.ids = Some(ids.into_iter().map(|v| v.into()).collect());
|
self.ids = Some(ids.into_iter().map(|v| v.into()).collect());
|
||||||
|
self.ids_ref = None;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ids_ref(&mut self, reference: ResultReference) -> &mut Self {
|
||||||
|
self.ids_ref = reference.into();
|
||||||
|
self.ids = None;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,21 +6,25 @@ pub struct QueryRequest<F, S, A: Default> {
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
||||||
#[serde(rename = "filter")]
|
#[serde(rename = "filter")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
filter: Option<Filter<F>>,
|
filter: Option<Filter<F>>,
|
||||||
|
|
||||||
#[serde(rename = "sort")]
|
#[serde(rename = "sort")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
sort: Option<Vec<Comparator<S>>>,
|
sort: Option<Vec<Comparator<S>>>,
|
||||||
|
|
||||||
#[serde(rename = "position")]
|
#[serde(rename = "position")]
|
||||||
position: i32,
|
position: i32,
|
||||||
|
|
||||||
#[serde(rename = "anchor")]
|
#[serde(rename = "anchor")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
anchor: Option<String>,
|
anchor: Option<String>,
|
||||||
|
|
||||||
#[serde(rename = "anchorOffset")]
|
#[serde(rename = "anchorOffset")]
|
||||||
anchor_offset: i32,
|
anchor_offset: i32,
|
||||||
|
|
||||||
#[serde(rename = "limit")]
|
#[serde(rename = "limit")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
limit: Option<usize>,
|
limit: Option<usize>,
|
||||||
|
|
||||||
#[serde(rename = "calculateTotal")]
|
#[serde(rename = "calculateTotal")]
|
||||||
|
|
|
@ -6,16 +6,26 @@ use super::query::{Comparator, Filter};
|
||||||
pub struct QueryChangesRequest<F, S, A: Default> {
|
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")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
filter: Option<Filter<F>>,
|
filter: Option<Filter<F>>,
|
||||||
|
|
||||||
#[serde(rename = "sort")]
|
#[serde(rename = "sort")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
sort: Option<Vec<Comparator<S>>>,
|
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")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
max_changes: Option<usize>,
|
max_changes: Option<usize>,
|
||||||
|
|
||||||
#[serde(rename = "upToId")]
|
#[serde(rename = "upToId")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
up_to_id: Option<String>,
|
up_to_id: Option<String>,
|
||||||
|
|
||||||
#[serde(rename = "calculateTotal")]
|
#[serde(rename = "calculateTotal")]
|
||||||
calculate_total: bool,
|
calculate_total: bool,
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, time::Duration};
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
|
@ -17,17 +17,19 @@ use crate::{
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
changes::ChangesRequest, copy::CopyRequest, get::GetRequest, query::QueryRequest,
|
changes::ChangesRequest, copy::CopyRequest, get::GetRequest, query::QueryRequest,
|
||||||
query_changes::QueryChangesRequest, set::SetRequest,
|
query_changes::QueryChangesRequest, response::Response, set::SetRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
pub struct Request<'x> {
|
pub struct Request<'x> {
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
client: &'x Client,
|
client: &'x mut Client,
|
||||||
|
|
||||||
using: Vec<URI>,
|
using: Vec<URI>,
|
||||||
|
|
||||||
#[serde(rename = "methodCalls")]
|
#[serde(rename = "methodCalls")]
|
||||||
method_calls: Vec<(Method, Arguments, String)>,
|
method_calls: Vec<(Method, Arguments, String)>,
|
||||||
|
|
||||||
#[serde(rename = "createdIds")]
|
#[serde(rename = "createdIds")]
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
created_ids: Option<HashMap<String, String>>,
|
created_ids: Option<HashMap<String, String>>,
|
||||||
|
@ -37,7 +39,7 @@ pub struct Request<'x> {
|
||||||
pub struct ResultReference {
|
pub struct ResultReference {
|
||||||
#[serde(rename = "resultOf")]
|
#[serde(rename = "resultOf")]
|
||||||
result_of: String,
|
result_of: String,
|
||||||
name: String,
|
name: Method,
|
||||||
path: String,
|
path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,7 +394,7 @@ impl Arguments {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'x> Request<'x> {
|
impl<'x> Request<'x> {
|
||||||
pub fn new(client: &'x Client) -> Self {
|
pub fn new(client: &'x mut Client) -> Self {
|
||||||
Request {
|
Request {
|
||||||
using: vec![URI::Core, URI::Mail],
|
using: vec![URI::Core, URI::Mail],
|
||||||
method_calls: vec![],
|
method_calls: vec![],
|
||||||
|
@ -401,6 +403,26 @@ impl<'x> Request<'x> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send(&mut self) -> crate::Result<Response> {
|
||||||
|
let response: Response = serde_json::from_slice(
|
||||||
|
&Client::handle_error(
|
||||||
|
reqwest::Client::builder()
|
||||||
|
.timeout(Duration::from_millis(self.client.timeout()))
|
||||||
|
.default_headers(self.client.headers().clone())
|
||||||
|
.build()?
|
||||||
|
.post(self.client.session().api_url())
|
||||||
|
.body(serde_json::to_string(&self)?)
|
||||||
|
.send()
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.bytes()
|
||||||
|
.await?,
|
||||||
|
)?;
|
||||||
|
self.client.update_session(response.session_state()).await?;
|
||||||
|
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 {
|
||||||
let call_id = format!("s{}", self.method_calls.len());
|
let call_id = format!("s{}", self.method_calls.len());
|
||||||
self.method_calls.push((method, arguments, call_id));
|
self.method_calls.push((method, arguments, call_id));
|
||||||
|
@ -613,6 +635,9 @@ impl<'x> Request<'x> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_email_submission(&mut self) -> &mut GetRequest<email_submission::Property, ()> {
|
pub fn get_email_submission(&mut self) -> &mut GetRequest<email_submission::Property, ()> {
|
||||||
|
if !self.using.contains(&URI::Submission) {
|
||||||
|
self.using.push(URI::Submission);
|
||||||
|
}
|
||||||
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.client.default_account_id().to_string()),
|
||||||
|
@ -624,6 +649,9 @@ impl<'x> Request<'x> {
|
||||||
&mut self,
|
&mut self,
|
||||||
since_state: impl Into<String>,
|
since_state: impl Into<String>,
|
||||||
) -> &mut ChangesRequest {
|
) -> &mut ChangesRequest {
|
||||||
|
if !self.using.contains(&URI::Submission) {
|
||||||
|
self.using.push(URI::Submission);
|
||||||
|
}
|
||||||
self.add_method_call(
|
self.add_method_call(
|
||||||
Method::ChangesEmailSubmission,
|
Method::ChangesEmailSubmission,
|
||||||
Arguments::changes(
|
Arguments::changes(
|
||||||
|
@ -638,6 +666,9 @@ impl<'x> Request<'x> {
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> &mut QueryRequest<email_submission::query::Filter, email_submission::query::Comparator, ()>
|
) -> &mut QueryRequest<email_submission::query::Filter, email_submission::query::Comparator, ()>
|
||||||
{
|
{
|
||||||
|
if !self.using.contains(&URI::Submission) {
|
||||||
|
self.using.push(URI::Submission);
|
||||||
|
}
|
||||||
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.client.default_account_id().to_string()),
|
||||||
|
@ -653,6 +684,9 @@ impl<'x> Request<'x> {
|
||||||
email_submission::query::Comparator,
|
email_submission::query::Comparator,
|
||||||
(),
|
(),
|
||||||
> {
|
> {
|
||||||
|
if !self.using.contains(&URI::Submission) {
|
||||||
|
self.using.push(URI::Submission);
|
||||||
|
}
|
||||||
self.add_method_call(
|
self.add_method_call(
|
||||||
Method::QueryChangesEmailSubmission,
|
Method::QueryChangesEmailSubmission,
|
||||||
Arguments::email_submission_query_changes(
|
Arguments::email_submission_query_changes(
|
||||||
|
@ -666,6 +700,9 @@ impl<'x> Request<'x> {
|
||||||
pub fn set_email_submission(
|
pub fn set_email_submission(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> &mut SetRequest<EmailSubmission<Set>, email_submission::SetArguments> {
|
) -> &mut SetRequest<EmailSubmission<Set>, email_submission::SetArguments> {
|
||||||
|
if !self.using.contains(&URI::Submission) {
|
||||||
|
self.using.push(URI::Submission);
|
||||||
|
}
|
||||||
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.client.default_account_id().to_string()),
|
||||||
|
@ -674,6 +711,9 @@ impl<'x> Request<'x> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_vacation_response(&mut self) -> &mut GetRequest<vacation_response::Property, ()> {
|
pub fn get_vacation_response(&mut self) -> &mut GetRequest<vacation_response::Property, ()> {
|
||||||
|
if !self.using.contains(&URI::VacationResponse) {
|
||||||
|
self.using.push(URI::VacationResponse);
|
||||||
|
}
|
||||||
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.client.default_account_id().to_string()),
|
||||||
|
@ -682,10 +722,22 @@ impl<'x> Request<'x> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_vacation_response(&mut self) -> &mut SetRequest<VacationResponse<Set>, ()> {
|
pub fn set_vacation_response(&mut self) -> &mut SetRequest<VacationResponse<Set>, ()> {
|
||||||
|
if !self.using.contains(&URI::VacationResponse) {
|
||||||
|
self.using.push(URI::VacationResponse);
|
||||||
|
}
|
||||||
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.client.default_account_id().to_string()),
|
||||||
)
|
)
|
||||||
.vacation_response_set_mut()
|
.vacation_response_set_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn result_reference(&self, path: impl Into<String>) -> ResultReference {
|
||||||
|
let last_method = self.method_calls.last().unwrap();
|
||||||
|
ResultReference {
|
||||||
|
result_of: last_method.2.clone(),
|
||||||
|
name: last_method.0.clone(),
|
||||||
|
path: path.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,635 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::Method;
|
use crate::{
|
||||||
|
blob::copy::CopyBlobResponse,
|
||||||
|
email::{self, import::EmailImportResponse, parse::EmailParseResponse, Email},
|
||||||
|
email_submission::{self, EmailSubmission},
|
||||||
|
identity::{self, Identity},
|
||||||
|
mailbox::{self, Mailbox},
|
||||||
|
push_subscription::{self, PushSubscription},
|
||||||
|
thread::Thread,
|
||||||
|
vacation_response::{self, VacationResponse},
|
||||||
|
Get, Method,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
use super::{
|
||||||
|
changes::ChangesResponse, copy::CopyResponse, error::MethodError, get::GetResponse,
|
||||||
|
query::QueryResponse, query_changes::QueryChangesResponse, set::SetResponse,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
#[serde(rename = "methodResponses")]
|
#[serde(rename = "methodResponses")]
|
||||||
method_calls: Vec<(Method, Result, String)>,
|
method_responses: Vec<MethodResponse>,
|
||||||
|
|
||||||
#[serde(rename = "createdIds")]
|
#[serde(rename = "createdIds")]
|
||||||
created_ids: Option<HashMap<String, String>>,
|
created_ids: Option<HashMap<String, String>>,
|
||||||
|
|
||||||
#[serde(rename = "sessionState")]
|
#[serde(rename = "sessionState")]
|
||||||
session_state: String,
|
session_state: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize)]
|
impl Response {
|
||||||
pub struct Result {}
|
pub fn method_responses(&self) -> &[MethodResponse] {
|
||||||
|
self.method_responses.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn method_response(&self, id: &str) -> Option<&MethodResponse> {
|
||||||
|
self.method_responses
|
||||||
|
.iter()
|
||||||
|
.find(|response| response.call_id() == id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn created_ids(&self) -> Option<impl Iterator<Item = (&String, &String)>> {
|
||||||
|
self.created_ids.as_ref().map(|map| map.iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn session_state(&self) -> &str {
|
||||||
|
&self.session_state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum MethodResponse {
|
||||||
|
CopyBlob((CopyBlob, CopyBlobResponse, String)),
|
||||||
|
GetPushSubscription(
|
||||||
|
(
|
||||||
|
GetPushSubscription,
|
||||||
|
GetResponse<PushSubscription<Get>>,
|
||||||
|
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)),
|
||||||
|
QueryChangesMailbox((QueryChangesMailbox, QueryChangesResponse, String)),
|
||||||
|
SetMailbox(
|
||||||
|
(
|
||||||
|
SetMailbox,
|
||||||
|
SetResponse<Mailbox<Get>, mailbox::Property>,
|
||||||
|
String,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GetThread((GetThread, GetResponse<Thread>, String)),
|
||||||
|
ChangesThread((ChangesThread, ChangesResponse<()>, String)),
|
||||||
|
GetEmail((GetEmail, GetResponse<Email<Get>>, String)),
|
||||||
|
ChangesEmail((ChangesEmail, ChangesResponse<()>, String)),
|
||||||
|
QueryEmail((QueryEmail, QueryResponse, String)),
|
||||||
|
QueryChangesEmail((QueryChangesEmail, QueryChangesResponse, String)),
|
||||||
|
SetEmail((SetEmail, SetResponse<Email<Get>, email::Property>, String)),
|
||||||
|
CopyEmail((CopyEmail, CopyResponse<Email<Get>, email::Property>, String)),
|
||||||
|
ImportEmail((ImportEmail, EmailImportResponse, String)),
|
||||||
|
ParseEmail((ParseEmail, EmailParseResponse, String)),
|
||||||
|
GetSearchSnippet((GetSearchSnippet, GetResponse<String>, String)),
|
||||||
|
GetIdentity((GetIdentity, GetResponse<Identity<Get>>, String)),
|
||||||
|
ChangesIdentity((ChangesIdentity, ChangesResponse<()>, String)),
|
||||||
|
SetIdentity(
|
||||||
|
(
|
||||||
|
SetIdentity,
|
||||||
|
SetResponse<Identity<Get>, identity::Property>,
|
||||||
|
String,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GetEmailSubmission(
|
||||||
|
(
|
||||||
|
GetEmailSubmission,
|
||||||
|
GetResponse<EmailSubmission<Get>>,
|
||||||
|
String,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ChangesEmailSubmission((ChangesEmailSubmission, ChangesResponse<()>, String)),
|
||||||
|
QueryEmailSubmission((QueryEmailSubmission, QueryResponse, String)),
|
||||||
|
QueryChangesEmailSubmission((QueryChangesEmailSubmission, QueryChangesResponse, String)),
|
||||||
|
SetEmailSubmission(
|
||||||
|
(
|
||||||
|
SetEmailSubmission,
|
||||||
|
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)),
|
||||||
|
Error((Error, MethodError, String)),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MethodResponse {
|
||||||
|
pub fn call_id(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::CopyBlob((_, _, id)) => id,
|
||||||
|
Self::GetPushSubscription((_, _, id)) => id,
|
||||||
|
Self::SetPushSubscription((_, _, id)) => id,
|
||||||
|
Self::GetMailbox((_, _, id)) => id,
|
||||||
|
Self::ChangesMailbox((_, _, id)) => id,
|
||||||
|
Self::QueryMailbox((_, _, id)) => id,
|
||||||
|
Self::QueryChangesMailbox((_, _, id)) => id,
|
||||||
|
Self::SetMailbox((_, _, id)) => id,
|
||||||
|
Self::GetThread((_, _, id)) => id,
|
||||||
|
Self::ChangesThread((_, _, id)) => id,
|
||||||
|
Self::GetEmail((_, _, id)) => id,
|
||||||
|
Self::ChangesEmail((_, _, id)) => id,
|
||||||
|
Self::QueryEmail((_, _, id)) => id,
|
||||||
|
Self::QueryChangesEmail((_, _, id)) => id,
|
||||||
|
Self::SetEmail((_, _, id)) => id,
|
||||||
|
Self::CopyEmail((_, _, id)) => id,
|
||||||
|
Self::ImportEmail((_, _, id)) => id,
|
||||||
|
Self::ParseEmail((_, _, id)) => id,
|
||||||
|
Self::GetSearchSnippet((_, _, id)) => id,
|
||||||
|
Self::GetIdentity((_, _, id)) => id,
|
||||||
|
Self::ChangesIdentity((_, _, id)) => id,
|
||||||
|
Self::SetIdentity((_, _, id)) => id,
|
||||||
|
Self::GetEmailSubmission((_, _, id)) => id,
|
||||||
|
Self::ChangesEmailSubmission((_, _, id)) => id,
|
||||||
|
Self::QueryEmailSubmission((_, _, id)) => id,
|
||||||
|
Self::QueryChangesEmailSubmission((_, _, id)) => id,
|
||||||
|
Self::SetEmailSubmission((_, _, id)) => id,
|
||||||
|
Self::GetVacationResponse((_, _, id)) => id,
|
||||||
|
Self::SetVacationResponse((_, _, id)) => id,
|
||||||
|
Self::Echo((_, _, id)) => id,
|
||||||
|
Self::Error((_, _, id)) => id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_type(&self, type_: Method) -> bool {
|
||||||
|
matches!(
|
||||||
|
(self, type_),
|
||||||
|
(Self::CopyBlob(_), Method::CopyBlob)
|
||||||
|
| (Self::GetPushSubscription(_), Method::GetPushSubscription)
|
||||||
|
| (Self::SetPushSubscription(_), Method::SetPushSubscription)
|
||||||
|
| (Self::GetMailbox(_), Method::GetMailbox)
|
||||||
|
| (Self::ChangesMailbox(_), Method::ChangesMailbox)
|
||||||
|
| (Self::QueryMailbox(_), Method::QueryMailbox)
|
||||||
|
| (Self::QueryChangesMailbox(_), Method::QueryChangesMailbox)
|
||||||
|
| (Self::SetMailbox(_), Method::SetMailbox)
|
||||||
|
| (Self::GetThread(_), Method::GetThread)
|
||||||
|
| (Self::ChangesThread(_), Method::ChangesThread)
|
||||||
|
| (Self::GetEmail(_), Method::GetEmail)
|
||||||
|
| (Self::ChangesEmail(_), Method::ChangesEmail)
|
||||||
|
| (Self::QueryEmail(_), Method::QueryEmail)
|
||||||
|
| (Self::QueryChangesEmail(_), Method::QueryChangesEmail)
|
||||||
|
| (Self::SetEmail(_), Method::SetEmail)
|
||||||
|
| (Self::CopyEmail(_), Method::CopyEmail)
|
||||||
|
| (Self::ImportEmail(_), Method::ImportEmail)
|
||||||
|
| (Self::ParseEmail(_), Method::ParseEmail)
|
||||||
|
| (Self::GetSearchSnippet(_), Method::GetSearchSnippet)
|
||||||
|
| (Self::GetIdentity(_), Method::GetIdentity)
|
||||||
|
| (Self::ChangesIdentity(_), Method::ChangesIdentity)
|
||||||
|
| (Self::SetIdentity(_), Method::SetIdentity)
|
||||||
|
| (Self::GetEmailSubmission(_), Method::GetEmailSubmission)
|
||||||
|
| (
|
||||||
|
Self::ChangesEmailSubmission(_),
|
||||||
|
Method::ChangesEmailSubmission
|
||||||
|
)
|
||||||
|
| (Self::QueryEmailSubmission(_), Method::QueryEmailSubmission)
|
||||||
|
| (
|
||||||
|
Self::QueryChangesEmailSubmission(_),
|
||||||
|
Method::QueryChangesEmailSubmission
|
||||||
|
)
|
||||||
|
| (Self::SetEmailSubmission(_), Method::SetEmailSubmission)
|
||||||
|
| (Self::GetVacationResponse(_), Method::GetVacationResponse)
|
||||||
|
| (Self::SetVacationResponse(_), Method::SetVacationResponse)
|
||||||
|
| (Self::Echo(_), Method::Echo)
|
||||||
|
| (Self::Error(_), Method::Error)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_copy_copy(&self) -> Option<&CopyBlobResponse> {
|
||||||
|
match self {
|
||||||
|
Self::CopyBlob((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_get_push_subscription(&self) -> Option<&GetResponse<PushSubscription<Get>>> {
|
||||||
|
match self {
|
||||||
|
Self::GetPushSubscription((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_set_push_subscription(
|
||||||
|
&self,
|
||||||
|
) -> Option<&SetResponse<PushSubscription<Get>, push_subscription::Property>> {
|
||||||
|
match self {
|
||||||
|
Self::SetPushSubscription((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_get_mailbox(&self) -> Option<&GetResponse<Mailbox<Get>>> {
|
||||||
|
match self {
|
||||||
|
Self::GetMailbox((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_changes_mailbox(&self) -> Option<&ChangesResponse<mailbox::ChangesResponse>> {
|
||||||
|
match self {
|
||||||
|
Self::ChangesMailbox((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_query_mailbox(&self) -> Option<&QueryResponse> {
|
||||||
|
match self {
|
||||||
|
Self::QueryMailbox((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_query_changes_mailbox(&self) -> Option<&QueryChangesResponse> {
|
||||||
|
match self {
|
||||||
|
Self::QueryChangesMailbox((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_set_mailbox(&self) -> Option<&SetResponse<Mailbox<Get>, mailbox::Property>> {
|
||||||
|
match self {
|
||||||
|
Self::SetMailbox((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_get_thread(&self) -> Option<&GetResponse<Thread>> {
|
||||||
|
match self {
|
||||||
|
Self::GetThread((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_changes_thread(&self) -> Option<&ChangesResponse<()>> {
|
||||||
|
match self {
|
||||||
|
Self::ChangesThread((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_get_email(&self) -> Option<&GetResponse<Email>> {
|
||||||
|
match self {
|
||||||
|
Self::GetEmail((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_changes_email(&self) -> Option<&ChangesResponse<()>> {
|
||||||
|
match self {
|
||||||
|
Self::ChangesEmail((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_query_email(&self) -> Option<&QueryResponse> {
|
||||||
|
match self {
|
||||||
|
Self::QueryEmail((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_query_changes_email(&self) -> Option<&QueryChangesResponse> {
|
||||||
|
match self {
|
||||||
|
Self::QueryChangesEmail((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_set_email(&self) -> Option<&SetResponse<Email, email::Property>> {
|
||||||
|
match self {
|
||||||
|
Self::SetEmail((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_copy_email(&self) -> Option<&CopyResponse<Email<Get>, email::Property>> {
|
||||||
|
match self {
|
||||||
|
Self::CopyEmail((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_import_email(&self) -> Option<&EmailImportResponse> {
|
||||||
|
match self {
|
||||||
|
Self::ImportEmail((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_parse_email(&self) -> Option<&EmailParseResponse> {
|
||||||
|
match self {
|
||||||
|
Self::ParseEmail((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_get_search_snippet(&self) -> Option<&GetResponse<String>> {
|
||||||
|
match self {
|
||||||
|
Self::GetSearchSnippet((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_get_identity(&self) -> Option<&GetResponse<Identity>> {
|
||||||
|
match self {
|
||||||
|
Self::GetIdentity((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_changes_identity(&self) -> Option<&ChangesResponse<()>> {
|
||||||
|
match self {
|
||||||
|
Self::ChangesIdentity((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_set_identity(&self) -> Option<&SetResponse<Identity, identity::Property>> {
|
||||||
|
match self {
|
||||||
|
Self::SetIdentity((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_get_email_submission(&self) -> Option<&GetResponse<EmailSubmission>> {
|
||||||
|
match self {
|
||||||
|
Self::GetEmailSubmission((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_changes_email_submission(&self) -> Option<&ChangesResponse<()>> {
|
||||||
|
match self {
|
||||||
|
Self::ChangesEmailSubmission((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_set_email_submission(
|
||||||
|
&self,
|
||||||
|
) -> Option<&SetResponse<EmailSubmission, email_submission::Property>> {
|
||||||
|
match self {
|
||||||
|
Self::SetEmailSubmission((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_query_email_submission(&self) -> Option<&QueryResponse> {
|
||||||
|
match self {
|
||||||
|
Self::QueryEmailSubmission((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_query_changes_email_submission(&self) -> Option<&QueryChangesResponse> {
|
||||||
|
match self {
|
||||||
|
Self::QueryChangesEmailSubmission((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_get_vacation_response(&self) -> Option<&GetResponse<VacationResponse>> {
|
||||||
|
match self {
|
||||||
|
Self::GetVacationResponse((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_set_vacation_response(
|
||||||
|
&self,
|
||||||
|
) -> Option<&SetResponse<VacationResponse, vacation_response::Property>> {
|
||||||
|
match self {
|
||||||
|
Self::SetVacationResponse((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_echo(&self) -> Option<&serde_json::Value> {
|
||||||
|
match self {
|
||||||
|
Self::Echo((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_error(&self) -> Option<&MethodError> {
|
||||||
|
match self {
|
||||||
|
Self::Error((_, response, _)) => response.into(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_error(&self) -> bool {
|
||||||
|
matches!(self, Self::Error(_))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum Echo {
|
||||||
|
#[serde(rename = "Core/echo")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum CopyBlob {
|
||||||
|
#[serde(rename = "Blob/copy")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum GetPushSubscription {
|
||||||
|
#[serde(rename = "PushSubscription/get")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum SetPushSubscription {
|
||||||
|
#[serde(rename = "PushSubscription/set")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum GetMailbox {
|
||||||
|
#[serde(rename = "Mailbox/get")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum ChangesMailbox {
|
||||||
|
#[serde(rename = "Mailbox/changes")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum QueryMailbox {
|
||||||
|
#[serde(rename = "Mailbox/query")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum QueryChangesMailbox {
|
||||||
|
#[serde(rename = "Mailbox/queryChanges")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum SetMailbox {
|
||||||
|
#[serde(rename = "Mailbox/set")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum GetThread {
|
||||||
|
#[serde(rename = "Thread/get")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum ChangesThread {
|
||||||
|
#[serde(rename = "Thread/changes")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum GetEmail {
|
||||||
|
#[serde(rename = "Email/get")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum ChangesEmail {
|
||||||
|
#[serde(rename = "Email/changes")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum QueryEmail {
|
||||||
|
#[serde(rename = "Email/query")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum QueryChangesEmail {
|
||||||
|
#[serde(rename = "Email/queryChanges")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum SetEmail {
|
||||||
|
#[serde(rename = "Email/set")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum CopyEmail {
|
||||||
|
#[serde(rename = "Email/copy")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum ImportEmail {
|
||||||
|
#[serde(rename = "Email/import")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum ParseEmail {
|
||||||
|
#[serde(rename = "Email/parse")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum GetSearchSnippet {
|
||||||
|
#[serde(rename = "SearchSnippet/get")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum GetIdentity {
|
||||||
|
#[serde(rename = "Identity/get")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum ChangesIdentity {
|
||||||
|
#[serde(rename = "Identity/changes")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum SetIdentity {
|
||||||
|
#[serde(rename = "Identity/set")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum GetEmailSubmission {
|
||||||
|
#[serde(rename = "EmailSubmission/get")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum ChangesEmailSubmission {
|
||||||
|
#[serde(rename = "EmailSubmission/changes")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum QueryEmailSubmission {
|
||||||
|
#[serde(rename = "EmailSubmission/query")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum QueryChangesEmailSubmission {
|
||||||
|
#[serde(rename = "EmailSubmission/queryChanges")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum SetEmailSubmission {
|
||||||
|
#[serde(rename = "EmailSubmission/set")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum GetVacationResponse {
|
||||||
|
#[serde(rename = "VacationResponse/get")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum SetVacationResponse {
|
||||||
|
#[serde(rename = "VacationResponse/set")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub enum Error {
|
||||||
|
#[serde(rename = "error")]
|
||||||
|
V,
|
||||||
|
}
|
||||||
|
|
|
@ -106,12 +106,8 @@ impl Session {
|
||||||
self.accounts.get(account)
|
self.accounts.get(account)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primary_accounts(&self) -> impl Iterator<Item = &String> {
|
pub fn primary_accounts(&self) -> impl Iterator<Item = (&String, &String)> {
|
||||||
self.primary_accounts.keys()
|
self.primary_accounts.iter()
|
||||||
}
|
|
||||||
|
|
||||||
pub fn primary_account(&self, account: &str) -> Option<&String> {
|
|
||||||
self.primary_accounts.get(account)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn username(&self) -> &str {
|
pub fn username(&self) -> &str {
|
||||||
|
@ -194,3 +190,51 @@ impl CoreCapabilities {
|
||||||
&self.collation_algorithms
|
&self.collation_algorithms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait URLParser: Sized {
|
||||||
|
fn parse(value: &str) -> Option<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum URLPart<T: URLParser> {
|
||||||
|
Value(String),
|
||||||
|
Parameter(T),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: URLParser> URLPart<T> {
|
||||||
|
pub fn parse(url: &str) -> crate::Result<Vec<URLPart<T>>> {
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
let mut buf = String::with_capacity(url.len());
|
||||||
|
let mut in_parameter = false;
|
||||||
|
|
||||||
|
for ch in url.chars() {
|
||||||
|
match ch {
|
||||||
|
'{' => {
|
||||||
|
if !buf.is_empty() {
|
||||||
|
parts.push(URLPart::Value(buf.clone()));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
in_parameter = true;
|
||||||
|
}
|
||||||
|
'}' => {
|
||||||
|
if in_parameter && !buf.is_empty() {
|
||||||
|
parts.push(URLPart::Parameter(T::parse(&buf).ok_or_else(|| {
|
||||||
|
crate::Error::Internal(format!(
|
||||||
|
"Invalid parameter '{}' in URL: {}",
|
||||||
|
buf, url
|
||||||
|
))
|
||||||
|
})?));
|
||||||
|
buf.clear();
|
||||||
|
} else {
|
||||||
|
return Err(crate::Error::Internal(format!("Invalid URL: {}", url)));
|
||||||
|
}
|
||||||
|
in_parameter = false;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
buf.push(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(parts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
139
src/core/set.rs
139
src/core/set.rs
|
@ -2,16 +2,31 @@ use chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::request::ResultReference;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct SetRequest<T, A: Default> {
|
pub struct SetRequest<T: Create, A: Default> {
|
||||||
#[serde(rename = "accountId")]
|
#[serde(rename = "accountId")]
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
||||||
#[serde(rename = "ifInState")]
|
#[serde(rename = "ifInState")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
if_in_state: Option<String>,
|
if_in_state: Option<String>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
create: Option<HashMap<String, T>>,
|
create: Option<HashMap<String, T>>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
update: Option<HashMap<String, T>>,
|
update: Option<HashMap<String, T>>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
destroy: Option<Vec<String>>,
|
destroy: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[serde(rename = "#destroy")]
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
destroy_ref: Option<ResultReference>,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
arguments: A,
|
arguments: A,
|
||||||
}
|
}
|
||||||
|
@ -20,20 +35,28 @@ pub struct SetRequest<T, A: Default> {
|
||||||
pub struct SetResponse<T, U> {
|
pub struct SetResponse<T, U> {
|
||||||
#[serde(rename = "accountId")]
|
#[serde(rename = "accountId")]
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
||||||
#[serde(rename = "oldState")]
|
#[serde(rename = "oldState")]
|
||||||
old_state: Option<String>,
|
old_state: Option<String>,
|
||||||
|
|
||||||
#[serde(rename = "newState")]
|
#[serde(rename = "newState")]
|
||||||
new_state: String,
|
new_state: String,
|
||||||
|
|
||||||
#[serde(rename = "created")]
|
#[serde(rename = "created")]
|
||||||
created: Option<HashMap<String, T>>,
|
created: Option<HashMap<String, T>>,
|
||||||
|
|
||||||
#[serde(rename = "updated")]
|
#[serde(rename = "updated")]
|
||||||
updated: Option<HashMap<String, Option<T>>>,
|
updated: Option<HashMap<String, Option<T>>>,
|
||||||
|
|
||||||
#[serde(rename = "destroyed")]
|
#[serde(rename = "destroyed")]
|
||||||
destroyed: Option<Vec<String>>,
|
destroyed: Option<Vec<String>>,
|
||||||
|
|
||||||
#[serde(rename = "notCreated")]
|
#[serde(rename = "notCreated")]
|
||||||
not_created: Option<HashMap<String, SetError<U>>>,
|
not_created: Option<HashMap<String, SetError<U>>>,
|
||||||
|
|
||||||
#[serde(rename = "notUpdated")]
|
#[serde(rename = "notUpdated")]
|
||||||
not_updated: Option<HashMap<String, SetError<U>>>,
|
not_updated: Option<HashMap<String, SetError<U>>>,
|
||||||
|
|
||||||
#[serde(rename = "notDestroyed")]
|
#[serde(rename = "notDestroyed")]
|
||||||
not_destroyed: Option<HashMap<String, SetError<U>>>,
|
not_destroyed: Option<HashMap<String, SetError<U>>>,
|
||||||
}
|
}
|
||||||
|
@ -94,23 +117,12 @@ pub enum SetErrorType {
|
||||||
CannotUnsend,
|
CannotUnsend,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_timestamp(timestamp: i64) -> DateTime<Utc> {
|
pub trait Create: Sized {
|
||||||
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(timestamp, 0), Utc)
|
fn new(create_id: Option<usize>) -> Self;
|
||||||
|
fn create_id(&self) -> Option<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string_not_set(string: &Option<String>) -> bool {
|
impl<T: Create, A: Default> SetRequest<T, A> {
|
||||||
matches!(string, Some(string) if string.is_empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn date_not_set(date: &Option<DateTime<Utc>>) -> bool {
|
|
||||||
matches!(date, Some(date) if date.timestamp() == 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_not_set<T>(list: &Option<Vec<T>>) -> bool {
|
|
||||||
matches!(list, Some(list) if list.is_empty() )
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, A: Default> SetRequest<T, A> {
|
|
||||||
pub fn new(account_id: String) -> Self {
|
pub fn new(account_id: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
account_id,
|
account_id,
|
||||||
|
@ -118,6 +130,7 @@ impl<T, A: Default> SetRequest<T, A> {
|
||||||
create: None,
|
create: None,
|
||||||
update: None,
|
update: None,
|
||||||
destroy: None,
|
destroy: None,
|
||||||
|
destroy_ref: None,
|
||||||
arguments: Default::default(),
|
arguments: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,22 +145,42 @@ impl<T, A: Default> SetRequest<T, A> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(&mut self, id: impl Into<String>, value: T) -> &mut Self {
|
pub fn create(&mut self) -> &mut T {
|
||||||
|
let create_id = self.create.as_ref().map_or(0, |c| c.len());
|
||||||
|
let create_id_str = format!("c{}", create_id);
|
||||||
self.create
|
self.create
|
||||||
.get_or_insert_with(HashMap::new)
|
.get_or_insert_with(HashMap::new)
|
||||||
.insert(id.into(), value);
|
.insert(create_id_str.clone(), T::new(create_id.into()));
|
||||||
self
|
self.create
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.get_mut(&create_id_str)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, id: impl Into<String>, value: T) -> &mut Self {
|
pub fn update(&mut self, id: impl Into<String>) -> &mut T {
|
||||||
|
let id: String = id.into();
|
||||||
self.update
|
self.update
|
||||||
.get_or_insert_with(HashMap::new)
|
.get_or_insert_with(HashMap::new)
|
||||||
.insert(id.into(), value);
|
.insert(id.clone(), T::new(None));
|
||||||
|
self.update.as_mut().unwrap().get_mut(&id).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy<U, V>(&mut self, ids: U) -> &mut Self
|
||||||
|
where
|
||||||
|
U: IntoIterator<Item = V>,
|
||||||
|
V: Into<String>,
|
||||||
|
{
|
||||||
|
self.destroy
|
||||||
|
.get_or_insert_with(Vec::new)
|
||||||
|
.extend(ids.into_iter().map(|id| id.into()));
|
||||||
|
self.destroy_ref = None;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(&mut self, id: impl Into<String>) -> &mut Self {
|
pub fn destroy_ref(&mut self, reference: ResultReference) -> &mut Self {
|
||||||
self.destroy.get_or_insert_with(Vec::new).push(id.into());
|
self.destroy_ref = reference.into();
|
||||||
|
self.destroy = None;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,40 +202,28 @@ impl<T, U> SetResponse<T, U> {
|
||||||
&self.new_state
|
&self.new_state
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn created(&self) -> Option<impl Iterator<Item = &String>> {
|
pub fn created(&self) -> Option<impl Iterator<Item = (&String, &T)>> {
|
||||||
self.created.as_ref().map(|map| map.keys())
|
self.created.as_ref().map(|map| map.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updated(&self) -> Option<impl Iterator<Item = &String>> {
|
pub fn updated(&self) -> Option<impl Iterator<Item = (&String, &Option<T>)>> {
|
||||||
self.updated.as_ref().map(|map| map.keys())
|
self.updated.as_ref().map(|map| map.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroyed(&self) -> Option<&[String]> {
|
pub fn destroyed(&self) -> Option<&[String]> {
|
||||||
self.destroyed.as_deref()
|
self.destroyed.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn not_created(&self) -> Option<impl Iterator<Item = &String>> {
|
pub fn not_created(&self) -> Option<impl Iterator<Item = (&String, &SetError<U>)>> {
|
||||||
self.not_created.as_ref().map(|map| map.keys())
|
self.not_created.as_ref().map(|map| map.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn not_updated(&self) -> Option<impl Iterator<Item = &String>> {
|
pub fn not_updated(&self) -> Option<impl Iterator<Item = (&String, &SetError<U>)>> {
|
||||||
self.not_updated.as_ref().map(|map| map.keys())
|
self.not_updated.as_ref().map(|map| map.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn not_destroyed(&self) -> Option<impl Iterator<Item = &String>> {
|
pub fn not_destroyed(&self) -> Option<impl Iterator<Item = (&String, &SetError<U>)>> {
|
||||||
self.not_destroyed.as_ref().map(|map| map.keys())
|
self.not_destroyed.as_ref().map(|map| map.iter())
|
||||||
}
|
|
||||||
|
|
||||||
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> {
|
pub fn created_details(&self, id: &str) -> Option<&T> {
|
||||||
|
@ -212,6 +233,18 @@ impl<T, U> SetResponse<T, U> {
|
||||||
pub fn updated_details(&self, id: &str) -> Option<&T> {
|
pub fn updated_details(&self, id: &str) -> Option<&T> {
|
||||||
self.updated.as_ref().and_then(|map| map.get(id))?.as_ref()
|
self.updated.as_ref().and_then(|map| map.get(id))?.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn not_created_details(&self, id: &str) -> Option<&SetError<U>> {
|
||||||
|
self.not_created.as_ref().and_then(|map| map.get(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
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> SetError<U> {
|
||||||
|
@ -227,3 +260,19 @@ impl<U> SetError<U> {
|
||||||
self.properties.as_deref()
|
self.properties.as_deref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_timestamp(timestamp: i64) -> DateTime<Utc> {
|
||||||
|
DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(timestamp, 0), Utc)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn string_not_set(string: &Option<String>) -> bool {
|
||||||
|
matches!(string, Some(string) if string.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn date_not_set(date: &Option<DateTime<Utc>>) -> bool {
|
||||||
|
matches!(date, Some(date) if date.timestamp() == 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_not_set<T>(list: &Option<Vec<T>>) -> bool {
|
||||||
|
matches!(list, Some(list) if list.is_empty() )
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ use super::{Email, Property};
|
||||||
pub struct EmailImportRequest {
|
pub struct EmailImportRequest {
|
||||||
#[serde(rename = "accountId")]
|
#[serde(rename = "accountId")]
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
||||||
#[serde(rename = "ifInState")]
|
#[serde(rename = "ifInState")]
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
if_in_state: Option<String>,
|
if_in_state: Option<String>,
|
||||||
|
|
||||||
emails: HashMap<String, EmailImport>,
|
emails: HashMap<String, EmailImport>,
|
||||||
|
@ -19,6 +21,9 @@ pub struct EmailImportRequest {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct EmailImport {
|
pub struct EmailImport {
|
||||||
|
#[serde(skip)]
|
||||||
|
create_id: usize,
|
||||||
|
|
||||||
#[serde(rename = "blobId")]
|
#[serde(rename = "blobId")]
|
||||||
blob_id: String,
|
blob_id: String,
|
||||||
|
|
||||||
|
@ -37,12 +42,16 @@ pub struct EmailImport {
|
||||||
pub struct EmailImportResponse {
|
pub struct EmailImportResponse {
|
||||||
#[serde(rename = "accountId")]
|
#[serde(rename = "accountId")]
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
||||||
#[serde(rename = "oldState")]
|
#[serde(rename = "oldState")]
|
||||||
old_state: Option<String>,
|
old_state: Option<String>,
|
||||||
|
|
||||||
#[serde(rename = "newState")]
|
#[serde(rename = "newState")]
|
||||||
new_state: String,
|
new_state: String,
|
||||||
|
|
||||||
#[serde(rename = "created")]
|
#[serde(rename = "created")]
|
||||||
created: Option<HashMap<String, Email>>,
|
created: Option<HashMap<String, Email>>,
|
||||||
|
|
||||||
#[serde(rename = "notCreated")]
|
#[serde(rename = "notCreated")]
|
||||||
not_created: Option<HashMap<String, SetError<Property>>>,
|
not_created: Option<HashMap<String, SetError<Property>>>,
|
||||||
}
|
}
|
||||||
|
@ -56,20 +65,26 @@ impl EmailImportRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn if_in_state(&mut self, if_in_state: String) -> &mut Self {
|
pub fn if_in_state(&mut self, if_in_state: impl Into<String>) -> &mut Self {
|
||||||
self.if_in_state = Some(if_in_state);
|
self.if_in_state = Some(if_in_state.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_email(&mut self, id: String, email_import: EmailImport) -> &mut Self {
|
pub fn email(&mut self, blob_id: impl Into<String>) -> &mut EmailImport {
|
||||||
self.emails.insert(id, email_import);
|
let create_id = self.emails.len();
|
||||||
self
|
let create_id_str = format!("i{}", create_id);
|
||||||
|
self.emails.insert(
|
||||||
|
create_id_str.clone(),
|
||||||
|
EmailImport::new(blob_id.into(), create_id),
|
||||||
|
);
|
||||||
|
self.emails.get_mut(&create_id_str).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmailImport {
|
impl EmailImport {
|
||||||
pub fn new(blob_id: String) -> Self {
|
fn new(blob_id: String, create_id: usize) -> Self {
|
||||||
EmailImport {
|
EmailImport {
|
||||||
|
create_id,
|
||||||
blob_id,
|
blob_id,
|
||||||
mailbox_ids: HashMap::new(),
|
mailbox_ids: HashMap::new(),
|
||||||
keywords: HashMap::new(),
|
keywords: HashMap::new(),
|
||||||
|
@ -77,20 +92,24 @@ impl EmailImport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mailbox_id(mut self, mailbox_id: String) -> Self {
|
pub fn mailbox_id(&mut self, mailbox_id: impl Into<String>) -> &mut Self {
|
||||||
self.mailbox_ids.insert(mailbox_id, true);
|
self.mailbox_ids.insert(mailbox_id.into(), true);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keyword(mut self, keyword: String) -> Self {
|
pub fn keyword(&mut self, keyword: impl Into<String>) -> &mut Self {
|
||||||
self.keywords.insert(keyword, true);
|
self.keywords.insert(keyword.into(), true);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn received_at(mut self, received_at: i64) -> Self {
|
pub fn received_at(&mut self, received_at: i64) -> &mut Self {
|
||||||
self.received_at = Some(from_timestamp(received_at));
|
self.received_at = Some(from_timestamp(received_at));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_id(&self) -> String {
|
||||||
|
format!("i{}", self.create_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmailImportResponse {
|
impl EmailImportResponse {
|
||||||
|
|
|
@ -9,10 +9,13 @@ use chrono::{DateTime, Utc};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::Get;
|
use crate::{core::request::ResultReference, Get};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||||
pub struct Email<State = Get> {
|
pub struct Email<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_create_id: Option<usize>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
_state: std::marker::PhantomData<State>,
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
@ -32,6 +35,11 @@ pub struct Email<State = Get> {
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
mailbox_ids: Option<HashMap<String, bool>>,
|
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")]
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
keywords: Option<HashMap<String, bool>>,
|
keywords: Option<HashMap<String, bool>>,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{BodyProperty, Email, Property};
|
use super::{BodyProperty, Email, Property};
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ pub struct EmailParseRequest {
|
||||||
max_body_value_bytes: usize,
|
max_body_value_bytes: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Deserialize)]
|
||||||
pub struct EmailParseResponse {
|
pub struct EmailParseResponse {
|
||||||
#[serde(rename = "accountId")]
|
#[serde(rename = "accountId")]
|
||||||
account_id: String,
|
account_id: String,
|
||||||
|
|
|
@ -1,22 +1,35 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{core::set::from_timestamp, Set};
|
use crate::{
|
||||||
|
core::{
|
||||||
|
request::ResultReference,
|
||||||
|
set::{from_timestamp, Create},
|
||||||
|
},
|
||||||
|
Set,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Email, EmailAddress, EmailAddressGroup, EmailBodyPart, EmailBodyValue, EmailHeader, Field,
|
Email, EmailAddress, EmailAddressGroup, EmailBodyPart, EmailBodyValue, EmailHeader, Field,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Email<Set> {
|
impl Email<Set> {
|
||||||
pub fn mailbox_ids<T, U>(mut self, mailbox_ids: T) -> Self
|
pub fn mailbox_ids<T, U>(&mut self, mailbox_ids: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
{
|
{
|
||||||
self.mailbox_ids = Some(mailbox_ids.into_iter().map(|s| (s.into(), true)).collect());
|
self.mailbox_ids = Some(mailbox_ids.into_iter().map(|s| (s.into(), true)).collect());
|
||||||
|
self.mailbox_ids_ref = None;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mailbox_id(mut self, mailbox_id: &str, set: bool) -> Self {
|
pub fn mailbox_ids_ref(&mut self, reference: ResultReference) -> &mut Self {
|
||||||
|
self.mailbox_ids_ref = reference.into();
|
||||||
|
self.mailbox_ids = None;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mailbox_id(&mut self, mailbox_id: &str, set: bool) -> &mut Self {
|
||||||
self.mailbox_ids = None;
|
self.mailbox_ids = None;
|
||||||
self.others.insert(
|
self.others.insert(
|
||||||
format!("mailboxIds/{}", mailbox_id),
|
format!("mailboxIds/{}", mailbox_id),
|
||||||
|
@ -25,7 +38,7 @@ impl Email<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keywords<T, U>(mut self, keywords: T) -> Self
|
pub fn keywords<T, U>(&mut self, keywords: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
|
@ -34,14 +47,14 @@ impl Email<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keyword(mut self, keyword: &str, set: bool) -> Self {
|
pub fn keyword(&mut self, keyword: &str, set: bool) -> &mut Self {
|
||||||
self.keywords = None;
|
self.keywords = None;
|
||||||
self.others
|
self.others
|
||||||
.insert(format!("keywords/{}", keyword), Field::Bool(set).into());
|
.insert(format!("keywords/{}", keyword), Field::Bool(set).into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message_id<T, U>(mut self, message_id: T) -> Self
|
pub fn message_id<T, U>(&mut self, message_id: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
|
@ -50,7 +63,7 @@ impl Email<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_reply_to<T, U>(mut self, in_reply_to: T) -> Self
|
pub fn in_reply_to<T, U>(&mut self, in_reply_to: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
|
@ -59,7 +72,7 @@ impl Email<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn references<T, U>(mut self, references: T) -> Self
|
pub fn references<T, U>(&mut self, references: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<String>,
|
U: Into<String>,
|
||||||
|
@ -68,7 +81,7 @@ impl Email<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sender<T, U>(mut self, sender: T) -> Self
|
pub fn sender<T, U>(&mut self, sender: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<EmailAddress>,
|
U: Into<EmailAddress>,
|
||||||
|
@ -77,7 +90,7 @@ impl Email<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from<T, U>(mut self, from: T) -> Self
|
pub fn from<T, U>(&mut self, from: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<EmailAddress>,
|
U: Into<EmailAddress>,
|
||||||
|
@ -86,7 +99,7 @@ impl Email<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to<T, U>(mut self, to: T) -> Self
|
pub fn to<T, U>(&mut self, to: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<EmailAddress>,
|
U: Into<EmailAddress>,
|
||||||
|
@ -95,7 +108,7 @@ impl Email<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cc<T, U>(mut self, cc: T) -> Self
|
pub fn cc<T, U>(&mut self, cc: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<EmailAddress>,
|
U: Into<EmailAddress>,
|
||||||
|
@ -104,7 +117,7 @@ impl Email<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bcc<T, U>(mut self, bcc: T) -> Self
|
pub fn bcc<T, U>(&mut self, bcc: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<EmailAddress>,
|
U: Into<EmailAddress>,
|
||||||
|
@ -113,7 +126,7 @@ impl Email<Set> {
|
||||||
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) -> &mut Self
|
||||||
where
|
where
|
||||||
T: IntoIterator<Item = U>,
|
T: IntoIterator<Item = U>,
|
||||||
U: Into<EmailAddress>,
|
U: Into<EmailAddress>,
|
||||||
|
@ -122,59 +135,61 @@ impl Email<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subject(mut self, subject: impl Into<String>) -> Self {
|
pub fn subject(&mut self, subject: impl Into<String>) -> &mut Self {
|
||||||
self.subject = Some(subject.into());
|
self.subject = Some(subject.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sent_at(mut self, sent_at: i64) -> Self {
|
pub fn sent_at(&mut self, sent_at: i64) -> &mut Self {
|
||||||
self.sent_at = Some(from_timestamp(sent_at));
|
self.sent_at = Some(from_timestamp(sent_at));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn body_structure(mut self, body_structure: EmailBodyPart) -> Self {
|
pub fn body_structure(&mut self, body_structure: EmailBodyPart) -> &mut Self {
|
||||||
self.body_structure = Some(body_structure.into());
|
self.body_structure = Some(body_structure.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn body_value(mut self, id: String, body_value: impl Into<EmailBodyValue>) -> Self {
|
pub fn body_value(&mut self, id: String, body_value: impl Into<EmailBodyValue>) -> &mut Self {
|
||||||
self.body_values
|
self.body_values
|
||||||
.get_or_insert_with(HashMap::new)
|
.get_or_insert_with(HashMap::new)
|
||||||
.insert(id, body_value.into());
|
.insert(id, body_value.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text_body(mut self, text_body: EmailBodyPart) -> Self {
|
pub fn text_body(&mut self, text_body: EmailBodyPart) -> &mut Self {
|
||||||
self.text_body.get_or_insert_with(Vec::new).push(text_body);
|
self.text_body.get_or_insert_with(Vec::new).push(text_body);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn html_body(mut self, html_body: EmailBodyPart) -> Self {
|
pub fn html_body(&mut self, html_body: EmailBodyPart) -> &mut Self {
|
||||||
self.html_body.get_or_insert_with(Vec::new).push(html_body);
|
self.html_body.get_or_insert_with(Vec::new).push(html_body);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attachment(mut self, attachment: EmailBodyPart) -> Self {
|
pub fn attachment(&mut self, attachment: EmailBodyPart) -> &mut Self {
|
||||||
self.attachments
|
self.attachments
|
||||||
.get_or_insert_with(Vec::new)
|
.get_or_insert_with(Vec::new)
|
||||||
.push(attachment);
|
.push(attachment);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn header(mut self, header: String, value: impl Into<Field>) -> Self {
|
pub fn header(&mut self, header: String, value: impl Into<Field>) -> &mut Self {
|
||||||
self.others.insert(header, Some(value.into()));
|
self.others.insert(header, Some(value.into()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Email {
|
impl Create for Email<Set> {
|
||||||
pub fn new() -> Email<Set> {
|
fn new(_create_id: Option<usize>) -> Email<Set> {
|
||||||
Email {
|
Email {
|
||||||
|
_create_id,
|
||||||
_state: Default::default(),
|
_state: Default::default(),
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
blob_id: Default::default(),
|
blob_id: Default::default(),
|
||||||
thread_id: Default::default(),
|
thread_id: Default::default(),
|
||||||
mailbox_ids: Default::default(),
|
mailbox_ids: Default::default(),
|
||||||
|
mailbox_ids_ref: Default::default(),
|
||||||
keywords: Default::default(),
|
keywords: Default::default(),
|
||||||
size: Default::default(),
|
size: Default::default(),
|
||||||
received_at: Default::default(),
|
received_at: Default::default(),
|
||||||
|
@ -199,6 +214,10 @@ impl Email {
|
||||||
others: Default::default(),
|
others: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_id(&self) -> Option<String> {
|
||||||
|
self._create_id.map(|id| format!("c{}", id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmailBodyPart {
|
impl EmailBodyPart {
|
||||||
|
|
|
@ -19,6 +19,9 @@ pub struct SetArguments {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct EmailSubmission<State = Get> {
|
pub struct EmailSubmission<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_create_id: Option<usize>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
_state: std::marker::PhantomData<State>,
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::Set;
|
use crate::{core::set::Create, Set};
|
||||||
|
|
||||||
use super::{Address, EmailSubmission, Envelope, UndoStatus};
|
use super::{Address, EmailSubmission, Envelope, UndoStatus};
|
||||||
|
|
||||||
impl EmailSubmission<Set> {
|
impl EmailSubmission<Set> {
|
||||||
pub fn identity_id(mut self, identity_id: String) -> Self {
|
pub fn identity_id(&mut self, identity_id: impl Into<String>) -> &mut Self {
|
||||||
self.identity_id = Some(identity_id);
|
self.identity_id = Some(identity_id.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn email_id(mut self, email_id: String) -> Self {
|
pub fn email_id(&mut self, email_id: impl Into<String>) -> &mut Self {
|
||||||
self.email_id = Some(email_id);
|
self.email_id = Some(email_id.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn envelope<T, U>(mut self, mail_from: U, rcpt_to: T) -> Self
|
pub fn envelope<T, U>(&mut self, mail_from: U, rcpt_to: T) -> &mut Self
|
||||||
where
|
where
|
||||||
T: Iterator<Item = U>,
|
T: Iterator<Item = U>,
|
||||||
U: Into<Address>,
|
U: Into<Address>,
|
||||||
|
@ -27,15 +27,16 @@ impl EmailSubmission<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn undo_status(mut self, undo_status: UndoStatus) -> Self {
|
pub fn undo_status(&mut self, undo_status: UndoStatus) -> &mut Self {
|
||||||
self.undo_status = Some(undo_status);
|
self.undo_status = Some(undo_status);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmailSubmission {
|
impl Create for EmailSubmission<Set> {
|
||||||
pub fn new() -> EmailSubmission<Set> {
|
fn new(_create_id: Option<usize>) -> Self {
|
||||||
EmailSubmission {
|
EmailSubmission {
|
||||||
|
_create_id,
|
||||||
_state: Default::default(),
|
_state: Default::default(),
|
||||||
id: None,
|
id: None,
|
||||||
identity_id: None,
|
identity_id: None,
|
||||||
|
@ -49,6 +50,10 @@ impl EmailSubmission {
|
||||||
mdn_blob_ids: None,
|
mdn_blob_ids: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_id(&self) -> Option<String> {
|
||||||
|
self._create_id.map(|id| format!("c{}", id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Address {
|
impl Address {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
use crate::core::session::URLParser;
|
||||||
|
|
||||||
|
pub enum URLParameter {
|
||||||
|
Types,
|
||||||
|
CloseAfter,
|
||||||
|
Ping,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl URLParser for URLParameter {
|
||||||
|
fn parse(value: &str) -> Option<Self> {
|
||||||
|
match value {
|
||||||
|
"types" => Some(URLParameter::Types),
|
||||||
|
"closeafter" => Some(URLParameter::CloseAfter),
|
||||||
|
"ping" => Some(URLParameter::Ping),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,9 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Identity<State = Get> {
|
pub struct Identity<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_create_id: Option<usize>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
_state: std::marker::PhantomData<State>,
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
use crate::{email::EmailAddress, Set};
|
use crate::{core::set::Create, email::EmailAddress, Set};
|
||||||
|
|
||||||
use super::Identity;
|
use super::Identity;
|
||||||
|
|
||||||
impl Identity<Set> {
|
impl Identity<Set> {
|
||||||
pub fn name(mut self, name: String) -> Self {
|
pub fn name(&mut self, name: String) -> &mut Self {
|
||||||
self.name = Some(name);
|
self.name = Some(name);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn email(mut self, email: String) -> Self {
|
pub fn email(&mut self, email: String) -> &mut Self {
|
||||||
self.email = Some(email);
|
self.email = Some(email);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bcc<T, U>(mut self, bcc: Option<T>) -> Self
|
pub fn bcc<T, U>(&mut self, bcc: Option<T>) -> &mut Self
|
||||||
where
|
where
|
||||||
T: Iterator<Item = U>,
|
T: Iterator<Item = U>,
|
||||||
U: Into<EmailAddress>,
|
U: Into<EmailAddress>,
|
||||||
|
@ -22,7 +22,7 @@ impl Identity<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reply_to<T, U>(mut self, reply_to: Option<T>) -> Self
|
pub fn reply_to<T, U>(&mut self, reply_to: Option<T>) -> &mut Self
|
||||||
where
|
where
|
||||||
T: Iterator<Item = U>,
|
T: Iterator<Item = U>,
|
||||||
U: Into<EmailAddress>,
|
U: Into<EmailAddress>,
|
||||||
|
@ -31,20 +31,21 @@ impl Identity<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text_signature(mut self, text_signature: String) -> Self {
|
pub fn text_signature(&mut self, text_signature: String) -> &mut Self {
|
||||||
self.text_signature = Some(text_signature);
|
self.text_signature = Some(text_signature);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn html_signature(mut self, html_signature: String) -> Self {
|
pub fn html_signature(&mut self, html_signature: String) -> &mut Self {
|
||||||
self.html_signature = Some(html_signature);
|
self.html_signature = Some(html_signature);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Identity {
|
impl Create for Identity<Set> {
|
||||||
pub fn new() -> Identity<Set> {
|
fn new(_create_id: Option<usize>) -> Self {
|
||||||
Identity {
|
Identity {
|
||||||
|
_create_id,
|
||||||
_state: Default::default(),
|
_state: Default::default(),
|
||||||
id: None,
|
id: None,
|
||||||
name: None,
|
name: None,
|
||||||
|
@ -56,4 +57,8 @@ impl Identity {
|
||||||
may_delete: None,
|
may_delete: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_id(&self) -> Option<String> {
|
||||||
|
self._create_id.map(|id| format!("c{}", id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
38
src/lib.rs
38
src/lib.rs
|
@ -1,4 +1,5 @@
|
||||||
use std::collections::HashMap;
|
use crate::core::error::ProblemDetails;
|
||||||
|
use std::{collections::HashMap, fmt::Display};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -7,6 +8,7 @@ pub mod client;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod email;
|
pub mod email;
|
||||||
pub mod email_submission;
|
pub mod email_submission;
|
||||||
|
pub mod event_source;
|
||||||
pub mod identity;
|
pub mod identity;
|
||||||
pub mod mailbox;
|
pub mod mailbox;
|
||||||
pub mod push_subscription;
|
pub mod push_subscription;
|
||||||
|
@ -125,3 +127,37 @@ pub struct StateChange {
|
||||||
pub struct Get;
|
pub struct Get;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Set;
|
pub struct Set;
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
pub enum Error {
|
||||||
|
Transport(reqwest::Error),
|
||||||
|
Parse(serde_json::Error),
|
||||||
|
Internal(String),
|
||||||
|
Problem(ProblemDetails),
|
||||||
|
ServerError(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<reqwest::Error> for Error {
|
||||||
|
fn from(e: reqwest::Error) -> Self {
|
||||||
|
Error::Transport(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<serde_json::Error> for Error {
|
||||||
|
fn from(e: serde_json::Error) -> Self {
|
||||||
|
Error::Parse(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Error::Transport(e) => write!(f, "Transport error: {}", e),
|
||||||
|
Error::Parse(e) => write!(f, "Parse error: {}", e),
|
||||||
|
Error::Internal(e) => write!(f, "Internal error: {}", e),
|
||||||
|
Error::Problem(e) => write!(f, "Problem details: {}", e),
|
||||||
|
Error::ServerError(e) => write!(f, "Server error: {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,8 +21,17 @@ pub struct QueryArguments {
|
||||||
filter_as_tree: bool,
|
filter_as_tree: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Default)]
|
||||||
|
pub struct ChangesResponse {
|
||||||
|
#[serde(rename = "updatedProperties")]
|
||||||
|
updated_properties: Option<Vec<Property>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Mailbox<State = Get> {
|
pub struct Mailbox<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_create_id: Option<usize>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
_state: std::marker::PhantomData<State>,
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
@ -139,3 +148,9 @@ pub enum Property {
|
||||||
#[serde(rename = "isSubscribed")]
|
#[serde(rename = "isSubscribed")]
|
||||||
IsSubscribed,
|
IsSubscribed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ChangesResponse {
|
||||||
|
pub fn updated_properties(&self) -> Option<&[Property]> {
|
||||||
|
self.updated_properties.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use serde::Serialize;
|
||||||
|
|
||||||
use crate::core::query::{self};
|
use crate::core::query::{self};
|
||||||
|
|
||||||
use super::Role;
|
use super::{QueryArguments, Role};
|
||||||
|
|
||||||
#[derive(Serialize, Clone, Debug)]
|
#[derive(Serialize, Clone, Debug)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
|
@ -81,3 +81,15 @@ impl Comparator {
|
||||||
query::Comparator::new(Comparator::ParentId)
|
query::Comparator::new(Comparator::ParentId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl QueryArguments {
|
||||||
|
pub fn sort_as_tree(&mut self, value: bool) -> &mut Self {
|
||||||
|
self.sort_as_tree = value;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filter_as_tree(&mut self, value: bool) -> &mut Self {
|
||||||
|
self.filter_as_tree = value;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
use crate::Set;
|
use crate::{core::set::Create, Set};
|
||||||
|
|
||||||
use super::{Mailbox, Role};
|
use super::{Mailbox, Role, SetArguments};
|
||||||
|
|
||||||
impl Mailbox<Set> {
|
impl Mailbox<Set> {
|
||||||
pub fn name(mut self, name: String) -> Self {
|
pub fn name(&mut self, name: impl Into<String>) -> &mut Self {
|
||||||
self.name = Some(name);
|
self.name = Some(name.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parent_id(mut self, parent_id: Option<String>) -> Self {
|
pub fn parent_id(&mut self, parent_id: Option<impl Into<String>>) -> &mut Self {
|
||||||
self.parent_id = parent_id;
|
self.parent_id = parent_id.map(|s| s.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn role(mut self, role: Role) -> Self {
|
pub fn role(&mut self, role: Role) -> &mut Self {
|
||||||
if !matches!(role, Role::None) {
|
if !matches!(role, Role::None) {
|
||||||
self.role = Some(role);
|
self.role = Some(role);
|
||||||
} else {
|
} else {
|
||||||
|
@ -22,7 +22,7 @@ impl Mailbox<Set> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sort_order(mut self, sort_order: u32) -> Self {
|
pub fn sort_order(&mut self, sort_order: u32) -> &mut Self {
|
||||||
self.sort_order = sort_order.into();
|
self.sort_order = sort_order.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,10 @@ pub fn role_not_set(role: &Option<Role>) -> bool {
|
||||||
matches!(role, Some(Role::None))
|
matches!(role, Some(Role::None))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mailbox {
|
impl Create for Mailbox<Set> {
|
||||||
pub fn new() -> Mailbox<Set> {
|
fn new(_create_id: Option<usize>) -> Self {
|
||||||
Mailbox {
|
Mailbox {
|
||||||
|
_create_id,
|
||||||
_state: Default::default(),
|
_state: Default::default(),
|
||||||
id: None,
|
id: None,
|
||||||
name: None,
|
name: None,
|
||||||
|
@ -49,4 +50,15 @@ impl Mailbox {
|
||||||
is_subscribed: None,
|
is_subscribed: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_id(&self) -> Option<String> {
|
||||||
|
self._create_id.map(|id| format!("c{}", id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetArguments {
|
||||||
|
pub fn on_destroy_remove_emails(&mut self, value: bool) -> &mut Self {
|
||||||
|
self.on_destroy_remove_emails = value;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,9 @@ use crate::{Get, Object};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PushSubscription<State = Get> {
|
pub struct PushSubscription<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_create_id: Option<usize>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
_state: std::marker::PhantomData<State>,
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,46 @@
|
||||||
use crate::{core::set::from_timestamp, Object, Set};
|
use crate::{
|
||||||
|
core::set::{from_timestamp, Create},
|
||||||
|
Object, Set,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{Keys, PushSubscription};
|
use super::{Keys, PushSubscription};
|
||||||
|
|
||||||
impl PushSubscription<Set> {
|
impl PushSubscription<Set> {
|
||||||
pub fn device_client_id(mut self, device_client_id: String) -> Self {
|
pub fn device_client_id(&mut self, device_client_id: impl Into<String>) -> &mut Self {
|
||||||
self.device_client_id = Some(device_client_id);
|
self.device_client_id = Some(device_client_id.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url(mut self, url: String) -> Self {
|
pub fn url(&mut self, url: impl Into<String>) -> &mut Self {
|
||||||
self.url = Some(url);
|
self.url = Some(url.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verification_code(mut self, verification_code: String) -> Self {
|
pub fn verification_code(&mut self, verification_code: impl Into<String>) -> &mut Self {
|
||||||
self.verification_code = Some(verification_code);
|
self.verification_code = Some(verification_code.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keys(mut self, keys: Keys) -> Self {
|
pub fn keys(&mut self, keys: Keys) -> &mut Self {
|
||||||
self.keys = Some(keys);
|
self.keys = Some(keys);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expires(mut self, expires: i64) -> Self {
|
pub fn expires(&mut self, expires: i64) -> &mut Self {
|
||||||
self.expires = Some(from_timestamp(expires));
|
self.expires = Some(from_timestamp(expires));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn types(mut self, types: Option<impl Iterator<Item = Object>>) -> Self {
|
pub fn types(&mut self, types: Option<impl Iterator<Item = Object>>) -> &mut Self {
|
||||||
self.types = types.map(|s| s.collect());
|
self.types = types.map(|s| s.collect());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PushSubscription {
|
impl Create for PushSubscription<Set> {
|
||||||
pub fn new() -> PushSubscription<Set> {
|
fn new(_create_id: Option<usize>) -> Self {
|
||||||
PushSubscription {
|
PushSubscription {
|
||||||
|
_create_id,
|
||||||
_state: Default::default(),
|
_state: Default::default(),
|
||||||
id: None,
|
id: None,
|
||||||
device_client_id: None,
|
device_client_id: None,
|
||||||
|
@ -47,6 +51,10 @@ impl PushSubscription {
|
||||||
types: Vec::with_capacity(0).into(),
|
types: Vec::with_capacity(0).into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_id(&self) -> Option<String> {
|
||||||
|
self._create_id.map(|id| format!("c{}", id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Keys {
|
impl Keys {
|
||||||
|
|
|
@ -9,6 +9,9 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct VacationResponse<State = Get> {
|
pub struct VacationResponse<State = Get> {
|
||||||
|
#[serde(skip)]
|
||||||
|
_create_id: Option<usize>,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
_state: std::marker::PhantomData<State>,
|
_state: std::marker::PhantomData<State>,
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,46 @@
|
||||||
use crate::{core::set::from_timestamp, Set};
|
use crate::{
|
||||||
|
core::set::{from_timestamp, Create},
|
||||||
|
Set,
|
||||||
|
};
|
||||||
|
|
||||||
use super::VacationResponse;
|
use super::VacationResponse;
|
||||||
|
|
||||||
impl VacationResponse<Set> {
|
impl VacationResponse<Set> {
|
||||||
pub fn is_enabled(mut self, is_enabled: bool) -> Self {
|
pub fn is_enabled(&mut self, is_enabled: bool) -> &mut Self {
|
||||||
self.is_enabled = Some(is_enabled);
|
self.is_enabled = Some(is_enabled);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_date(mut self, from_date: Option<i64>) -> Self {
|
pub fn from_date(&mut self, from_date: Option<i64>) -> &mut Self {
|
||||||
self.from_date = from_date.map(from_timestamp);
|
self.from_date = from_date.map(from_timestamp);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_date(mut self, to_date: Option<i64>) -> Self {
|
pub fn to_date(&mut self, to_date: Option<i64>) -> &mut Self {
|
||||||
self.to_date = to_date.map(from_timestamp);
|
self.to_date = to_date.map(from_timestamp);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subject(mut self, subject: Option<String>) -> Self {
|
pub fn subject(&mut self, subject: Option<impl Into<String>>) -> &mut Self {
|
||||||
self.subject = subject;
|
self.subject = subject.map(|s| s.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text_body(mut self, text_body: Option<String>) -> Self {
|
pub fn text_body(&mut self, text_body: Option<impl Into<String>>) -> &mut Self {
|
||||||
self.text_body = text_body;
|
self.text_body = text_body.map(|s| s.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn html_body(mut self, html_body: Option<String>) -> Self {
|
pub fn html_body(&mut self, html_body: Option<impl Into<String>>) -> &mut Self {
|
||||||
self.html_body = html_body;
|
self.html_body = html_body.map(|s| s.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VacationResponse {
|
impl Create for VacationResponse<Set> {
|
||||||
pub fn new() -> VacationResponse<Set> {
|
fn new(_create_id: Option<usize>) -> Self {
|
||||||
VacationResponse {
|
VacationResponse {
|
||||||
|
_create_id,
|
||||||
_state: Default::default(),
|
_state: Default::default(),
|
||||||
id: None,
|
id: None,
|
||||||
is_enabled: None,
|
is_enabled: None,
|
||||||
|
@ -47,4 +51,8 @@ impl VacationResponse {
|
||||||
html_body: "".to_string().into(),
|
html_body: "".to_string().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_id(&self) -> Option<String> {
|
||||||
|
self._create_id.map(|id| format!("c{}", id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue