mirror of
https://git.meli.delivery/meli/meli
synced 2024-11-19 03:25:38 +00:00
JMAP WIP #3
This commit is contained in:
parent
e8611cca2f
commit
a1efeed343
@ -35,6 +35,19 @@ use std::hash::Hasher;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! _impl {
|
||||
($field:ident : $t:ty) => {
|
||||
pub fn $field(mut self, new_val: $t) -> Self {
|
||||
self.$field = new_val;
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod connection;
|
||||
use connection::*;
|
||||
|
||||
pub mod protocol;
|
||||
use protocol::*;
|
||||
|
||||
@ -122,7 +135,7 @@ macro_rules! get_conf_val {
|
||||
($s:ident[$var:literal]) => {
|
||||
$s.extra.get($var).ok_or_else(|| {
|
||||
MeliError::new(format!(
|
||||
"Configuration error ({}): IMAP connection requires the field `{}` set",
|
||||
"Configuration error ({}): JMAP connection requires the field `{}` set",
|
||||
$s.name.as_str(),
|
||||
$var
|
||||
))
|
||||
@ -152,7 +165,7 @@ pub struct JmapType {
|
||||
online: Arc<Mutex<bool>>,
|
||||
is_subscribed: Arc<IsSubscribedFn>,
|
||||
server_conf: JmapServerConf,
|
||||
connection: Arc<Mutex<JmapConnection>>,
|
||||
connection: Arc<JmapConnection>,
|
||||
folders: Arc<RwLock<FnvHashMap<FolderHash, JmapFolder>>>,
|
||||
}
|
||||
|
||||
@ -168,15 +181,11 @@ impl MailBackend for JmapType {
|
||||
let handle = {
|
||||
let tx = w.tx();
|
||||
let closure = move |_work_context| {
|
||||
let mut conn_lck = connection.lock().unwrap();
|
||||
tx.send(AsyncStatus::Payload(
|
||||
protocol::get_message_list(
|
||||
&mut conn_lck,
|
||||
&folders.read().unwrap()[&folder_hash],
|
||||
)
|
||||
.and_then(|ids| {
|
||||
protocol::get_message(&mut conn_lck, std::dbg!(&ids).as_slice())
|
||||
}),
|
||||
protocol::get_message_list(&connection, &folders.read().unwrap()[&folder_hash])
|
||||
.and_then(|ids| {
|
||||
protocol::get_message(&connection, std::dbg!(&ids).as_slice())
|
||||
}),
|
||||
))
|
||||
.unwrap();
|
||||
tx.send(AsyncStatus::Finished).unwrap();
|
||||
@ -196,9 +205,7 @@ impl MailBackend for JmapType {
|
||||
|
||||
fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>> {
|
||||
if self.folders.read().unwrap().is_empty() {
|
||||
let folders = std::dbg!(protocol::get_mailboxes(
|
||||
&mut self.connection.lock().unwrap()
|
||||
))?;
|
||||
let folders = std::dbg!(protocol::get_mailboxes(&self.connection))?;
|
||||
let ret = Ok(folders
|
||||
.iter()
|
||||
.map(|(&h, f)| (h, BackendFolder::clone(f) as Folder))
|
||||
@ -242,10 +249,7 @@ impl JmapType {
|
||||
let server_conf = JmapServerConf::new(s)?;
|
||||
|
||||
Ok(Box::new(JmapType {
|
||||
connection: Arc::new(Mutex::new(JmapConnection::new(
|
||||
&server_conf,
|
||||
online.clone(),
|
||||
)?)),
|
||||
connection: Arc::new(JmapConnection::new(&server_conf, online.clone())?),
|
||||
folders: Arc::new(RwLock::new(FnvHashMap::default())),
|
||||
account_name: s.name.clone(),
|
||||
online,
|
||||
@ -263,37 +267,3 @@ impl JmapType {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JmapConnection {
|
||||
request_no: usize,
|
||||
client: Client,
|
||||
online_status: Arc<Mutex<bool>>,
|
||||
}
|
||||
|
||||
impl JmapConnection {
|
||||
pub fn new(server_conf: &JmapServerConf, online_status: Arc<Mutex<bool>>) -> Result<Self> {
|
||||
use reqwest::header;
|
||||
let mut headers = header::HeaderMap::new();
|
||||
headers.insert(
|
||||
header::AUTHORIZATION,
|
||||
header::HeaderValue::from_static("fc32dffe-14e7-11ea-a277-2477037a1804"),
|
||||
);
|
||||
headers.insert(
|
||||
header::ACCEPT,
|
||||
header::HeaderValue::from_static("application/json"),
|
||||
);
|
||||
headers.insert(
|
||||
header::CONTENT_TYPE,
|
||||
header::HeaderValue::from_static("application/json"),
|
||||
);
|
||||
Ok(JmapConnection {
|
||||
request_no: 0,
|
||||
client: reqwest::blocking::ClientBuilder::new()
|
||||
.danger_accept_invalid_certs(server_conf.danger_accept_invalid_certs)
|
||||
.default_headers(headers)
|
||||
.build()?,
|
||||
online_status,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
64
melib/src/backends/jmap/connection.rs
Normal file
64
melib/src/backends/jmap/connection.rs
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* meli - jmap module.
|
||||
*
|
||||
* Copyright 2019 Manos Pitsidianakis
|
||||
*
|
||||
* This file is part of meli.
|
||||
*
|
||||
* meli is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* meli is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JmapConnection {
|
||||
pub request_no: Arc<Mutex<usize>>,
|
||||
pub client: Arc<Mutex<Client>>,
|
||||
pub online_status: Arc<Mutex<bool>>,
|
||||
pub server_conf: JmapServerConf,
|
||||
}
|
||||
|
||||
impl JmapConnection {
|
||||
pub fn new(server_conf: &JmapServerConf, online_status: Arc<Mutex<bool>>) -> Result<Self> {
|
||||
use reqwest::header;
|
||||
let mut headers = header::HeaderMap::new();
|
||||
headers.insert(
|
||||
header::AUTHORIZATION,
|
||||
header::HeaderValue::from_static("fc32dffe-14e7-11ea-a277-2477037a1804"),
|
||||
);
|
||||
headers.insert(
|
||||
header::ACCEPT,
|
||||
header::HeaderValue::from_static("application/json"),
|
||||
);
|
||||
headers.insert(
|
||||
header::CONTENT_TYPE,
|
||||
header::HeaderValue::from_static("application/json"),
|
||||
);
|
||||
let client = reqwest::blocking::ClientBuilder::new()
|
||||
.danger_accept_invalid_certs(server_conf.danger_accept_invalid_certs)
|
||||
.default_headers(headers)
|
||||
.build()?;
|
||||
|
||||
let res_text = client.get(&server_conf.server_hostname).send()?.text()?;
|
||||
debug!(&res_text);
|
||||
|
||||
let server_conf = server_conf.clone();
|
||||
Ok(JmapConnection {
|
||||
request_no: Arc::new(Mutex::new(0)),
|
||||
client: Arc::new(Mutex::new(client)),
|
||||
online_status,
|
||||
server_conf,
|
||||
})
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@
|
||||
|
||||
use super::*;
|
||||
use crate::backends::jmap::protocol::*;
|
||||
use crate::backends::jmap::rfc8620::bool_false;
|
||||
use std::collections::HashMap;
|
||||
|
||||
// 4.1.1.
|
||||
@ -151,7 +152,7 @@ pub struct EmailQueryResponse {
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EmailQueryCall {
|
||||
pub filter: Vec<EmailFilterCondition>, /* "inMailboxes": [ folder.id ] },*/
|
||||
pub filter: EmailFilterCondition, /* "inMailboxes": [ folder.id ] },*/
|
||||
pub collapse_threads: bool,
|
||||
pub position: u64,
|
||||
pub fetch_threads: bool,
|
||||
@ -166,18 +167,44 @@ impl Method<EmailObject> for EmailQueryCall {
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EmailGetCall {
|
||||
pub filter: Vec<EmailFilterCondition>, /* "inMailboxes": [ folder.id ] },*/
|
||||
pub collapse_threads: bool,
|
||||
pub position: u64,
|
||||
pub fetch_threads: bool,
|
||||
pub fetch_messages: bool,
|
||||
pub fetch_message_properties: Vec<MessageProperty>,
|
||||
#[serde(flatten)]
|
||||
pub get_call: GetCall<EmailObject>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub body_properties: Vec<String>,
|
||||
#[serde(default = "bool_false")]
|
||||
pub fetch_text_body_values: bool,
|
||||
#[serde(default = "bool_false")]
|
||||
pub fetch_html_body_values: bool,
|
||||
#[serde(default = "bool_false")]
|
||||
pub fetch_all_body_values: bool,
|
||||
#[serde(default)]
|
||||
pub max_body_value_bytes: u64,
|
||||
}
|
||||
|
||||
impl Method<EmailObject> for EmailGetCall {
|
||||
const NAME: &'static str = "Email/get";
|
||||
}
|
||||
|
||||
impl EmailGetCall {
|
||||
pub fn new(get_call: GetCall<EmailObject>) -> Self {
|
||||
EmailGetCall {
|
||||
get_call,
|
||||
body_properties: Vec::new(),
|
||||
fetch_text_body_values: false,
|
||||
fetch_html_body_values: false,
|
||||
fetch_all_body_values: false,
|
||||
max_body_value_bytes: 0,
|
||||
}
|
||||
}
|
||||
|
||||
_impl!(get_call: GetCall<EmailObject>);
|
||||
_impl!(body_properties: Vec<String>);
|
||||
_impl!(fetch_text_body_values: bool);
|
||||
_impl!(fetch_html_body_values: bool);
|
||||
_impl!(fetch_all_body_values: bool);
|
||||
_impl!(max_body_value_bytes: u64);
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct EmailFilterCondition {
|
||||
@ -225,6 +252,29 @@ pub struct EmailFilterCondition {
|
||||
pub header: Vec<String>,
|
||||
}
|
||||
|
||||
impl EmailFilterCondition {
|
||||
_impl!(in_mailboxes: Vec<Id>);
|
||||
_impl!(in_mailbox_other_than: Vec<Id>);
|
||||
_impl!(before: UtcDate);
|
||||
_impl!(after: UtcDate);
|
||||
_impl!(min_size: Option<u64>);
|
||||
_impl!(max_size: Option<u64>);
|
||||
_impl!(all_in_thread_have_keyword: String);
|
||||
_impl!(some_in_thread_have_keyword: String);
|
||||
_impl!(none_in_thread_have_keyword: String);
|
||||
_impl!(has_keyword: String);
|
||||
_impl!(not_keyword: String);
|
||||
_impl!(has_attachment: Option<bool>);
|
||||
_impl!(text: String);
|
||||
_impl!(from: String);
|
||||
_impl!(to: String);
|
||||
_impl!(cc: String);
|
||||
_impl!(bcc: String);
|
||||
_impl!(subject: String);
|
||||
_impl!(body: String);
|
||||
_impl!(header: Vec<String>);
|
||||
}
|
||||
|
||||
impl FilterTrait<EmailObject> for EmailFilterCondition {}
|
||||
|
||||
// The following convenience properties are also specified for the Email
|
||||
|
@ -29,6 +29,15 @@ pub type UtcDate = String;
|
||||
|
||||
use super::rfc8620::Object;
|
||||
|
||||
macro_rules! get_request_no {
|
||||
($lock:expr) => {{
|
||||
let mut lck = $lock.lock().unwrap();
|
||||
let ret = *lck;
|
||||
*lck += 1;
|
||||
ret
|
||||
}};
|
||||
}
|
||||
|
||||
pub trait Method<OBJ: Object>: Serialize {
|
||||
const NAME: &'static str;
|
||||
}
|
||||
@ -68,19 +77,25 @@ pub struct Request {
|
||||
/* Why is this Value instead of Box<dyn Method<_>>? The Method trait cannot be made into a
|
||||
* Trait object because its serialize() will be generic. */
|
||||
method_calls: Vec<Value>,
|
||||
|
||||
#[serde(skip_serializing)]
|
||||
request_no: Arc<Mutex<usize>>,
|
||||
}
|
||||
|
||||
impl Request {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(request_no: Arc<Mutex<usize>>) -> Self {
|
||||
Request {
|
||||
using: USING,
|
||||
method_calls: Vec::new(),
|
||||
request_no,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_call<M: Method<O>, O: Object>(&mut self, call: M) {
|
||||
pub fn add_call<M: Method<O>, O: Object>(&mut self, call: M) -> usize {
|
||||
let seq = get_request_no!(self.request_no);
|
||||
self.method_calls
|
||||
.push(serde_json::to_value((M::NAME, call, "f")).unwrap());
|
||||
.push(serde_json::to_value((M::NAME, call, &format!("m{}", seq))).unwrap());
|
||||
seq
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,17 +115,19 @@ pub enum MethodCall {
|
||||
Empty {},
|
||||
}
|
||||
|
||||
pub fn get_mailboxes(conn: &mut JmapConnection) -> Result<FnvHashMap<FolderHash, JmapFolder>> {
|
||||
pub fn get_mailboxes(conn: &JmapConnection) -> Result<FnvHashMap<FolderHash, JmapFolder>> {
|
||||
let seq = get_request_no!(conn.request_no);
|
||||
let res = conn
|
||||
.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.post("https://jmap-proxy.local/jmap/fc32dffe-14e7-11ea-a277-2477037a1804/")
|
||||
.json(&json!({
|
||||
"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
|
||||
"methodCalls": [["Mailbox/get", {},
|
||||
format!("#m{}", conn.request_no + 1).as_str()]],
|
||||
format!("#m{}",seq).as_str()]],
|
||||
}))
|
||||
.send();
|
||||
conn.request_no += 1;
|
||||
|
||||
let mut v: JsonResponse =
|
||||
serde_json::from_str(&std::dbg!(res.unwrap().text().unwrap())).unwrap();
|
||||
@ -259,12 +276,13 @@ pub struct JmapRights {
|
||||
// fetchSearchSnippets: false
|
||||
// }, "call1"]
|
||||
// ]
|
||||
pub fn get_message_list(conn: &mut JmapConnection, folder: &JmapFolder) -> Result<Vec<String>> {
|
||||
pub fn get_message_list(conn: &JmapConnection, folder: &JmapFolder) -> Result<Vec<String>> {
|
||||
let seq = get_request_no!(conn.request_no);
|
||||
let email_call: EmailQueryCall = EmailQueryCall {
|
||||
filter: vec![EmailFilterCondition {
|
||||
filter: EmailFilterCondition {
|
||||
in_mailboxes: vec![folder.id.clone()],
|
||||
..Default::default()
|
||||
}],
|
||||
},
|
||||
collapse_threads: false,
|
||||
position: 0,
|
||||
fetch_threads: true,
|
||||
@ -285,9 +303,8 @@ pub fn get_message_list(conn: &mut JmapConnection, folder: &JmapFolder) -> Resul
|
||||
],
|
||||
};
|
||||
|
||||
let mut req = Request::new();
|
||||
let mut req = Request::new(conn.request_no.clone());
|
||||
req.add_call(email_call);
|
||||
std::dbg!(serde_json::to_string(&req));
|
||||
|
||||
/*
|
||||
{
|
||||
@ -328,37 +345,43 @@ pub fn get_message_list(conn: &mut JmapConnection, folder: &JmapFolder) -> Resul
|
||||
]]
|
||||
}
|
||||
*/
|
||||
/*
|
||||
r#"
|
||||
"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
|
||||
"methodCalls": [["Email/query", { "filter": {
|
||||
"inMailboxes": [ folder.id ]
|
||||
},
|
||||
"collapseThreads": false,
|
||||
"position": 0,
|
||||
"fetchThreads": true,
|
||||
"fetchMessages": true,
|
||||
"fetchMessageProperties": [
|
||||
"threadId",
|
||||
"mailboxId",
|
||||
"isUnread",
|
||||
"isFlagged",
|
||||
"isAnswered",
|
||||
"isDraft",
|
||||
"hasAttachment",
|
||||
"from",
|
||||
"to",
|
||||
"subject",
|
||||
"date",
|
||||
"preview"
|
||||
],
|
||||
}, format!("m{}", seq).as_str()]],
|
||||
});"
|
||||
);*/
|
||||
|
||||
std::dbg!(serde_json::to_string(&req));
|
||||
let res = conn
|
||||
.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.post("https://jmap-proxy.local/jmap/fc32dffe-14e7-11ea-a277-2477037a1804/")
|
||||
.json(&json!({
|
||||
"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
|
||||
"methodCalls": [["Email/query", { "filter": {
|
||||
"inMailboxes": [ folder.id ]
|
||||
},
|
||||
"collapseThreads": false,
|
||||
"position": 0,
|
||||
"fetchThreads": true,
|
||||
"fetchMessages": true,
|
||||
"fetchMessageProperties": [
|
||||
"threadId",
|
||||
"mailboxId",
|
||||
"isUnread",
|
||||
"isFlagged",
|
||||
"isAnswered",
|
||||
"isDraft",
|
||||
"hasAttachment",
|
||||
"from",
|
||||
"to",
|
||||
"subject",
|
||||
"date",
|
||||
"preview"
|
||||
],
|
||||
}, format!("#m{}", conn.request_no + 1).as_str()]],
|
||||
}))
|
||||
.json(&req)
|
||||
.send();
|
||||
|
||||
conn.request_no += 1;
|
||||
let mut v: JsonResponse = serde_json::from_str(&std::dbg!(res.unwrap().text().unwrap()))?;
|
||||
|
||||
let result: Response = v.method_responses.remove(0).1;
|
||||
@ -369,11 +392,35 @@ pub fn get_message_list(conn: &mut JmapConnection, folder: &JmapFolder) -> Resul
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_message(conn: &mut JmapConnection, ids: &[String]) -> Result<Vec<Envelope>> {
|
||||
pub fn get_message(conn: &JmapConnection, ids: &[String]) -> Result<Vec<Envelope>> {
|
||||
let seq = get_request_no!(conn.request_no);
|
||||
let email_call: EmailGetCall =
|
||||
EmailGetCall::new(GetCall::new().ids(Some(ids.iter().cloned().collect::<Vec<String>>())));
|
||||
|
||||
let mut req = Request::new(conn.request_no.clone());
|
||||
req.add_call(email_call);
|
||||
let res = conn
|
||||
.client
|
||||
.lock()
|
||||
.unwrap()
|
||||
.post("https://jmap-proxy.local/jmap/fc32dffe-14e7-11ea-a277-2477037a1804/")
|
||||
.json(&json!({
|
||||
.json(&req)
|
||||
.send();
|
||||
|
||||
let res_text = res?.text()?;
|
||||
let v: JsonResponse = serde_json::from_str(&res_text)?;
|
||||
let mut f = std::fs::File::create(std::dbg!(format!("/tmp/asdfsa{}", seq))).unwrap();
|
||||
use std::io::Write;
|
||||
f.write_all(
|
||||
serde_json::to_string_pretty(&serde_json::from_str::<Value>(&res_text)?)?.as_bytes(),
|
||||
)
|
||||
.unwrap();
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*json!({
|
||||
"using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
|
||||
"methodCalls": [["Email/get", {
|
||||
"ids": ids,
|
||||
@ -383,12 +430,7 @@ pub fn get_message(conn: &mut JmapConnection, ids: &[String]) -> Result<Vec<Enve
|
||||
"bodyProperties": [ "partId", "blobId", "size", "type" ],
|
||||
"fetchHTMLBodyValues": true,
|
||||
"maxBodyValueBytes": 256
|
||||
}, format!("#m{}", conn.request_no + 1).as_str()]],
|
||||
}, format!("m{}", seq).as_str()]],
|
||||
}))
|
||||
.send();
|
||||
conn.request_no += 1;
|
||||
|
||||
let v: JsonResponse = serde_json::from_str(&std::dbg!(res.unwrap().text().unwrap()))?;
|
||||
std::dbg!(&v);
|
||||
Ok(vec![])
|
||||
}
|
||||
*/
|
||||
|
@ -19,14 +19,18 @@
|
||||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use super::Id;
|
||||
use core::marker::PhantomData;
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
mod filters;
|
||||
pub use filters::*;
|
||||
mod comparator;
|
||||
pub use comparator::*;
|
||||
|
||||
use super::protocol::Method;
|
||||
use std::collections::HashMap;
|
||||
pub trait Object {}
|
||||
|
||||
// 5.1. /get
|
||||
@ -57,20 +61,76 @@ pub trait Object {}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GetCall<OBJ: Object, CALL: Method<OBJ>>
|
||||
pub struct JmapSession {
|
||||
capabilities: HashMap<String, CapabilitiesObject>,
|
||||
accounts: HashMap<Id, Account>,
|
||||
primary_accounts: Vec<Id>,
|
||||
username: String,
|
||||
api_url: String,
|
||||
download_url: String,
|
||||
|
||||
upload_url: String,
|
||||
event_source_url: String,
|
||||
state: String,
|
||||
#[serde(flatten)]
|
||||
extra_properties: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CapabilitiesObject {
|
||||
max_size_upload: u64,
|
||||
max_concurrent_upload: u64,
|
||||
max_size_request: u64,
|
||||
max_concurrent_requests: u64,
|
||||
max_calls_in_request: u64,
|
||||
max_objects_in_get: u64,
|
||||
max_objects_in_set: u64,
|
||||
collation_algorithms: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Account {
|
||||
name: String,
|
||||
is_personal: bool,
|
||||
is_read_only: bool,
|
||||
account_capabilities: HashMap<String, Value>,
|
||||
#[serde(flatten)]
|
||||
extra_properties: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GetCall<OBJ: Object>
|
||||
where
|
||||
OBJ: std::fmt::Debug + Serialize,
|
||||
{
|
||||
#[serde(skip_serializing_if = "String::is_empty")]
|
||||
account_id: String,
|
||||
pub account_id: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
ids: Option<Vec<String>>,
|
||||
pub ids: Option<Vec<String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
properties: Option<Vec<String>>,
|
||||
_ph: PhantomData<*const CALL>,
|
||||
__ph: PhantomData<*const OBJ>,
|
||||
pub properties: Option<Vec<String>>,
|
||||
_ph: PhantomData<*const OBJ>,
|
||||
}
|
||||
|
||||
impl<OBJ: Object> GetCall<OBJ>
|
||||
where
|
||||
OBJ: std::fmt::Debug + Serialize,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
account_id: String::new(),
|
||||
ids: None,
|
||||
properties: None,
|
||||
_ph: PhantomData,
|
||||
}
|
||||
}
|
||||
_impl!(account_id: String);
|
||||
_impl!(ids: Option<Vec<String>>);
|
||||
_impl!(properties: Option<Vec<String>>);
|
||||
}
|
||||
// The response has the following arguments:
|
||||
//
|
||||
// o accountId: "Id"
|
||||
@ -128,6 +188,7 @@ pub struct GetResponse<T> {
|
||||
enum JmapError {
|
||||
RequestTooLarge,
|
||||
InvalidArguments,
|
||||
InvalidResultReference,
|
||||
}
|
||||
|
||||
// 5.5. /query
|
||||
@ -321,11 +382,39 @@ where
|
||||
_ph: PhantomData<*const OBJ>,
|
||||
}
|
||||
|
||||
fn bool_false() -> bool {
|
||||
impl<F: FilterTrait<OBJ>, OBJ: Object> QueryCall<F, OBJ>
|
||||
where
|
||||
OBJ: std::fmt::Debug + Serialize,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
account_id: String::new(),
|
||||
filter: None,
|
||||
sort: None,
|
||||
position: 0,
|
||||
anchor: None,
|
||||
anchor_offset: 0,
|
||||
limit: None,
|
||||
calculate_total: false,
|
||||
_ph: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
_impl!(account_id: String);
|
||||
_impl!(filter: Option<Filter<F, OBJ>>);
|
||||
_impl!(sort: Option<Comparator<OBJ>>);
|
||||
_impl!(position: u64);
|
||||
_impl!(anchor: Option<String>);
|
||||
_impl!(anchor_offset: u64);
|
||||
_impl!(limit: Option<u64>);
|
||||
_impl!(calculate_total: bool);
|
||||
}
|
||||
|
||||
pub fn bool_false() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn bool_true() -> bool {
|
||||
pub fn bool_true() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,23 @@ pub struct Comparator<OBJ: Object> {
|
||||
_ph: PhantomData<*const OBJ>,
|
||||
}
|
||||
|
||||
impl<OBJ: Object> Comparator<OBJ> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
property: String::new(),
|
||||
is_ascending: true,
|
||||
collation: None,
|
||||
additional_properties: Vec::new(),
|
||||
_ph: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
_impl!(property: String);
|
||||
_impl!(is_ascending: bool);
|
||||
_impl!(collation: Option<String>);
|
||||
_impl!(additional_properties: Vec<String>);
|
||||
}
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub enum FilterOperator {
|
||||
|
Loading…
Reference in New Issue
Block a user