Skip to main content

foxtive_ntex_multipart/
result.rs

1use crate::file_validator::InputError;
2use foxtive::StatusCode;
3use foxtive::helpers::time::current_timestamp;
4use ntex::web::{HttpRequest, HttpResponse, WebResponseError};
5use serde_json::json;
6use std::fmt::{Display, Formatter};
7use std::io::Error;
8use thiserror::Error;
9
10pub type MultipartResult<T> = Result<T, MultipartError>;
11
12#[derive(Debug, Error)]
13pub enum MultipartError {
14    NoFile,
15    IoError(Error),
16    NoContentType(String),
17    ParseError(String),
18    MissingDataField(String),
19    InvalidContentDisposition(String),
20    NtexError(ntex_multipart::MultipartError),
21    ValidationError(InputError),
22}
23
24impl From<Error> for MultipartError {
25    fn from(value: Error) -> Self {
26        MultipartError::IoError(value)
27    }
28}
29
30impl WebResponseError for MultipartError {
31    fn status_code(&self) -> StatusCode {
32        match self {
33            MultipartError::IoError(_) => StatusCode::INTERNAL_SERVER_ERROR,
34            MultipartError::NoFile
35            | MultipartError::NoContentType(_)
36            | MultipartError::ParseError(_)
37            | MultipartError::MissingDataField(_)
38            | MultipartError::InvalidContentDisposition(_)
39            | MultipartError::NtexError(_)
40            | MultipartError::ValidationError(_) => StatusCode::BAD_REQUEST,
41        }
42    }
43
44    fn error_response(&self, _: &HttpRequest) -> HttpResponse {
45        match self {
46            MultipartError::NoFile => send_response(self.status_code(), "No file(s) were uploaded"),
47            MultipartError::IoError(_) => {
48                send_response(self.status_code(), "Internal Server Error")
49            }
50            MultipartError::NoContentType(err) => send_response(self.status_code(), err),
51            MultipartError::ParseError(err) => send_response(self.status_code(), err),
52            MultipartError::MissingDataField(err) => send_response(self.status_code(), err),
53            MultipartError::InvalidContentDisposition(err) => {
54                send_response(self.status_code(), err)
55            }
56            MultipartError::NtexError(err) => send_response(self.status_code(), &err.to_string()),
57            MultipartError::ValidationError(err) => {
58                send_response(self.status_code(), &err.error.to_string())
59            }
60        }
61    }
62}
63
64fn send_response(status_code: StatusCode, message: &str) -> HttpResponse {
65    let data: Option<String> = None;
66    let code = match status_code {
67        StatusCode::BAD_REQUEST => "004",
68        _ => "010",
69    };
70
71    HttpResponse::build(status_code).json(&json!({
72        "success": false,
73        "message": message,
74        "code": code,
75        "timestamp": current_timestamp(),
76        "data": data
77    }))
78}
79impl Display for MultipartError {
80    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
81        match self {
82            MultipartError::IoError(err) => {
83                write!(f, "{err}")
84            }
85            MultipartError::NoFile => {
86                write!(f, "No file was uploaded")
87            }
88            MultipartError::MissingDataField(ct) => {
89                write!(f, "Data field '{ct}' is required")
90            }
91            MultipartError::NoContentType(ct) => {
92                write!(f, "Invalid content type: {ct}")
93            }
94            MultipartError::ParseError(pe) => {
95                write!(f, "Failed to parse post data: {pe}")
96            }
97            MultipartError::InvalidContentDisposition(err) => {
98                write!(f, "Invalid content disposition: {err}")
99            }
100            MultipartError::NtexError(err) => {
101                write!(f, "{err}")
102            }
103            MultipartError::ValidationError(err) => write!(f, "{}", err.error),
104        }
105    }
106}