nure_tools/
schedule.rs

1use crate::{
2    errors::RequestError,
3    groups::{parse_group_json, Group},
4    lecture_rooms::LectureRoom,
5    teachers::{parse_teacher_json, Teacher},
6    utils::{get_wrapper, Period},
7};
8use anyhow::{anyhow, Result};
9use reqwest::blocking::get;
10use serde_json::{self, Map, Value};
11
12/** Get schedule function.
13
14Returns shedule for the given request in `Vec<Lecture>` format.
15
16# Arguments
17 * request - accepts a [`Request`] enum with a [`Group`]/[`Teacher`]/[`LectureRoom`] object inside.
18 * period - accepts a [`Period`] struct.
19
20# Examples
21```
22# use anyhow::Error;
23# use nure_tools::{
24#     groups::{find_group, Group},
25#     schedule::{get_schedule, Lecture, Request},
26#     utils::Period,
27# };
28let groups_response: Vec<Group> = find_group("пзпі-23-2")?;
29
30for group in groups_response {
31    let schedule_request_bygroup: Request = Request::Group(group);
32    let schedule_response: Vec<Lecture> = get_schedule(
33        schedule_request_bygroup,
34        Period::from_string("2024-01-02", "2024-01-03")?,
35    )?;
36    println!("{:#?}", schedule_response);
37}
38# Ok::<(), Error>(())
39```
40
41# Errors
42This function fails if:
43 * `RequestError::GetFailed` - Get request fails.
44 * `RequestError::NotJson` - Server returns value not in json format.
45 * `RequestError::BadResponse` - Server returns any response except 200.
46 * `RequestError::InvalidReturn` - Server returns value in unexpected format.
47
48**/
49pub fn get_schedule(request: Request, period: Period) -> Result<Vec<Lecture>> {
50    let start_time = period.start_time.timestamp().to_string();
51    let end_time = period.end_time.timestamp().to_string();
52
53    let (request_type, request_id) = match request {
54        Request::Group(group) => ("groups", group.id),
55        Request::Teacher(teacher) => ("teachers", teacher.id),
56        Request::LectureRoom(lecture_room) => ("auditories", lecture_room.id),
57    };
58
59    let response = get_wrapper(get(format!(
60        "https://api.mindenit.org/schedule/{}/{}?start={}&end={}",
61        request_type, request_id, start_time, end_time,
62    )))?;
63
64    let mut result: Vec<Lecture> = Vec::new();
65
66    if let Value::Array(vector) = response {
67        let mut lecture_room: String = String::new();
68        let mut start_time: i64 = 0;
69        let mut end_time: i64 = 0;
70        let mut number_pair: u8 = 0;
71        let mut lecture_type: String = String::new();
72        let mut teachers: Vec<Teacher> = vec![];
73        let mut groups: Vec<Group> = vec![];
74        let mut subject: Subject = Subject::default();
75
76        for element in vector {
77            if let Value::Object(mut obj) = element {
78                if let Value::String(st) = obj.get("auditory").unwrap() {
79                    lecture_room = st.clone();
80                }
81                if let Value::Number(n) = obj.get("startTime").unwrap() {
82                    start_time = n.as_i64().unwrap();
83                }
84                if let Value::Number(n) = obj.get("endTime").unwrap() {
85                    end_time = n.as_i64().unwrap();
86                }
87                if let Value::Number(n) = obj.get("numberPair").unwrap() {
88                    number_pair = n.as_i64().unwrap() as u8;
89                }
90                if let Value::String(st) = obj.get("type").unwrap() {
91                    lecture_type = st.clone();
92                }
93                if let Value::Array(vector) = obj.remove("teachers").unwrap() {
94                    teachers = parse_teacher_json(vector);
95                }
96                if let Value::Array(vector) = obj.remove("groups").unwrap() {
97                    groups = parse_group_json(vector);
98                }
99                if let Value::Object(obj) = obj.remove("subject").unwrap() {
100                    subject = parse_subject_json(obj);
101                }
102
103                result.push(Lecture::new(
104                    lecture_room.clone(),
105                    Period::from_timestamp(start_time, end_time)?,
106                    number_pair,
107                    lecture_type.clone(),
108                    teachers.clone(),
109                    groups.clone(),
110                    subject.clone(),
111                ));
112            };
113        }
114
115        Ok(result)
116    } else {
117        Err(anyhow!(RequestError::InvalidReturn))
118    }
119}
120
121/** Helper function to parse subject json returned by API into [`Subject`] struct.
122
123You probably will never use it, but you can if you want, see example in [`get_schedule`] function source
124**/
125pub fn parse_subject_json(obj: Map<String, Value>) -> Subject {
126    let mut brief: String = String::new();
127    let mut id: i32 = 0;
128    let mut title: String = String::new();
129
130    if let Value::String(st) = obj.get("brief").unwrap() {
131        brief = st.clone();
132    }
133    if let Value::Number(n) = obj.get("id").unwrap() {
134        id = n.as_i64().unwrap_or(0) as i32;
135    }
136    if let Value::String(st) = obj.get("title").unwrap() {
137        title = st.clone();
138    }
139
140    Subject::new(brief, id, title)
141}
142
143/** Request enum to simplify the [`get_schedule`] function.
144# Variants
145 * `Group` - require a [`Group`] to parse id from it.
146 * `Teacher` - require a [`Teacher`] to parse id from it.
147 * `LectureRoom` - require a [`LectureRoom`] to parse id from it.
148**/
149pub enum Request {
150    Group(Group),
151    Teacher(Teacher),
152    LectureRoom(LectureRoom),
153}
154
155/** Massive Lacture struct.
156**/
157#[derive(Debug, Clone)]
158pub struct Lecture {
159    pub lecture_room: String,
160    pub period: Period,
161    pub number_pair: u8,
162    pub lecture_type: String,
163    pub teachers: Vec<Teacher>,
164    pub groups: Vec<Group>,
165    pub subject: Subject,
166}
167/** Subject struct.
168**/
169#[derive(Default, Debug, Clone)]
170pub struct Subject {
171    pub brief: String,
172    pub id: i32,
173    pub title: String,
174}
175
176impl Lecture {
177    fn new(
178        lecture_room: String,
179        period: Period,
180        number_pair: u8,
181        lecture_type: String,
182        teachers: Vec<Teacher>,
183        groups: Vec<Group>,
184        subject: Subject,
185    ) -> Self {
186        Self {
187            lecture_room,
188            period,
189            number_pair,
190            lecture_type,
191            teachers,
192            groups,
193            subject,
194        }
195    }
196}
197
198impl Subject {
199    fn new(brief: String, id: i32, title: String) -> Self {
200        Self { brief, id, title }
201    }
202}