use std::{borrow::Cow, collections::HashMap}; use serde::{Deserialize, Serialize}; use serde_json::Value; use strum::Display; use crate::endpoints::{Argument, Arguments, Invocation}; #[derive(Serialize, Deserialize, Clone, Debug)] pub struct RequestError { #[serde(rename = "type")] pub type_: ProblemType, pub status: u16, pub detail: Cow<'static, str>, #[serde(flatten)] pub meta: HashMap, } #[derive(Serialize, Deserialize, Clone, Debug)] pub enum ProblemType { /// The client included a capability in the "using" property of the /// request that the server does not support. #[serde(rename = "urn:ietf:params:jmap:error:unknownCapability")] UnknownCapability, /// The content type of the request was not "application/json" or the /// request did not parse as I-JSON. #[serde(rename = "urn:ietf:params:jmap:error:notJSON")] NotJson, /// The request parsed as JSON but did not match the type signature of /// the Request object. #[serde(rename = "urn:ietf:params:jmap:error:notRequest")] NotRequest, /// The request was not processed as it would have exceeded one of the /// request limits defined on the capability object, such as /// maxSizeRequest, maxCallsInRequest, or maxConcurrentRequests. A /// "limit" property MUST also be present on the "problem details" /// object, containing the name of the limit being applied. #[serde(rename = "urn:ietf:params:jmap:error:limit")] OverLimit, } /// If a method encounters an error, the appropriate "error" response /// MUST be inserted at the current point in the "methodResponses" array /// and, unless otherwise specified, further processing MUST NOT happen /// within that method call. /// /// Any further method calls in the request MUST then be processed as /// normal. Errors at the method level MUST NOT generate an HTTP-level /// error. #[derive(Serialize, Deserialize, Debug, Copy, Clone, Display)] #[serde(tag = "type")] pub enum MethodError { /// Some internal server resource was temporarily unavailable. /// /// Attempting the same operation later (perhaps after a backoff with a /// random factor) may succeed. ServerUnavailable, /// An unexpected or unknown error occurred during the processing of the call. /// /// The method call made no changes to the server's state. Attempting the /// same operation again is expected to fail again. Contacting the service /// administrator is likely necessary to resolve this problem if it is /// persistent. ServerFail, /// Some, but not all, expected changes described by the method occurred. /// /// The client MUST resynchronise impacted data to determine server state. /// /// Use of this error is strongly discouraged. ServerPartialFail, /// The server does not recognise this method name. UnknownMethod, /// One of the arguments is of the wrong type or is otherwise invalid, or a /// required argument is missing. A "description" property MAY be present to /// help debug with an explanation of what the problem was. This is a /// non-localised string, and it is not intended to be shown directly to /// end users. InvalidArguments, /// The method used a result reference for one of its arguments (see /// Section 3.7), but this failed to resolve. InvalidResultReference, /// The method and arguments are valid, but executing the method would /// violate an Access Control List (ACL) or other permissions policy. Forbidden, /// The accountId does not correspond to a valid account. AccountNotFound, /// The accountId given corresponds to a valid account, but the account /// does not support this method or data type. AccountNotSupportedByMethod, /// This method modifies state, but the account is read-only (as returned on /// the corresponding Account object in the JMAP Session resource). AccountReadOnly, } impl MethodError { pub fn into_invocation(self, request_id: Cow<'_, str>) -> Invocation<'_> { let mut arguments = Arguments::default(); arguments.0.insert( Cow::Borrowed("type"), Argument::Absolute(Value::String(self.to_string())), ); Invocation { name: "error".into(), arguments, request_id, } } }