about summary refs log tree commit diff
path: root/util/src/error.rs
diff options
context:
space:
mode:
authorVika <vika@fireburn.ru>2023-07-29 21:59:56 +0300
committerVika <vika@fireburn.ru>2023-07-29 21:59:56 +0300
commit0617663b249f9ca488e5de652108b17d67fbaf45 (patch)
tree11564b6c8fa37bf9203a0a4cc1c4e9cc088cb1a5 /util/src/error.rs
parent26c2b79f6a6380ae3224e9309b9f3352f5717bd7 (diff)
Moved the entire Kittybox tree into the root
Diffstat (limited to 'util/src/error.rs')
-rw-r--r--util/src/error.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/util/src/error.rs b/util/src/error.rs
new file mode 100644
index 0000000..1c95020
--- /dev/null
+++ b/util/src/error.rs
@@ -0,0 +1,95 @@
+use serde::{Deserialize, Serialize};
+use http::StatusCode;
+use axum_core::response::{Response, IntoResponse};
+
+#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
+#[serde(rename_all = "snake_case")]
+/// Kinds of errors that can happen within a Micropub operation.
+pub enum ErrorType {
+    /// An erroneous attempt to create something that already exists.
+    AlreadyExists,
+    /// Current user is expressly forbidden from performing this action.
+    Forbidden,
+    /// The Micropub server experienced an internal error.
+    InternalServerError,
+    /// The request was invalid or malformed.
+    InvalidRequest,
+    /// The provided OAuth2 scopes were insufficient to allow performing this action.
+    InvalidScope,
+    /// There was no token or other means of authorization in the request.
+    NotAuthorized,
+    /// Whatever was requested was not found.
+    NotFound,
+    /// The request payload was of a type unsupported by the Micropub endpoint.
+    UnsupportedMediaType,
+}
+
+/// Representation of the Micropub API error.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct MicropubError {
+    /// General kind of an error that occured.
+    pub error: ErrorType,
+    /// A human-readable error description intended for application developers.
+    // TODO use Cow<'static, str> to save on heap allocations
+    pub error_description: String,
+}
+
+impl std::error::Error for MicropubError {}
+
+impl std::fmt::Display for MicropubError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str("Micropub error: ")?;
+        f.write_str(&self.error_description)
+    }
+}
+
+impl From<serde_json::Error> for MicropubError {
+    fn from(err: serde_json::Error) -> Self {
+        use ErrorType::*;
+        Self {
+            error: InvalidRequest,
+            error_description: err.to_string(),
+        }
+    }
+}
+
+impl MicropubError {
+    /// Create a new Micropub error.
+    pub fn new(error: ErrorType, error_description: &str) -> Self {
+        Self {
+            error,
+            error_description: error_description.to_owned(),
+        }
+    }
+}
+
+impl From<&MicropubError> for StatusCode {
+    fn from(err: &MicropubError) -> Self {
+        use ErrorType::*;
+        match err.error {
+            AlreadyExists => StatusCode::CONFLICT,
+            Forbidden => StatusCode::FORBIDDEN,
+            InternalServerError => StatusCode::INTERNAL_SERVER_ERROR,
+            InvalidRequest => StatusCode::BAD_REQUEST,
+            InvalidScope => StatusCode::UNAUTHORIZED,
+            NotAuthorized => StatusCode::UNAUTHORIZED,
+            NotFound => StatusCode::NOT_FOUND,
+            UnsupportedMediaType => StatusCode::UNSUPPORTED_MEDIA_TYPE,
+        }
+    }
+}
+impl From<MicropubError> for StatusCode {
+    fn from(err: MicropubError) -> Self {
+        (&err).into()
+    }
+}
+
+impl IntoResponse for MicropubError {
+    fn into_response(self) -> Response {
+        IntoResponse::into_response((
+            StatusCode::from(&self),
+            [("Content-Type", "application/json")],
+            serde_json::to_string(&self).unwrap(),
+        ))
+    }
+}