Добавлена возможность создания ResponseError с описанием ошибки.

Добавлен макрос для трансформации ErrorCode в Response, а также для имплементации треита PartialStatusCode.
This commit is contained in:
2025-03-28 15:42:45 +04:00
parent 70a7480ea3
commit 30c985a3d7
12 changed files with 296 additions and 122 deletions

View File

@@ -0,0 +1,38 @@
use self::schema::*;
use crate::app_state::AppState;
use crate::routes::schedule::schema::{Error, ScheduleView};
use crate::routes::schema::{IntoResponseAsError, ResponseError};
use actix_web::{get, web};
#[utoipa::path(responses(
(status = OK, body = ScheduleView),
(status = SERVICE_UNAVAILABLE, body = ResponseError<ErrorCode>)
))]
#[get("/")]
pub async fn get_schedule(app_state: web::Data<AppState>) -> Response {
match ScheduleView::try_from(app_state.get_ref()) {
Ok(res) => Ok(res).into(),
Err(e) => match e {
Error::NoSchedule => ErrorCode::NoSchedule.into_response(),
},
}
}
mod schema {
use crate::routes::schedule::schema::ScheduleView;
use actix_macros::{IntoResponseErrorNamed, StatusCode};
use derive_more::Display;
use serde::Serialize;
use utoipa::ToSchema;
pub type Response = crate::routes::schema::Response<ScheduleView, ErrorCode>;
#[derive(Clone, Serialize, ToSchema, StatusCode, Display, IntoResponseErrorNamed)]
#[status_code = "actix_web::http::StatusCode::SERVICE_UNAVAILABLE"]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[schema(as = ScheduleView::ErrorCode)]
pub enum ErrorCode {
#[display("Schedule not parsed yet")]
NoSchedule,
}
}

View File

@@ -0,0 +1,2 @@
pub mod get_schedule;
mod schema;

View File

@@ -0,0 +1,47 @@
use crate::app_state::AppState;
use crate::parser::schema::ScheduleEntry;
use chrono::{DateTime, Utc};
use serde::Serialize;
use std::collections::HashMap;
use utoipa::ToSchema;
#[derive(Serialize, ToSchema)]
pub struct ScheduleView {
etag: String,
replacer_id: Option<String>,
uploaded_at: DateTime<Utc>,
downloaded_at: DateTime<Utc>,
groups: HashMap<String, ScheduleEntry>,
teachers: HashMap<String, ScheduleEntry>,
updated_groups: Vec<Vec<i32>>,
updated_teachers: Vec<Vec<i32>>,
}
pub enum Error {
NoSchedule,
}
impl TryFrom<&AppState> for ScheduleView {
type Error = Error;
fn try_from(app_state: &AppState) -> Result<Self, Self::Error> {
let schedule_lock = app_state.schedule.lock().unwrap();
if let Some(schedule_ref) = schedule_lock.as_ref() {
let schedule = schedule_ref.clone();
Ok(Self {
etag: schedule.etag,
replacer_id: None,
uploaded_at: schedule.updated_at,
downloaded_at: schedule.parsed_at,
groups: schedule.data.groups,
teachers: schedule.data.teachers,
updated_groups: vec![],
updated_teachers: vec![],
})
} else {
Err(Error::NoSchedule)
}
}
}