features, cleanup and bug fixes #26
10 changed files with 225 additions and 214 deletions
reactor Error types
better separate response error types used for route handlers and other errors - with an exception of PresentationError
commit
d98df7839d
43
src/error.rs
43
src/error.rs
|
|
@ -42,11 +42,6 @@ impl Display for LoginRequired {
|
|||
}
|
||||
}
|
||||
impl Error for LoginRequired {}
|
||||
impl ResponseError for LoginRequired {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
StatusCode::UNAUTHORIZED
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum MultipartFieldError {
|
||||
|
|
@ -83,39 +78,18 @@ pub enum MultipartFieldError {
|
|||
Runtime(#[from] tokio::task::JoinError),
|
||||
}
|
||||
|
||||
impl ResponseError for MultipartFieldError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
MultipartFieldError::IOError(_) | MultipartFieldError::Runtime(_) => {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
MultipartFieldError::ContentTooLarge { .. }
|
||||
| MultipartFieldError::Date { .. }
|
||||
| MultipartFieldError::MultipartError(_)
|
||||
| MultipartFieldError::NotAFile { field: _ }
|
||||
| MultipartFieldError::TooManyOccurrences { .. }
|
||||
| MultipartFieldError::UTF8Error(_)
|
||||
| MultipartFieldError::MissingField { field: _ }
|
||||
| MultipartFieldError::InvalidAddress(_) => StatusCode::BAD_REQUEST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub(crate) enum PresentationError {
|
||||
#[error("Failed to render page template: {0}")]
|
||||
Render(#[from] RenderError),
|
||||
#[error("Failed to generate URL for route: {0}")]
|
||||
Url(#[from] UrlGenerationError),
|
||||
#[error("Couldn't generate response as login is required")]
|
||||
LoginRequired(#[from] LoginRequired),
|
||||
}
|
||||
|
||||
impl ResponseError for PresentationError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
Self::Render(_) | Self::Url(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Self::LoginRequired(_) => StatusCode::UNAUTHORIZED,
|
||||
}
|
||||
}
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
|
|
@ -185,8 +159,8 @@ mod ldap_response_code {
|
|||
pub const UNAVAILABLE: u32 = 52;
|
||||
}
|
||||
|
||||
impl ResponseError for AuthenticationError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
impl AuthenticationError {
|
||||
pub(crate) fn as_status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
AuthenticationError::Ldap(ldap_error) => match ldap_error {
|
||||
LdapError::LdapResult { result } => match result.rc {
|
||||
|
|
@ -203,3 +177,16 @@ impl ResponseError for AuthenticationError {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("Authentication failed: {0}")]
|
||||
pub(crate) struct LoginResponseError(#[from] AuthenticationError);
|
||||
|
||||
impl ResponseError for LoginResponseError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
self.0.as_status_code()
|
||||
}
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
default_error_response(self, self.status_code())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::time::Duration;
|
|||
use actix_web::error::UrlGenerationError;
|
||||
use actix_web::{HttpRequest, Result};
|
||||
use chrono::{FixedOffset, TimeZone, Timelike};
|
||||
use error::{DeleteError, SaveError};
|
||||
use error::DeleteError;
|
||||
use lettre::Address;
|
||||
use log::{debug, error, info, warn};
|
||||
use rand::distributions::DistString;
|
||||
|
|
@ -22,6 +22,7 @@ use toml::value::Datetime;
|
|||
|
||||
use crate::auth::User;
|
||||
use crate::error::PresentationError;
|
||||
use crate::job_offers::error::SaveError;
|
||||
use crate::route::{JOBOFFER_ATTACHMENT_ROUTE, PREVIEW_ATTACHMENT_ROUTE};
|
||||
use crate::route::{JOBOFFER_DELETION_ROUTE, JOBOFFER_PUBLISH_ROUTE, JOBOFFER_UNPUBLISH_ROUTE};
|
||||
use crate::util::{toml_date_to_chrono_date, toml_datetime_to_chrono_datetime};
|
||||
|
|
|
|||
|
|
@ -6,26 +6,20 @@ use http::StatusCode;
|
|||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub(crate) enum SaveError {
|
||||
#[error("Creating a new Job Offer failed as the generated ID is already taken")]
|
||||
AlreadyExists,
|
||||
#[error("{0}")]
|
||||
IO(#[from] std::io::Error),
|
||||
#[error("{0}")]
|
||||
Persist(#[from] tempfile::PersistError),
|
||||
#[error("Could not serialize Job Offer: {0}")]
|
||||
Serialize(#[from] toml::ser::Error),
|
||||
#[error("Could not generate url for confirmation link: {0}")]
|
||||
Url(#[from] UrlGenerationError),
|
||||
#[error("Could not send Confirmation E-Mail: {0}")]
|
||||
Email(#[from] EmailError),
|
||||
#[error("The Runtime encountered an error!")]
|
||||
#[error("The Runtime encountered an error!: {0}")]
|
||||
Runtime(#[from] tokio::task::JoinError),
|
||||
#[error("A reviewer-only setting was specified, but no valid session was found.")]
|
||||
LoginRequired(#[from] LoginRequired),
|
||||
#[error("Creating a new Job Offer failed as the generated ID is already taken")]
|
||||
AlreadyExists,
|
||||
}
|
||||
|
||||
impl ResponseError for SaveError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
impl SaveError {
|
||||
pub(crate) fn as_status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
// add special handling of ErrorKind::StorageFull | FilesystemQuotaExceeded once those error kinds are stabilized
|
||||
/*
|
||||
|
|
@ -42,14 +36,35 @@ impl ResponseError for SaveError {
|
|||
{
|
||||
StatusCode::INSUFFICIENT_STORAGE
|
||||
}*/
|
||||
SaveError::Persist(_)
|
||||
| SaveError::IO(_)
|
||||
SaveError::IO(_)
|
||||
| SaveError::Persist(_)
|
||||
| SaveError::Serialize(_)
|
||||
| SaveError::Url(_)
|
||||
| SaveError::Runtime(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
SaveError::AlreadyExists => StatusCode::CONFLICT,
|
||||
SaveError::Email(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
SaveError::LoginRequired(_) => StatusCode::UNAUTHORIZED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub(crate) enum SaveResponseError {
|
||||
#[error("Could not generate url for confirmation link: {0}")]
|
||||
Url(#[from] UrlGenerationError),
|
||||
#[error("Could not save job offer: {0}")]
|
||||
Save(#[from] SaveError),
|
||||
#[error("Could not send Confirmation E-Mail: {0}")]
|
||||
Email(#[from] EmailError),
|
||||
#[error("A reviewer-only setting was specified, but no valid session was found.")]
|
||||
Login(#[from] LoginRequired),
|
||||
}
|
||||
|
||||
impl ResponseError for SaveResponseError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
SaveResponseError::Save(inner) => inner.as_status_code(),
|
||||
SaveResponseError::Url(_) | SaveResponseError::Email(_) => {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
SaveResponseError::Login(_) => StatusCode::UNAUTHORIZED,
|
||||
}
|
||||
}
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
|
|
@ -72,17 +87,3 @@ pub(crate) enum DeleteError {
|
|||
#[error("{0}")]
|
||||
IO(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
impl ResponseError for DeleteError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
DeleteError::IO(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
let status_code = self.status_code();
|
||||
match self {
|
||||
DeleteError::IO(inner) => default_error_response(inner, status_code),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use log::{error, trace};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::error::{AuthenticationError, PresentationError};
|
||||
use crate::error::{LoginResponseError, PresentationError};
|
||||
use crate::route::HTML_CONTENT;
|
||||
use crate::{template, ServerConfig};
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ pub(crate) async fn login_post(
|
|||
query: web::Query<LoginQuery>,
|
||||
config: web::Data<ServerConfig>,
|
||||
session: Session,
|
||||
) -> Result<HttpResponse, AuthenticationError> {
|
||||
) -> Result<HttpResponse, LoginResponseError> {
|
||||
let result = crate::auth::User::login(&form.username, &form.password, &session, &config).await;
|
||||
|
||||
match result {
|
||||
|
|
@ -99,7 +99,7 @@ pub(crate) async fn login_post(
|
|||
}
|
||||
Err(err) => {
|
||||
error!("failed to perform authentication for login: {}", err);
|
||||
Err(err)
|
||||
Err(err.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use crate::auth::User;
|
||||
use crate::error::{AuthenticationError, LoginRequired, MultipartFieldError, PresentationError};
|
||||
use crate::job_offers::error::{DeleteError, SaveError};
|
||||
use crate::error::{MultipartFieldError, PresentationError};
|
||||
use crate::job_offers::error::SaveResponseError;
|
||||
use crate::route::LOGIN_ROUTE;
|
||||
use crate::{route, ServerConfig};
|
||||
|
||||
use crate::route::job_offer::error::{ConfirmationError, DeletionError, SubmissionError};
|
||||
use crate::route::job_offer::error::{
|
||||
ConfirmationResponseError, DeletionResponseError, SubmissionResponseError, SyncResponseError,
|
||||
};
|
||||
use actix_session::SessionExt;
|
||||
use actix_web::dev::ServiceResponse;
|
||||
use actix_web::error::UrlGenerationError;
|
||||
|
|
@ -22,9 +24,9 @@ use url::Url;
|
|||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Some error occurred while attempting to display an error page")]
|
||||
pub struct ErrorHandlerError;
|
||||
pub struct ErrorHandlerResponseError;
|
||||
|
||||
impl ResponseError for ErrorHandlerError {}
|
||||
impl ResponseError for ErrorHandlerResponseError {}
|
||||
|
||||
pub(crate) fn generic_server_error_handler<B>(
|
||||
res: ServiceResponse,
|
||||
|
|
@ -32,8 +34,8 @@ pub(crate) fn generic_server_error_handler<B>(
|
|||
title: &str,
|
||||
msg: Option<&str>,
|
||||
) -> Result<ErrorHandlerResponse<B>, actix_web::Error> {
|
||||
let hb: &Data<Handlebars> = res.request().app_data().ok_or(ErrorHandlerError)?;
|
||||
let config: &Data<ServerConfig> = res.request().app_data().ok_or(ErrorHandlerError)?;
|
||||
let hb: &Data<Handlebars> = res.request().app_data().ok_or(ErrorHandlerResponseError)?;
|
||||
let config: &Data<ServerConfig> = res.request().app_data().ok_or(ErrorHandlerResponseError)?;
|
||||
|
||||
let base = route::base(res.request(), config, title)?;
|
||||
let session = res.get_session();
|
||||
|
|
@ -61,19 +63,15 @@ pub(crate) fn internal_server_error_handler<B>(
|
|||
res: ServiceResponse,
|
||||
) -> Result<ErrorHandlerResponse<B>, actix_web::Error> {
|
||||
if let Some(err) = res.response().error() {
|
||||
if let Some(err) = err.as_error::<SaveError>() {
|
||||
if let Some(err) = err.as_error::<SaveResponseError>() {
|
||||
error!("Internal Server Error due to SaveError: {}", err)
|
||||
} else if let Some(err) = err.as_error::<DeleteError>() {
|
||||
} else if let Some(err) = err.as_error::<DeletionResponseError>() {
|
||||
error!("Internal Server Error due to DeleteError: {}", err)
|
||||
} else if let Some(err) = err.as_error::<ErrorHandlerError>() {
|
||||
} else if let Some(err) = err.as_error::<ErrorHandlerResponseError>() {
|
||||
error!("Internal Server Error due to ErrorHandlerError: {}", err)
|
||||
} else if let Some(err) = err.as_error::<MultipartFieldError>() {
|
||||
error!("Internal Server Error due to MultipartFieldError: {}", err)
|
||||
} else if let Some(err) = err.as_error::<PresentationError>() {
|
||||
error!("Internal Server Error due to PresentationError: {}", err)
|
||||
} else if let Some(err) = err.as_error::<AuthenticationError>() {
|
||||
error!("Internal Server Error due to AuthenticationError: {}", err)
|
||||
} else if let Some(err) = err.as_error::<SubmissionError>() {
|
||||
} else if let Some(err) = err.as_error::<SubmissionResponseError>() {
|
||||
error!("Internal Server Error due to SubmissionError: {}", err)
|
||||
} else {
|
||||
error!("Unknown Error Type for Internal Server Error")
|
||||
|
|
@ -100,15 +98,15 @@ pub(crate) fn bad_request<B>(
|
|||
) -> Result<ErrorHandlerResponse<B>, actix_web::Error> {
|
||||
let msg;
|
||||
let msg = if let Some(err) = res.response().error() {
|
||||
if let Some(err) = err.as_error::<SubmissionError>() {
|
||||
if let Some(err) = err.as_error::<SubmissionResponseError>() {
|
||||
match err {
|
||||
SubmissionError::MissingLinkOrAttachment => {
|
||||
SubmissionResponseError::MissingLinkOrAttachment => {
|
||||
Some("Es muss mindestens ein Link oder ein Anhang angegeben werden.")
|
||||
}
|
||||
SubmissionError::Form(MultipartFieldError::Date { err:_ }) => {
|
||||
SubmissionResponseError::Form(MultipartFieldError::Date { err:_ }) => {
|
||||
Some("Eine Datumsangabe entsprach nicht dem erwarteten Format.")
|
||||
}
|
||||
SubmissionError::Form(MultipartFieldError::ContentTooLarge {
|
||||
SubmissionResponseError::Form(MultipartFieldError::ContentTooLarge {
|
||||
field,
|
||||
max_byte_size,
|
||||
}) => {
|
||||
|
|
@ -117,32 +115,32 @@ pub(crate) fn bad_request<B>(
|
|||
);
|
||||
Some(msg.as_str())
|
||||
}
|
||||
SubmissionError::Form(MultipartFieldError::TooManyOccurrences { field, limit }) => {
|
||||
SubmissionResponseError::Form(MultipartFieldError::TooManyOccurrences { field, limit }) => {
|
||||
msg = format!(
|
||||
"Das Feld mit der ID {field} wurde zu oft vorhanden, erlaubt sind {limit} vorkommen."
|
||||
);
|
||||
Some(msg.as_str())
|
||||
}
|
||||
SubmissionError::Form(MultipartFieldError::MultipartError(mpe)) => {
|
||||
SubmissionResponseError::Form(MultipartFieldError::MultipartError(mpe)) => {
|
||||
warn!("{}", mpe);
|
||||
msg = format!("{}", mpe);
|
||||
Some(msg.as_str())
|
||||
}
|
||||
SubmissionError::Form(MultipartFieldError::NotAFile { field }) => {
|
||||
SubmissionResponseError::Form(MultipartFieldError::NotAFile { field }) => {
|
||||
msg = format!(
|
||||
"Das Feld mit der ID {field} erwartet eine Datei, aber der zugehörige ContentDisposition-Header enthielt keinen Dateinamen."
|
||||
);
|
||||
Some(msg.as_str())
|
||||
}
|
||||
SubmissionError::Form(MultipartFieldError::MissingField { field }) => {
|
||||
SubmissionResponseError::Form(MultipartFieldError::MissingField { field }) => {
|
||||
msg =
|
||||
format!("Das Feld mit der ID {field} fehlt obwohl es nicht optional ist.");
|
||||
Some(msg.as_str())
|
||||
}
|
||||
SubmissionError::Form(MultipartFieldError::UTF8Error(_err)) => {
|
||||
SubmissionResponseError::Form(MultipartFieldError::UTF8Error(_err)) => {
|
||||
Some("Ein Feld das im UTF-8 format erwartet wurde konnte nicht als UTF-8 geparst werden.")
|
||||
}
|
||||
SubmissionError::Form(MultipartFieldError::InvalidAddress(reason)) => {
|
||||
SubmissionResponseError::Form(MultipartFieldError::InvalidAddress(reason)) => {
|
||||
Some(match reason {
|
||||
AddressError::MissingParts => { "Unvollständige E-Mail Address" }
|
||||
AddressError::Unbalanced => { "Unausgeglichene Klammern '<' & '>' in E-Mail Address. " }
|
||||
|
|
@ -150,11 +148,11 @@ pub(crate) fn bad_request<B>(
|
|||
AddressError::InvalidDomain => { "Der Host/Domain Teil (nach dem @) der E-Mail Address ist ungültig." }
|
||||
})
|
||||
}
|
||||
SubmissionError::Save(_)
|
||||
| SubmissionError::TooManyRequests
|
||||
| SubmissionError::Render(_)
|
||||
| SubmissionError::Form(MultipartFieldError::IOError(_))
|
||||
| SubmissionError::Form(MultipartFieldError::Runtime(_)) => {
|
||||
SubmissionResponseError::Save(_)
|
||||
| SubmissionResponseError::TooManyRequests
|
||||
| SubmissionResponseError::Render(_)
|
||||
| SubmissionResponseError::Form(MultipartFieldError::IOError(_))
|
||||
| SubmissionResponseError::Form(MultipartFieldError::Runtime(_)) => {
|
||||
error!(
|
||||
"Response Status Code (Bad Request) and Error appear to disagree : {}",
|
||||
err
|
||||
|
|
@ -162,17 +160,17 @@ pub(crate) fn bad_request<B>(
|
|||
None
|
||||
}
|
||||
}
|
||||
} else if let Some(err) = err.as_error::<ConfirmationError>() {
|
||||
} else if let Some(err) = err.as_error::<ConfirmationResponseError>() {
|
||||
match err {
|
||||
ConfirmationError::InvalidRequest => {
|
||||
ConfirmationResponseError::InvalidRequest => {
|
||||
Some("Die Stellenanzeige erwartet keine Bestätigung, die Stellenanzeigen ID ist ungültig oder der Bestätigungstoken is ungültig.")
|
||||
}
|
||||
ConfirmationError::Save(_)
|
||||
| ConfirmationError::Delete(_)
|
||||
| ConfirmationError::SuccessRenderError(_)
|
||||
| ConfirmationError::RenderError(_)
|
||||
| ConfirmationError::Url(_)
|
||||
| ConfirmationError::Presentation(_) => {
|
||||
ConfirmationResponseError::Save(_)
|
||||
| ConfirmationResponseError::Delete(_)
|
||||
| ConfirmationResponseError::SuccessRenderError(_)
|
||||
| ConfirmationResponseError::RenderError(_)
|
||||
| ConfirmationResponseError::Url(_)
|
||||
| ConfirmationResponseError::Presentation(_) => {
|
||||
error!(
|
||||
"Response Status Code (Bad Request) and Error appear to disagree : {}",
|
||||
err
|
||||
|
|
@ -180,17 +178,17 @@ pub(crate) fn bad_request<B>(
|
|||
None
|
||||
}
|
||||
}
|
||||
} else if let Some(err) = err.as_error::<MultipartFieldError>() {
|
||||
warn!("Unexpected MultipartFieldError as top level error!");
|
||||
msg = err.to_string();
|
||||
Some(msg.as_str())
|
||||
} else if let Some(err) = err.as_error::<DeletionError>() {
|
||||
} else if let Some(err) = err.as_error::<DeletionResponseError>() {
|
||||
match err {
|
||||
DeletionError::Delete(err) => {
|
||||
DeletionResponseError::Presentation(err) => {
|
||||
warn!("Failed to present deletion response: {}", err);
|
||||
Some("Failed to generate response.")
|
||||
}
|
||||
DeletionResponseError::Delete(err) => {
|
||||
warn!("Couldn't delete Job Offer: {}", err);
|
||||
Some("Could not delete a Job Offer")
|
||||
}
|
||||
DeletionError::Login(_) => {
|
||||
DeletionResponseError::Login(_) => {
|
||||
error!(
|
||||
"Response Status Code (Bad Request) and Error appear to disagree : {}",
|
||||
err
|
||||
|
|
@ -226,23 +224,22 @@ pub(crate) fn unauthorized_error_handler<B>(
|
|||
.response()
|
||||
.error()
|
||||
.and_then(|err| {
|
||||
err.as_error::<LoginRequired>()
|
||||
.or_else(|| {
|
||||
err.as_error::<SaveError>().and_then(|elem| match elem {
|
||||
SaveError::LoginRequired(login) => Some(login),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
err.as_error::<DeletionError>().and_then(|elem| match elem {
|
||||
DeletionError::Login(login) => Some(login),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
err.as_error::<PresentationError>()
|
||||
err.as_error::<SaveResponseError>()
|
||||
.and_then(|elem| match elem {
|
||||
PresentationError::LoginRequired(login) => Some(login),
|
||||
SaveResponseError::Login(login) => Some(login),
|
||||
_ => None,
|
||||
})
|
||||
.or_else(|| {
|
||||
err.as_error::<DeletionResponseError>()
|
||||
.and_then(|elem| match elem {
|
||||
DeletionResponseError::Login(login) => Some(login),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
.or_else(|| {
|
||||
err.as_error::<SyncResponseError>()
|
||||
.and_then(|elem| match elem {
|
||||
SyncResponseError::Login(login) => Some(login),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use actix_session::Session;
|
|||
use actix_web::{
|
||||
get, http::header, post, web, web::ServiceConfig, HttpRequest, HttpResponse, Responder, Result,
|
||||
};
|
||||
use error::AttachmentError;
|
||||
use error::AttachmentResponseError;
|
||||
use handlebars::Handlebars;
|
||||
use http::header::CONTENT_TYPE;
|
||||
use serde::Deserialize;
|
||||
|
|
@ -17,7 +17,7 @@ pub(crate) mod error;
|
|||
use crate::auth::User;
|
||||
use crate::error::PresentationError;
|
||||
use crate::job_offers::JobOffers;
|
||||
use crate::route::job_offer::error::SyncError;
|
||||
use crate::route::job_offer::error::SyncResponseError;
|
||||
use crate::route::{HTML_CONTENT, JSON_CONTENT};
|
||||
use crate::server_config::ServerConfig;
|
||||
use crate::template;
|
||||
|
|
@ -93,14 +93,14 @@ pub(crate) async fn job_offer_attachment(
|
|||
config: web::Data<ServerConfig>,
|
||||
session: Session,
|
||||
offers: web::Data<JobOffers>,
|
||||
) -> Result<impl Responder, AttachmentError> {
|
||||
) -> Result<impl Responder, AttachmentResponseError> {
|
||||
let id = &path.id;
|
||||
let attachment_name = path.attachment.as_str();
|
||||
|
||||
let offer = offers
|
||||
.get_offer(id)
|
||||
.await
|
||||
.ok_or(AttachmentError::OfferNotFound)?;
|
||||
.ok_or(AttachmentResponseError::OfferNotFound)?;
|
||||
|
||||
if !offer.is_published()
|
||||
&& !query
|
||||
|
|
@ -174,7 +174,7 @@ pub(crate) async fn sync(
|
|||
session: Session,
|
||||
config: web::Data<ServerConfig>,
|
||||
offers: web::Data<JobOffers>,
|
||||
) -> Result<HttpResponse, SyncError> {
|
||||
) -> Result<HttpResponse, SyncResponseError> {
|
||||
// TODO return the user to a page where they are asked to confirm syncing
|
||||
// aka. the get variant of this route
|
||||
User::current(&session)?;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use serde_json::json;
|
|||
|
||||
use crate::auth::User;
|
||||
use crate::error::PresentationError;
|
||||
use crate::route::job_offer::error::{DeletionError, StateChangeError};
|
||||
use crate::route::job_offer::error::{DeletionResponseError, StateChangeResponseError};
|
||||
use crate::route::{HTML_CONTENT, JOBOFFER_OVERVIEW_ROUTE};
|
||||
use crate::{auth, template, JobOffers, ServerConfig};
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ pub(crate) async fn delete_joboffer(
|
|||
offers: web::Data<JobOffers>,
|
||||
config: web::Data<ServerConfig>,
|
||||
session: Session,
|
||||
) -> actix_web::Result<HttpResponse, DeletionError> {
|
||||
) -> actix_web::Result<HttpResponse, DeletionResponseError> {
|
||||
// TODO return the user to a page where they are asked to confirm deletion
|
||||
// aka. the get variant of this route
|
||||
let _user = auth::User::current(&session)?;
|
||||
|
|
@ -47,7 +47,7 @@ pub(crate) async fn delete_expired_joboffers(
|
|||
offers: web::Data<JobOffers>,
|
||||
config: web::Data<ServerConfig>,
|
||||
session: Session,
|
||||
) -> actix_web::Result<HttpResponse, PresentationError> {
|
||||
) -> actix_web::Result<HttpResponse, DeletionResponseError> {
|
||||
let user = User::current(&session)?;
|
||||
let offers_guard = offers.get_offers().await;
|
||||
|
||||
|
|
@ -57,14 +57,17 @@ pub(crate) async fn delete_expired_joboffers(
|
|||
Some(&user),
|
||||
);
|
||||
|
||||
let base = crate::route::base(&req, &config, "Delete Expired")?;
|
||||
let base =
|
||||
crate::route::base(&req, &config, "Delete Expired").map_err(PresentationError::Url)?;
|
||||
|
||||
let data = json! {{
|
||||
"base": base,
|
||||
"expired_job_offers": job_offers,
|
||||
}};
|
||||
|
||||
let rendered = hb.render(template::JOBOFFER_DELETE_EXPIRED, &data)?;
|
||||
let rendered = hb
|
||||
.render(template::JOBOFFER_DELETE_EXPIRED, &data)
|
||||
.map_err(PresentationError::Render)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.insert_header((http::header::CONTENT_TYPE, HTML_CONTENT.clone()))
|
||||
|
|
@ -127,7 +130,7 @@ pub(crate) async fn bulk_delete(
|
|||
config: web::Data<ServerConfig>,
|
||||
form: web::Form<BulkDeleteData>,
|
||||
session: Session,
|
||||
) -> actix_web::Result<HttpResponse, DeletionError> {
|
||||
) -> actix_web::Result<HttpResponse, DeletionResponseError> {
|
||||
debug!("Received bulk deletion request!");
|
||||
|
||||
let _user = User::current(&session)?;
|
||||
|
|
@ -154,7 +157,7 @@ pub(crate) async fn review_joboffer(
|
|||
session: Session,
|
||||
config: web::Data<ServerConfig>,
|
||||
offers: web::Data<JobOffers>,
|
||||
) -> actix_web::Result<HttpResponse, StateChangeError> {
|
||||
) -> actix_web::Result<HttpResponse, StateChangeResponseError> {
|
||||
// TODO return the user to a page where they are asked to confirm publishing
|
||||
// aka. the get variant of this route
|
||||
let _user = auth::User::current(&session)?;
|
||||
|
|
@ -182,7 +185,7 @@ pub(crate) async fn unpublish_joboffer(
|
|||
session: Session,
|
||||
config: web::Data<ServerConfig>,
|
||||
offers: web::Data<JobOffers>,
|
||||
) -> actix_web::Result<HttpResponse, StateChangeError> {
|
||||
) -> actix_web::Result<HttpResponse, StateChangeResponseError> {
|
||||
// TODO return the user to a page where they are asked to confirm un-publishing
|
||||
// aka. the get variant of this route
|
||||
let _user = auth::User::current(&session)?;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use serde_json::json;
|
|||
|
||||
use crate::auth::User;
|
||||
use crate::job_offers::JobOfferData;
|
||||
use crate::route::job_offer::error::ConfirmationError;
|
||||
use crate::route::job_offer::error::ConfirmationError::SuccessRenderError;
|
||||
use crate::route::job_offer::error::ConfirmationResponseError;
|
||||
use crate::route::job_offer::error::ConfirmationResponseError::SuccessRenderError;
|
||||
use crate::route::HTML_CONTENT;
|
||||
use crate::{get, template, JobOffers, ServerConfig};
|
||||
|
||||
|
|
@ -35,13 +35,13 @@ pub(crate) async fn confirm_joboffer_get(
|
|||
config: web::Data<ServerConfig>,
|
||||
offers: web::Data<JobOffers>,
|
||||
path: web::Path<(String, String)>,
|
||||
) -> actix_web::Result<HttpResponse, ConfirmationError> {
|
||||
) -> actix_web::Result<HttpResponse, ConfirmationResponseError> {
|
||||
let id: &String = &path.0;
|
||||
let req_token = &path.1;
|
||||
|
||||
if let Some(job_offer) = offers.get_offer(id).await {
|
||||
if !job_offer.check_confirmation_token(req_token) {
|
||||
Err(ConfirmationError::InvalidRequest)
|
||||
Err(ConfirmationResponseError::InvalidRequest)
|
||||
} else {
|
||||
let user = User::current(&session).ok();
|
||||
|
||||
|
|
@ -66,14 +66,14 @@ pub(crate) async fn confirm_joboffer_get(
|
|||
|
||||
let body = hb
|
||||
.render(template::JOBOFFER_CONFIRM_SUBMISSION, &data)
|
||||
.map_err(ConfirmationError::RenderError)?;
|
||||
.map_err(ConfirmationResponseError::RenderError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.insert_header((http::header::CONTENT_TYPE, HTML_CONTENT.clone()))
|
||||
.body(body))
|
||||
}
|
||||
} else {
|
||||
Err(ConfirmationError::InvalidRequest)
|
||||
Err(ConfirmationResponseError::InvalidRequest)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ pub(crate) async fn confirm_joboffer_post(
|
|||
path: web::Path<(String, String)>,
|
||||
offers: web::Data<JobOffers>,
|
||||
config: web::Data<ServerConfig>,
|
||||
) -> actix_web::Result<HttpResponse, ConfirmationError> {
|
||||
) -> actix_web::Result<HttpResponse, ConfirmationResponseError> {
|
||||
let id = &path.0;
|
||||
let req_token = &path.1;
|
||||
|
||||
|
|
@ -113,10 +113,10 @@ pub(crate) async fn confirm_joboffer_post(
|
|||
.insert_header((http::header::CONTENT_TYPE, HTML_CONTENT.clone()))
|
||||
.body(body))
|
||||
}
|
||||
Err(()) => Err(ConfirmationError::InvalidRequest),
|
||||
Err(()) => Err(ConfirmationResponseError::InvalidRequest),
|
||||
}
|
||||
} else {
|
||||
Err(ConfirmationError::InvalidRequest)
|
||||
Err(ConfirmationResponseError::InvalidRequest)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ pub(crate) async fn reject_joboffer_post(
|
|||
hb: web::Data<Handlebars<'_>>,
|
||||
offers: web::Data<JobOffers>,
|
||||
config: web::Data<ServerConfig>,
|
||||
) -> actix_web::Result<HttpResponse, ConfirmationError> {
|
||||
) -> actix_web::Result<HttpResponse, ConfirmationResponseError> {
|
||||
let id = &path.0;
|
||||
let req_token = &path.1;
|
||||
|
||||
|
|
@ -154,9 +154,9 @@ pub(crate) async fn reject_joboffer_post(
|
|||
.insert_header((http::header::CONTENT_TYPE, HTML_CONTENT.clone()))
|
||||
.body(body))
|
||||
} else {
|
||||
Err(ConfirmationError::InvalidRequest)
|
||||
Err(ConfirmationResponseError::InvalidRequest)
|
||||
}
|
||||
} else {
|
||||
Err(ConfirmationError::InvalidRequest)
|
||||
Err(ConfirmationResponseError::InvalidRequest)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,14 +17,14 @@ use url::Url;
|
|||
|
||||
use crate::auth::User;
|
||||
use crate::error::{LoginRequired, MultipartFieldError, PresentationError};
|
||||
use crate::job_offers::error::{EmailError, SaveError};
|
||||
use crate::job_offers::error::{EmailError, SaveResponseError};
|
||||
use crate::job_offers::{
|
||||
Attachment, ConfirmationStatus, JobOffer, JobOfferStatus, JobOffers, Link, MutBorrowedJobOffer,
|
||||
ReviewStatus,
|
||||
};
|
||||
use crate::route::job_offer::confirmation::JOBOFFER_CONFIRM_ROUTE;
|
||||
use crate::route::job_offer::create::multipart_form::{multi_field, multi_file, once_field};
|
||||
use crate::route::job_offer::error::SubmissionError;
|
||||
use crate::route::job_offer::error::SubmissionResponseError;
|
||||
use crate::route::HTML_CONTENT;
|
||||
use crate::server_config::{EmailConfig, ServerConfig};
|
||||
use crate::{template, SubmissionLimiter};
|
||||
|
|
@ -62,7 +62,7 @@ pub(crate) async fn create_joboffer_post(
|
|||
limiter: web::Data<SubmissionLimiter>,
|
||||
hb: web::Data<Handlebars<'_>>,
|
||||
multipart: Multipart,
|
||||
) -> Result<HttpResponse, SubmissionError> {
|
||||
) -> Result<HttpResponse, SubmissionResponseError> {
|
||||
let user = User::current(&session).ok();
|
||||
|
||||
debug!("getting lease for new submission");
|
||||
|
|
@ -86,7 +86,7 @@ pub(crate) async fn create_joboffer_post(
|
|||
if submission_lease.is_none() && user.is_none() {
|
||||
debug!("failed to get a lease too many requests");
|
||||
// the user is not authenticated and has reached the quota for un-authenticated users
|
||||
return Err(SubmissionError::TooManyRequests);
|
||||
return Err(SubmissionResponseError::TooManyRequests);
|
||||
}
|
||||
|
||||
debug!("got lease, starting to process submission");
|
||||
|
|
@ -112,7 +112,7 @@ pub(crate) async fn create_joboffer_post(
|
|||
// submission failed end the lease immediately
|
||||
lease.end().await
|
||||
}
|
||||
return Err(SubmissionError::MissingLinkOrAttachment);
|
||||
return Err(SubmissionResponseError::MissingLinkOrAttachment);
|
||||
}
|
||||
|
||||
debug!("validation successful, saving submitted job offer");
|
||||
|
|
@ -179,7 +179,7 @@ pub(crate) async fn create_job_offer<'data, 'config>(
|
|||
offers: &'data JobOffers,
|
||||
config: &'config ServerConfig,
|
||||
user: Option<&User>,
|
||||
) -> Result<MutBorrowedJobOffer<'data, 'static, 'config>, SaveError> {
|
||||
) -> Result<MutBorrowedJobOffer<'data, 'static, 'config>, SaveResponseError> {
|
||||
let now_date = crate::util::now();
|
||||
|
||||
let token: String =
|
||||
|
|
@ -193,7 +193,7 @@ pub(crate) async fn create_job_offer<'data, 'config>(
|
|||
{
|
||||
// a reviewer-only option is set, but user is not logged-in as a reviewer
|
||||
// maybe a session just expired or some one is messing with the form
|
||||
return Err(SaveError::LoginRequired(LoginRequired::new()));
|
||||
return Err(SaveResponseError::Login(LoginRequired::new()));
|
||||
}
|
||||
|
||||
let submission_datetime = user
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ use log::warn;
|
|||
use thiserror::Error;
|
||||
|
||||
use crate::error::{default_error_response, LoginRequired, MultipartFieldError, PresentationError};
|
||||
use crate::job_offers::error::{DeleteError, SaveError};
|
||||
use crate::job_offers::error::{DeleteError, SaveError, SaveResponseError};
|
||||
use crate::job_offers::JobofferLoadError;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum ConfirmationError {
|
||||
pub(crate) enum ConfirmationResponseError {
|
||||
/// The referenced job offer does not exists,
|
||||
/// or does not await confirmation,
|
||||
/// or the token was invalid
|
||||
|
|
@ -33,33 +33,37 @@ pub(crate) enum ConfirmationError {
|
|||
Presentation(#[from] PresentationError),
|
||||
}
|
||||
|
||||
impl ResponseError for ConfirmationError {
|
||||
impl ResponseError for ConfirmationResponseError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
ConfirmationError::RenderError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ConfirmationError::SuccessRenderError(_) => StatusCode::CREATED,
|
||||
ConfirmationError::InvalidRequest => StatusCode::BAD_REQUEST,
|
||||
ConfirmationError::Save(inner) => inner.status_code(),
|
||||
ConfirmationError::Delete(inner) => inner.status_code(),
|
||||
ConfirmationError::Url(inner) => inner.status_code(),
|
||||
ConfirmationError::Presentation(inner) => inner.status_code(),
|
||||
ConfirmationResponseError::RenderError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ConfirmationResponseError::SuccessRenderError(_) => StatusCode::CREATED,
|
||||
ConfirmationResponseError::InvalidRequest => StatusCode::BAD_REQUEST,
|
||||
ConfirmationResponseError::Save(inner) => inner.as_status_code(),
|
||||
ConfirmationResponseError::Delete(DeleteError::IO(_)) => {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
ConfirmationResponseError::Url(inner) => inner.status_code(),
|
||||
ConfirmationResponseError::Presentation(inner) => inner.status_code(),
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
let status_code = self.status_code();
|
||||
match self {
|
||||
ConfirmationError::SuccessRenderError(inner) => {
|
||||
ConfirmationResponseError::SuccessRenderError(inner) => {
|
||||
warn!("Failed to render successful submission response {}", inner);
|
||||
HttpResponse::build(status_code).body("The submission was successful, but an error occurred while generating this response.")
|
||||
}
|
||||
ConfirmationError::InvalidRequest => {
|
||||
ConfirmationResponseError::InvalidRequest => {
|
||||
HttpResponse::build(status_code).body("Invalid Request")
|
||||
} // TODO more detail
|
||||
ConfirmationError::Save(inner) => inner.error_response(),
|
||||
ConfirmationError::Delete(inner) => inner.error_response(),
|
||||
ConfirmationError::Url(inner) => inner.error_response(),
|
||||
error @ (ConfirmationError::RenderError(_) | ConfirmationError::Presentation(_)) => {
|
||||
ConfirmationResponseError::Save(_) | ConfirmationResponseError::Delete(_) => {
|
||||
default_error_response(self, status_code)
|
||||
}
|
||||
ConfirmationResponseError::Url(inner) => inner.error_response(),
|
||||
error @ (ConfirmationResponseError::RenderError(_)
|
||||
| ConfirmationResponseError::Presentation(_)) => {
|
||||
default_error_response(error, status_code)
|
||||
}
|
||||
}
|
||||
|
|
@ -67,30 +71,30 @@ impl ResponseError for ConfirmationError {
|
|||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum DeletionError {
|
||||
pub(crate) enum DeletionResponseError {
|
||||
#[error("Could not delete Job Offer: {0}")]
|
||||
Delete(#[from] DeleteError),
|
||||
#[error("Login required to perform job Offer deletion: {0}")]
|
||||
Login(#[from] LoginRequired),
|
||||
#[error("{0}")]
|
||||
Presentation(#[from] PresentationError),
|
||||
}
|
||||
|
||||
impl ResponseError for DeletionError {
|
||||
impl ResponseError for DeletionResponseError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
DeletionError::Delete(inner) => inner.status_code(),
|
||||
DeletionError::Login(inner) => inner.status_code(),
|
||||
DeletionResponseError::Delete(DeleteError::IO(_))
|
||||
| DeletionResponseError::Presentation(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
DeletionResponseError::Login(_) => StatusCode::UNAUTHORIZED,
|
||||
}
|
||||
}
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
match self {
|
||||
DeletionError::Delete(inner) => inner.error_response(),
|
||||
DeletionError::Login(inner) => inner.error_response(),
|
||||
}
|
||||
default_error_response(self, self.status_code())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum StateChangeError {
|
||||
pub(crate) enum StateChangeResponseError {
|
||||
#[error("Could not save changes to Job Offer: {0}")]
|
||||
Save(#[from] SaveError),
|
||||
#[error("Login required to perform job Offer deletion: {0}")]
|
||||
|
|
@ -99,104 +103,120 @@ pub(crate) enum StateChangeError {
|
|||
Presentation(#[from] PresentationError),
|
||||
}
|
||||
|
||||
impl From<RenderError> for StateChangeError {
|
||||
impl From<RenderError> for StateChangeResponseError {
|
||||
fn from(render: RenderError) -> Self {
|
||||
Self::Presentation(PresentationError::Render(render))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UrlGenerationError> for StateChangeError {
|
||||
impl From<UrlGenerationError> for StateChangeResponseError {
|
||||
fn from(url_gen: UrlGenerationError) -> Self {
|
||||
Self::Presentation(PresentationError::Url(url_gen))
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseError for StateChangeError {
|
||||
impl ResponseError for StateChangeResponseError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
StateChangeError::Save(inner) => inner.status_code(),
|
||||
StateChangeError::Login(inner) => inner.status_code(),
|
||||
StateChangeError::Presentation(inner) => inner.status_code(),
|
||||
StateChangeResponseError::Save(inner) => inner.as_status_code(),
|
||||
StateChangeResponseError::Login(_inner) => StatusCode::UNAUTHORIZED,
|
||||
StateChangeResponseError::Presentation(inner) => inner.status_code(),
|
||||
}
|
||||
}
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
match self {
|
||||
StateChangeError::Save(inner) => inner.error_response(),
|
||||
StateChangeError::Login(inner) => inner.error_response(),
|
||||
StateChangeError::Presentation(inner) => inner.error_response(),
|
||||
StateChangeResponseError::Login(_) | StateChangeResponseError::Save(_) => {
|
||||
default_error_response(self, self.status_code())
|
||||
}
|
||||
StateChangeResponseError::Presentation(inner) => inner.error_response(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum SubmissionError {
|
||||
pub(crate) enum SubmissionResponseError {
|
||||
#[error("At least one link or attachment is required!")]
|
||||
MissingLinkOrAttachment,
|
||||
#[error("An error occurred while processing the form submission: {0}")]
|
||||
Form(#[from] MultipartFieldError),
|
||||
#[error("Failed to save the submission: {0}")]
|
||||
Save(#[from] SaveError),
|
||||
Save(#[from] SaveResponseError),
|
||||
#[error("{0}")]
|
||||
Render(#[from] PresentationError),
|
||||
#[error("Too many requests!")]
|
||||
TooManyRequests,
|
||||
}
|
||||
|
||||
impl From<UrlGenerationError> for SubmissionError {
|
||||
impl From<UrlGenerationError> for SubmissionResponseError {
|
||||
fn from(url: UrlGenerationError) -> Self {
|
||||
Self::Render(PresentationError::Url(url))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RenderError> for SubmissionError {
|
||||
impl From<RenderError> for SubmissionResponseError {
|
||||
fn from(render: RenderError) -> Self {
|
||||
Self::Render(PresentationError::Render(render))
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseError for SubmissionError {
|
||||
impl ResponseError for SubmissionResponseError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
SubmissionError::MissingLinkOrAttachment => StatusCode::BAD_REQUEST,
|
||||
SubmissionError::Form(inner) => inner.status_code(),
|
||||
SubmissionError::Save(inner) => inner.status_code(),
|
||||
SubmissionError::Render(inner) => inner.status_code(),
|
||||
SubmissionError::TooManyRequests => StatusCode::TOO_MANY_REQUESTS,
|
||||
SubmissionResponseError::MissingLinkOrAttachment => StatusCode::BAD_REQUEST,
|
||||
SubmissionResponseError::Form(MultipartFieldError::Date { .. })
|
||||
| SubmissionResponseError::Form(MultipartFieldError::ContentTooLarge { .. })
|
||||
| SubmissionResponseError::Form(MultipartFieldError::MultipartError(_))
|
||||
| SubmissionResponseError::Form(MultipartFieldError::NotAFile { .. })
|
||||
| SubmissionResponseError::Form(MultipartFieldError::TooManyOccurrences { .. })
|
||||
| SubmissionResponseError::Form(MultipartFieldError::MissingField { .. })
|
||||
| SubmissionResponseError::Form(MultipartFieldError::UTF8Error(_))
|
||||
| SubmissionResponseError::Form(MultipartFieldError::InvalidAddress(_)) => {
|
||||
StatusCode::BAD_REQUEST
|
||||
}
|
||||
SubmissionResponseError::Form(MultipartFieldError::IOError(_))
|
||||
| SubmissionResponseError::Form(MultipartFieldError::Runtime(_)) => {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
SubmissionResponseError::Save(inner) => inner.status_code(),
|
||||
SubmissionResponseError::Render(inner) => inner.status_code(),
|
||||
SubmissionResponseError::TooManyRequests => StatusCode::TOO_MANY_REQUESTS,
|
||||
}
|
||||
}
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
let status_code = self.status_code();
|
||||
match self {
|
||||
SubmissionError::MissingLinkOrAttachment => default_error_response(self, status_code),
|
||||
SubmissionError::Form(inner) => inner.error_response(),
|
||||
SubmissionError::Save(inner) => inner.error_response(),
|
||||
SubmissionError::Render(inner) => inner.error_response(),
|
||||
SubmissionError::TooManyRequests => default_error_response(self, status_code),
|
||||
SubmissionResponseError::Save(inner) => inner.error_response(),
|
||||
SubmissionResponseError::Render(inner) => inner.error_response(),
|
||||
SubmissionResponseError::MissingLinkOrAttachment
|
||||
| SubmissionResponseError::Form(_)
|
||||
| SubmissionResponseError::TooManyRequests => default_error_response(self, status_code),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum SyncError {
|
||||
pub(crate) enum SyncResponseError {
|
||||
#[error("{0}")]
|
||||
LoginRequired(#[from] LoginRequired),
|
||||
Login(#[from] LoginRequired),
|
||||
#[error("{0}")]
|
||||
Load(#[from] JobofferLoadError),
|
||||
#[error("{0}")]
|
||||
Presentation(#[from] PresentationError),
|
||||
}
|
||||
|
||||
impl ResponseError for SyncError {
|
||||
impl ResponseError for SyncResponseError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
SyncError::LoginRequired(_) => StatusCode::FORBIDDEN,
|
||||
SyncError::Load(_) | SyncError::Presentation(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
SyncResponseError::Login(_) => StatusCode::UNAUTHORIZED,
|
||||
SyncResponseError::Load(_) | SyncResponseError::Presentation(_) => {
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub(crate) enum AttachmentError {
|
||||
pub(crate) enum AttachmentResponseError {
|
||||
#[error("Job Offer not found!")]
|
||||
OfferNotFound,
|
||||
#[error("Viewing this Job Offers Attachments requires Authentication, as the offer is not yet published: {0}")]
|
||||
|
|
@ -205,24 +225,26 @@ pub(crate) enum AttachmentError {
|
|||
IO(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
impl ResponseError for AttachmentError {
|
||||
impl ResponseError for AttachmentResponseError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match self {
|
||||
AttachmentError::OfferNotFound => StatusCode::NOT_FOUND,
|
||||
AttachmentError::IO(error) if error.kind() == ErrorKind::NotFound => {
|
||||
AttachmentResponseError::OfferNotFound => StatusCode::NOT_FOUND,
|
||||
AttachmentResponseError::IO(error) if error.kind() == ErrorKind::NotFound => {
|
||||
StatusCode::NOT_FOUND
|
||||
}
|
||||
AttachmentError::LoginRequired(inner) => inner.status_code(),
|
||||
AttachmentError::IO(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
AttachmentResponseError::LoginRequired(_) => StatusCode::UNAUTHORIZED,
|
||||
AttachmentResponseError::IO(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
let status_code = self.status_code();
|
||||
match self {
|
||||
AttachmentError::OfferNotFound => default_error_response(self, status_code),
|
||||
AttachmentError::LoginRequired(inner) => inner.error_response(),
|
||||
AttachmentError::IO(inner) => default_error_response(inner, status_code),
|
||||
AttachmentResponseError::OfferNotFound => default_error_response(self, status_code),
|
||||
AttachmentResponseError::LoginRequired(_inner) => {
|
||||
default_error_response(self, status_code)
|
||||
}
|
||||
AttachmentResponseError::IO(inner) => default_error_response(inner, status_code),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue