• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

doitsu2014 / my-cms / 14187034714

01 Apr 2025 04:12AM UTC coverage: 59.597% (+20.5%) from 39.058%
14187034714

push

github

web-flow
Feature/support multi language (#19)

* Enhance entity structure: add category and post translations, update migration dependencies, and improve README guidelines

* Add support for category translations: update create and modify handlers, requests, and tests

add TODO

* Add category translations support: update create, modify, and read handlers, and adjust request structures

* Refactor category translation requests: remove slug field and update handlers to set category ID for translations

* Add support for post translations: update create and modify requests, handlers, and models

* Update CI configuration and scripts for improved coverage reporting and toolchain management

* Update coverage configuration and scripts for improved reporting and toolchain management

* Update CI and coverage configurations for improved reporting and ignore patterns

* Update CI configuration and coverage scripts for improved reporting and cleanup

* Remove unused coverage step from CI configuration

* Update CI configuration to use fixed lcov report paths for coverage uploads

197 of 396 new or added lines in 19 files covered. (49.75%)

71 existing lines in 11 files now uncovered.

975 of 1636 relevant lines covered (59.6%)

26.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

32.56
/src/presentation_models/api_response.rs
1
use application_core::common::app_error::AppError;
2
use axum::{http::StatusCode, response::Response};
3
use hyper::header::CONTENT_TYPE;
4
use serde::Serialize;
5

6
pub trait AxumResponse {
7
    fn to_axum_response(self) -> Response<String>;
8
}
9

10
#[derive(Serialize)]
11
#[serde(rename_all = "camelCase")]
12
pub struct ApiResponseWith<TData>
13
where
14
    TData: Serialize,
15
{
16
    message: String,
17
    data: TData,
18
}
19

20
impl<TData> ApiResponseWith<TData>
21
where
22
    TData: Serialize,
23
{
UNCOV
24
    pub fn new(data: TData) -> Self {
×
UNCOV
25
        Self {
×
UNCOV
26
            message: "".to_string(),
×
UNCOV
27
            data,
×
UNCOV
28
        }
×
UNCOV
29
    }
×
30

UNCOV
31
    pub fn with_message(self, message: String) -> Self {
×
UNCOV
32
        Self { message, ..self }
×
UNCOV
33
    }
×
34
}
35

36
impl<TData> AxumResponse for ApiResponseWith<TData>
37
where
38
    TData: Serialize,
39
{
UNCOV
40
    fn to_axum_response(self) -> Response<String> {
×
UNCOV
41
        let json_body = serde_json::to_string(&self).unwrap();
×
UNCOV
42
        Response::builder()
×
UNCOV
43
            .status(StatusCode::OK)
×
UNCOV
44
            .header(CONTENT_TYPE, "application/json")
×
UNCOV
45
            .body(json_body)
×
UNCOV
46
            .unwrap()
×
UNCOV
47
    }
×
48
}
49

50
#[derive(Serialize)]
51
#[serde(rename_all = "camelCase")]
52
pub struct ApiResponseError {
53
    error_code: ErrorCode,
54
    errors: Vec<String>,
55
}
56

57
#[derive(Debug, Serialize, Clone, Copy, PartialEq)]
58
#[serde(rename_all = "camelCase")]
59
pub enum ErrorCode {
60
    #[serde(rename = "0")]
61
    UnknownError,
62
    #[serde(rename = "401")]
63
    UnAuthorized,
64
    #[serde(rename = "401")]
65
    ForBidden,
66
    #[serde(rename = "404")]
67
    NotFound,
68
    #[serde(rename = "10000")]
69
    ValidationError,
70
    #[serde(rename = "10001")]
71
    ConnectionError,
72
    #[serde(rename = "10002")]
73
    Logical,
74
    #[serde(rename = "99999")]
75
    ConcurrencyOptimistic,
76
}
77

78
impl AxumResponse for ApiResponseError {
79
    fn to_axum_response(self) -> Response<String> {
×
80
        let status_code = match self.error_code {
×
81
            ErrorCode::UnknownError => StatusCode::INTERNAL_SERVER_ERROR,
×
82
            ErrorCode::ConnectionError => StatusCode::INTERNAL_SERVER_ERROR,
×
83
            ErrorCode::UnAuthorized => StatusCode::UNAUTHORIZED,
×
84
            ErrorCode::ForBidden => StatusCode::FORBIDDEN,
×
85
            ErrorCode::NotFound => StatusCode::NOT_FOUND,
×
86
            ErrorCode::ValidationError => StatusCode::BAD_REQUEST,
×
87
            ErrorCode::Logical => StatusCode::BAD_REQUEST,
×
88
            ErrorCode::ConcurrencyOptimistic => StatusCode::BAD_REQUEST,
×
89
        };
90

91
        let json_body = serde_json::to_string(&self).unwrap();
×
92
        Response::builder()
×
93
            .status(status_code)
×
UNCOV
94
            .header(CONTENT_TYPE, "application/json")
×
UNCOV
95
            .body(json_body)
×
UNCOV
96
            .unwrap()
×
97
    }
×
98
}
99

100
impl ApiResponseError {
101
    pub fn with_error_code(self, error_code: ErrorCode) -> Self {
1✔
102
        Self {
1✔
103
            error_code,
1✔
104
            errors: self.errors,
1✔
105
        }
1✔
106
    }
1✔
107

108
    pub fn add_error(self, error: String) -> Self {
1✔
109
        let mut errors = self.errors;
1✔
110
        errors.push(error);
1✔
111
        Self {
1✔
112
            error_code: self.error_code,
1✔
113
            errors,
1✔
114
        }
1✔
115
    }
1✔
116

117
    pub fn new() -> Self {
1✔
118
        Self {
1✔
119
            error_code: ErrorCode::UnknownError,
1✔
120
            errors: vec![],
1✔
121
        }
1✔
122
    }
1✔
123
}
124

125
impl From<AppError> for ApiResponseError {
126
    fn from(app_error: AppError) -> Self {
×
127
        match app_error {
×
128
            AppError::Db(err) => Self::new()
×
129
                .with_error_code(ErrorCode::ConnectionError)
×
130
                .add_error(err.to_string()),
×
131
            AppError::DbTx(err) => Self::new()
×
132
                .with_error_code(ErrorCode::ConnectionError)
×
133
                .add_error(err.to_string()),
×
134
            AppError::S3Error(err) => Self::new()
×
135
                .with_error_code(ErrorCode::ConnectionError)
×
136
                .add_error(err.to_string()),
×
137
            AppError::Validation(field, message) => Self::new()
×
138
                .with_error_code(ErrorCode::ValidationError)
×
139
                .add_error(format!("{}: {}", field, message)),
×
140
            AppError::Logical(m) => Self::new().with_error_code(ErrorCode::Logical).add_error(m),
×
141
            AppError::ConcurrencyOptimistic(m) => Self::new()
×
142
                .with_error_code(ErrorCode::ConcurrencyOptimistic)
×
UNCOV
143
                .add_error(m),
×
144
            AppError::Unknown => Self::new().with_error_code(ErrorCode::UnknownError),
×
145
            AppError::NotFound => Self::new().with_error_code(ErrorCode::NotFound),
×
146
        }
147
    }
×
148
}
149

150
impl Default for ApiResponseError {
151
    fn default() -> Self {
×
152
        Self::new()
×
153
    }
×
154
}
155

156
#[cfg(test)]
157
mod tests {
158
    use crate::presentation_models::api_response::*;
159

160
    #[test]
161
    fn test_case_one() {
1✔
162
        let response_message = ApiResponseError::new()
1✔
163
            .with_error_code(ErrorCode::UnAuthorized)
1✔
164
            .add_error("User is unauthorized".to_string());
1✔
165

1✔
166
        assert_eq!(ErrorCode::UnAuthorized, response_message.error_code);
1✔
167
        assert_eq!(1, response_message.errors.len());
1✔
168
    }
1✔
169
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc