diff --git a/Cargo.toml b/Cargo.toml index 2ca3934..79ce6c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ serde_json = "1.0" jsonwebtoken = "7.2" time = "0.2" keycloak = "14" +chrono = "0.4" [dependencies.serde_derive] diff --git a/src/indiware_connector.rs b/src/indiware_connector.rs index 892a99b..b7390e3 100644 --- a/src/indiware_connector.rs +++ b/src/indiware_connector.rs @@ -1,6 +1,7 @@ use crate::config; use crate::schema::timetable; use crate::DbConn; +use chrono::Local; use diesel::{Insertable, Queryable}; use quickxml_to_serde::{xml_string_to_json, Config}; use serde_derive::{Deserialize, Serialize}; @@ -21,10 +22,14 @@ pub struct TimetableData { pub courses: Vec, } -async fn get_timetable_xml() -> serde_json::value::Value { +async fn get_today_timetable_xml() -> serde_json::value::Value { let client = reqwest::Client::new(); let resp = client - .get(config::TIMETABLE_URL) + .get(format!( + "{}/PlanKl{}.xml", + config::TIMETABLE_URL, + Local::today().format("%Y%m%d") + )) .basic_auth(config::TIMETABLE_USER, config::TIMETABLE_PASSWORD) .send() .await @@ -35,6 +40,36 @@ async fn get_timetable_xml() -> serde_json::value::Value { xml_string_to_json(resp, &Config::new_with_defaults()).unwrap() } +async fn get_timetable_xml() -> serde_json::value::Value { + let client = reqwest::Client::new(); + let resp = client + .get(format!("{}/Klassen.xml", config::TIMETABLE_URL)) + .basic_auth(config::TIMETABLE_USER, config::TIMETABLE_PASSWORD) + .send() + .await + .unwrap() + .text() + .await + .unwrap(); + xml_string_to_json(resp, &Config::new_with_defaults()).unwrap() +} + +async fn get_today_timetable_xml_data() -> Vec { + let xml = get_today_timetable_xml().await; + let classes = xml + .as_object() + .unwrap() + .get("VpMobil") + .unwrap() + .get("Klassen") + .unwrap() + .get("Kl") + .unwrap() + .as_array() + .unwrap(); + classes.to_owned() +} + async fn get_timetable_xml_data() -> Vec { let xml = get_timetable_xml().await; let classes = xml @@ -51,6 +86,79 @@ async fn get_timetable_xml_data() -> Vec { classes.to_owned() } +pub async fn get_today_timetable(_conn: DbConn) -> Vec { + let xml = get_today_timetable_xml().await; + let classes = get_today_timetable_xml_data().await; + let mut timetable: Vec = Vec::new(); + for i in classes.iter() { + let mut courses: Vec = Vec::new(); + let nothing = json!([""]); + let std = i + .as_object() + .unwrap() + .get("Pl") + .unwrap() + .as_object() + .unwrap() + .get("Std") + .unwrap_or(¬hing); + let mut plan = vec![]; + if std.is_array() { + plan.extend(std.as_array().unwrap().iter().cloned()) + } else if std.is_object() { + plan.push(std.clone()) + } + for i in &plan { + if i.as_object() != None { + courses.push(i.to_owned()); + } else { + dbg!("Failed: {:?}", &i); + } + } + let response = TimetableData { + count: plan.len(), + courses, + }; + let timetable_element = Timetable { + date: String::from( + xml.as_object() + .unwrap() + .get("VpMobil") + .unwrap() + .get("Kopf") + .unwrap() + .get("DatumPlan") + .unwrap() + .as_str() + .unwrap(), + ), + updated: String::from( + xml.as_object() + .unwrap() + .get("VpMobil") + .unwrap() + .get("Kopf") + .unwrap() + .get("zeitstempel") + .unwrap() + .as_str() + .unwrap(), + ), + class: String::from( + i.as_object() + .unwrap() + .get("Kurz") + .unwrap() + .as_str() + .unwrap(), + ), + timetable_data: serde_json::from_str(&json!(response).to_string()).unwrap(), + }; + timetable.push(timetable_element) + } + timetable +} + pub async fn get_timetable(_conn: DbConn) -> Vec { let xml = get_timetable_xml().await; let classes = get_timetable_xml_data().await; @@ -124,6 +232,50 @@ pub async fn get_timetable(_conn: DbConn) -> Vec { timetable } +pub async fn get_today_class_timetable(_conn: DbConn, class: String) -> TimetableData { + let classes = get_today_timetable_xml_data().await; + let courses: Vec = Vec::new(); + let mut response = TimetableData { count: 0, courses }; + for i in classes.iter() { + if i.as_object() + .unwrap() + .get("Kurz") + .unwrap() + .as_str() + .unwrap() + .replace("/", "_") + == class + { + let nothing = json!([""]); + let std = i + .as_object() + .unwrap() + .get("Pl") + .unwrap() + .as_object() + .unwrap() + .get("Std") + .unwrap_or(¬hing); + let mut plan = vec![]; + if std.is_array() { + plan.extend(std.as_array().unwrap().iter().cloned()) + } else if std.is_object() { + plan.push(std.clone()) + } + response.count = plan.len(); + for i in plan { + if i.as_object() != None { + response.courses.push(i.to_owned()); + } else { + dbg!("Failed: {:?}", &i); + } + } + break; + } + } + response +} + pub async fn get_class_timetable(_conn: DbConn, class: String) -> TimetableData { let classes = get_timetable_xml_data().await; let courses: Vec = Vec::new(); diff --git a/src/main.rs b/src/main.rs index 5a5de0a..d3924a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -168,6 +168,15 @@ async fn get_timetable( Json::from(timetable) } +#[get("/today")] +async fn get_today_timetable( + conn: DbConn, + _key: ApiKey<'_>, +) -> Json> { + let timetable = timetable_connector::get_today_timetable(conn).await; + Json::from(timetable) +} + #[get("/")] async fn get_class_timetable( conn: DbConn, @@ -178,6 +187,16 @@ async fn get_class_timetable( Json::from(timetable) } +#[get("//today")] +async fn get_today_class_timetable( + conn: DbConn, + class: String, + _key: ApiKey<'_>, +) -> Json { + let timetable = timetable_connector::get_today_class_timetable(conn, class).await; + Json::from(timetable) +} + #[get("/")] async fn get_classes(_key: ApiKey<'_>) -> Json> { let class_list = timetable_connector::get_classes().await; @@ -192,7 +211,12 @@ fn rocket() -> _ { .mount("/login", routes![login]) .mount( "/api/timetable", - routes![get_timetable, get_class_timetable], + routes![ + get_timetable, + get_class_timetable, + get_today_timetable, + get_today_class_timetable + ], ) .mount("/api/classes", routes![get_classes]) .mount("/api/userinfo", routes![get_userinfo])