use serde::Deserialize;
use jmap_types::{Id, State};
use super::{ChangesResponse, GetResponse};
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Quota {
pub id: Id,
pub name: String,
pub scope: crate::types::QuotaScope,
pub resource_type: String,
pub types: Vec<String>,
pub used: u64,
pub hard_limit: u64,
#[serde(default)]
pub warn_limit: Option<u64>,
#[serde(default)]
pub soft_limit: Option<u64>,
#[serde(default)]
pub description: Option<String>,
#[serde(flatten, default, skip_serializing_if = "serde_json::Map::is_empty")]
pub extra: serde_json::Map<String, serde_json::Value>,
}
impl super::SessionClient {
pub async fn quota_get(&self) -> Result<GetResponse<Quota>, jmap_base_client::ClientError> {
let (api_url, account_id) = self.session_parts()?;
let args = serde_json::json!({
"accountId": account_id,
"ids": serde_json::Value::Null,
});
let req = super::build_request("Quota/get", args, super::USING_QUOTA);
let resp = self.call_internal(api_url, &req).await?;
jmap_base_client::extract_response(&resp, super::CALL_ID)
}
pub async fn quota_changes(
&self,
since_state: &State,
max_changes: Option<u64>,
) -> Result<ChangesResponse, jmap_base_client::ClientError> {
if since_state.as_ref().is_empty() {
return Err(jmap_base_client::ClientError::InvalidArgument(
"quota_changes: since_state may not be empty".into(),
));
}
let (api_url, account_id) = self.session_parts()?;
let mut args = serde_json::json!({
"accountId": account_id,
"sinceState": since_state,
});
if let Some(mc) = max_changes {
args["maxChanges"] = mc.into();
}
let req = super::build_request("Quota/changes", args, super::USING_QUOTA);
let resp = self.call_internal(api_url, &req).await?;
jmap_base_client::extract_response(&resp, super::CALL_ID)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn quota_preserves_vendor_extras() {
let raw = json!({
"id": "Q1",
"name": "Message Storage",
"scope": "account",
"resourceType": "octets",
"types": ["Message"],
"used": 1024,
"hardLimit": 1048576,
"acmeCorpBillingTier": "enterprise"
});
let obj: Quota = serde_json::from_value(raw).expect("Quota must deserialize");
assert_eq!(
obj.extra
.get("acmeCorpBillingTier")
.and_then(|v| v.as_str()),
Some("enterprise")
);
}
}