use chrono::{DateTime, Utc}; use derive_more::{Display, Error}; use serde::{Deserialize, Serialize, Serializer}; use serde_repr::{Deserialize_repr, Serialize_repr}; use std::collections::HashMap; use std::sync::Arc; use utoipa::ToSchema; /// The beginning and end of the lesson. #[derive(Clone, Hash, Debug, Serialize, Deserialize, ToSchema)] pub struct LessonBoundaries { /// The beginning of a lesson. pub start: DateTime, /// The end of the lesson. pub end: DateTime, } /// Type of lesson. #[derive(Clone, Hash, PartialEq, Debug, Serialize_repr, Deserialize_repr, ToSchema)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[repr(u8)] pub enum LessonType { /// Обычная. Default = 0, /// Допы. Additional, /// Перемена. Break, /// Консультация. Consultation, /// Самостоятельная работа. IndependentWork, /// Зачёт. Exam, /// Зачёт с оценкой. ExamWithGrade, /// Экзамен. ExamDefault, } #[derive(Clone, Hash, Debug, Serialize, Deserialize, ToSchema)] pub struct LessonSubGroup { /// Index of subgroup. pub number: u8, /// Cabinet, if present. pub cabinet: Option, /// Full name of the teacher. pub teacher: String, } #[derive(Clone, Hash, Debug, Serialize, Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] pub struct Lesson { /// Type. #[serde(rename = "type")] pub lesson_type: LessonType, /// Lesson indexes, if present. pub default_range: Option<[u8; 2]>, /// Name. pub name: Option, /// The beginning and end. pub time: LessonBoundaries, /// List of subgroups. #[serde(rename = "subGroups")] pub subgroups: Option>, /// Group name, if this is a schedule for teachers. pub group: Option, } #[derive(Clone, Hash, Debug, Serialize, Deserialize, ToSchema)] pub struct Day { /// Day of the week. pub name: String, /// Address of another corps. pub street: Option, /// Date. pub date: DateTime, /// List of lessons on this day. pub lessons: Vec, } #[derive(Clone, Hash, Debug, Serialize, Deserialize, ToSchema)] pub struct ScheduleEntry { /// The name of the group or name of the teacher. pub name: String, /// List of six days. pub days: Vec, } #[derive(Clone)] pub struct ParseResult { /// List of groups. pub groups: HashMap, /// List of teachers. pub teachers: HashMap, } #[derive(Clone, Debug, Display, Error, ToSchema)] #[display("row {row}, column {column}")] pub struct ErrorCellPos { pub row: u32, pub column: u32, } #[derive(Clone, Debug, Display, Error, ToSchema)] #[display("'{data}' at {pos}")] pub struct ErrorCell { pub pos: ErrorCellPos, pub data: String, } impl ErrorCell { pub fn new(row: u32, column: u32, data: String) -> Self { Self { pos: ErrorCellPos { row, column }, data, } } } #[derive(Clone, Debug, Display, Error, ToSchema)] pub enum ParseError { /// Errors related to reading XLS file. #[display("{_0:?}: Failed to read XLS file.")] #[schema(value_type = String)] BadXLS(Arc), /// Not a single sheet was found. #[display("No work sheets found.")] NoWorkSheets, /// There are no data on the boundaries of the sheet. #[display("There is no data on work sheet boundaries.")] UnknownWorkSheetRange, /// Failed to read the beginning and end of the lesson from the cell #[display("Failed to read lesson start and end from {_0}.")] LessonBoundaries(ErrorCell), /// Not found the beginning and the end corresponding to the lesson. #[display("No start and end times matching the lesson (at {_0}) was found.")] LessonTimeNotFound(ErrorCellPos), } impl Serialize for ParseError { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match self { ParseError::BadXLS(_) => serializer.serialize_str("BAD_XLS"), ParseError::NoWorkSheets => serializer.serialize_str("NO_WORK_SHEETS"), ParseError::UnknownWorkSheetRange => { serializer.serialize_str("UNKNOWN_WORK_SHEET_RANGE") } ParseError::LessonBoundaries(_) => serializer.serialize_str("GLOBAL_TIME"), ParseError::LessonTimeNotFound(_) => serializer.serialize_str("LESSON_TIME_NOT_FOUND"), } } }