Skip to main content

potree_auth/common/utils/http/
render_error.rs

1use axum::response::IntoResponse;
2use http::StatusCode;
3
4use crate::authorization::domain::action::Action;
5use crate::authorization::domain::resource::ResourceIdentifier;
6use crate::authorization::domain::resource::ResourceType;
7use crate::user::domain::User;
8
9/// Errors that can be experienced by a rendering (e.g. HTML) `axum` route
10/// handler.
11///
12/// All rendering route handlers should return this error. All domain specific
13/// errors should be marshalled into an [`RenderError`] to ensure consistent
14/// HTTP responses.
15///
16/// > A [`RenderError`] is different to an
17/// > [`ApiError`][`super::api_error::ApiError`] in that it responds with a user
18/// > facing error (i.e. HTML).
19#[derive(Debug, Clone, thiserror::Error)]
20pub enum RenderError {
21    #[error("unable to extract router state")]
22    StateExtraction,
23
24    #[error("unable to find resource: {resource_name}")]
25    ResourceNotFound { resource_name: String },
26
27    #[error("{} is not authorized to {} the {:?}: {:?}", user.name, action, resource_type, resource_identifier)]
28    NotAuthorized {
29        user: Box<User>,
30        action: Action,
31        resource_identifier: Option<ResourceIdentifier>,
32        resource_type: ResourceType,
33    },
34
35    #[error("user is not authenticated")]
36    NotAuthenticated,
37
38    #[error("the server is not configured correctly: {message}")]
39    ServerConfiguration { message: String },
40
41    #[error("a generic server error: {message}")]
42    ServerError { message: String },
43
44    #[error("an error was experienced during authentication: {message}")]
45    AuthenticationFlow { message: String },
46
47    #[error("there is an issue with the the server infrastructure: {message}")]
48    Infrastucture { message: String },
49}
50
51/// This should really be updated to redirect the user to an error page.
52impl IntoResponse for RenderError {
53    fn into_response(self) -> axum::response::Response {
54        // Log the error.
55        tracing::error!("{self}");
56
57        // Generate a response to send to the client.
58        match self {
59            RenderError::StateExtraction
60            | RenderError::ServerConfiguration { .. }
61            | RenderError::ServerError { .. }
62            | RenderError::Infrastucture { .. } => {
63                (StatusCode::INTERNAL_SERVER_ERROR).into_response()
64            }
65            RenderError::ResourceNotFound { .. } => {
66                (StatusCode::NOT_FOUND, self.to_string()).into_response()
67            }
68            RenderError::NotAuthorized { .. } => {
69                (StatusCode::FORBIDDEN, self.to_string()).into_response()
70            }
71            RenderError::NotAuthenticated | RenderError::AuthenticationFlow { .. } => {
72                (StatusCode::UNAUTHORIZED).into_response()
73            }
74        }
75    }
76}