Split today and latest timetable

This commit is contained in:
Denys Konovalov 2021-09-06 21:00:41 +02:00
parent e04f39945e
commit 228bd4e46e
3 changed files with 180 additions and 3 deletions

@ -17,6 +17,7 @@ serde_json = "1.0"
jsonwebtoken = "7.2" jsonwebtoken = "7.2"
time = "0.2" time = "0.2"
keycloak = "14" keycloak = "14"
chrono = "0.4"
[dependencies.serde_derive] [dependencies.serde_derive]

@ -1,6 +1,7 @@
use crate::config; use crate::config;
use crate::schema::timetable; use crate::schema::timetable;
use crate::DbConn; use crate::DbConn;
use chrono::Local;
use diesel::{Insertable, Queryable}; use diesel::{Insertable, Queryable};
use quickxml_to_serde::{xml_string_to_json, Config}; use quickxml_to_serde::{xml_string_to_json, Config};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
@ -21,10 +22,14 @@ pub struct TimetableData {
pub courses: Vec<rocket::serde::json::Value>, pub courses: Vec<rocket::serde::json::Value>,
} }
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 client = reqwest::Client::new();
let resp = client 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) .basic_auth(config::TIMETABLE_USER, config::TIMETABLE_PASSWORD)
.send() .send()
.await .await
@ -35,6 +40,36 @@ async fn get_timetable_xml() -> serde_json::value::Value {
xml_string_to_json(resp, &Config::new_with_defaults()).unwrap() 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<serde_json::value::Value> {
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<serde_json::value::Value> { async fn get_timetable_xml_data() -> Vec<serde_json::value::Value> {
let xml = get_timetable_xml().await; let xml = get_timetable_xml().await;
let classes = xml let classes = xml
@ -51,6 +86,79 @@ async fn get_timetable_xml_data() -> Vec<serde_json::value::Value> {
classes.to_owned() classes.to_owned()
} }
pub async fn get_today_timetable(_conn: DbConn) -> Vec<Timetable> {
let xml = get_today_timetable_xml().await;
let classes = get_today_timetable_xml_data().await;
let mut timetable: Vec<Timetable> = Vec::new();
for i in classes.iter() {
let mut courses: Vec<rocket::serde::json::Value> = Vec::new();
let nothing = json!([""]);
let std = i
.as_object()
.unwrap()
.get("Pl")
.unwrap()
.as_object()
.unwrap()
.get("Std")
.unwrap_or(&nothing);
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<Timetable> { pub async fn get_timetable(_conn: DbConn) -> Vec<Timetable> {
let xml = get_timetable_xml().await; let xml = get_timetable_xml().await;
let classes = get_timetable_xml_data().await; let classes = get_timetable_xml_data().await;
@ -124,6 +232,50 @@ pub async fn get_timetable(_conn: DbConn) -> Vec<Timetable> {
timetable timetable
} }
pub async fn get_today_class_timetable(_conn: DbConn, class: String) -> TimetableData {
let classes = get_today_timetable_xml_data().await;
let courses: Vec<rocket::serde::json::Value> = 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(&nothing);
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 { pub async fn get_class_timetable(_conn: DbConn, class: String) -> TimetableData {
let classes = get_timetable_xml_data().await; let classes = get_timetable_xml_data().await;
let courses: Vec<rocket::serde::json::Value> = Vec::new(); let courses: Vec<rocket::serde::json::Value> = Vec::new();

@ -168,6 +168,15 @@ async fn get_timetable(
Json::from(timetable) Json::from(timetable)
} }
#[get("/today")]
async fn get_today_timetable(
conn: DbConn,
_key: ApiKey<'_>,
) -> Json<Vec<timetable_connector::Timetable>> {
let timetable = timetable_connector::get_today_timetable(conn).await;
Json::from(timetable)
}
#[get("/<class>")] #[get("/<class>")]
async fn get_class_timetable( async fn get_class_timetable(
conn: DbConn, conn: DbConn,
@ -178,6 +187,16 @@ async fn get_class_timetable(
Json::from(timetable) Json::from(timetable)
} }
#[get("/<class>/today")]
async fn get_today_class_timetable(
conn: DbConn,
class: String,
_key: ApiKey<'_>,
) -> Json<timetable_connector::TimetableData> {
let timetable = timetable_connector::get_today_class_timetable(conn, class).await;
Json::from(timetable)
}
#[get("/")] #[get("/")]
async fn get_classes(_key: ApiKey<'_>) -> Json<Vec<String>> { async fn get_classes(_key: ApiKey<'_>) -> Json<Vec<String>> {
let class_list = timetable_connector::get_classes().await; let class_list = timetable_connector::get_classes().await;
@ -192,7 +211,12 @@ fn rocket() -> _ {
.mount("/login", routes![login]) .mount("/login", routes![login])
.mount( .mount(
"/api/timetable", "/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/classes", routes![get_classes])
.mount("/api/userinfo", routes![get_userinfo]) .mount("/api/userinfo", routes![get_userinfo])