feat(api): add api endpoints to retrieve every teacher and class

This commit is contained in:
Mariano Riefolo 2024-09-02 17:43:48 +02:00
parent 8d1fe3b8f2
commit d3d9f04a2c

View File

@ -11,7 +11,7 @@ use scraper::{Html, Selector};
use serde::Deserialize;
use serde_json::json;
use sha1::{Digest, Sha1};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::ops::Range;
use std::{fs, process::Command};
@ -21,7 +21,9 @@ pub fn get_routes() -> Router {
Router::new()
.route("/pdf", get(pdf))
.route("/classi", get(get_classes))
.route("/professori", get(get_teachers)),
.route("/professori", get(get_teachers))
.route("/classe", get(get_class))
.route("/professore", get(get_teacher)),
)
}
@ -94,7 +96,7 @@ pub struct Header {
weekdays: HashMap<String, Range<usize>>,
}
pub async fn get_classes(Query(params): Query<FilterByTeacherQuery>) -> impl IntoResponse {
pub async fn get_class(Query(params): Query<FilterByTeacherQuery>) -> impl IntoResponse {
let filename = match download_pdf(params.id).await {
Ok(x) => x,
Err(_) => {
@ -136,7 +138,7 @@ pub struct FilterByClassQuery {
classe: String,
}
pub async fn get_teachers(Query(params): Query<FilterByClassQuery>) -> impl IntoResponse {
pub async fn get_teacher(Query(params): Query<FilterByClassQuery>) -> impl IntoResponse {
let filename = match download_pdf(params.id).await {
Ok(x) => x,
Err(_) => {
@ -222,3 +224,106 @@ pub fn get_header(record: &StringRecord) -> Header {
weekdays,
}
}
#[derive(Deserialize)]
pub struct GetTeachersQuery {
id: u8,
}
pub async fn get_teachers(Query(params): Query<GetTeachersQuery>) -> impl IntoResponse {
let filename = match download_pdf(params.id).await {
Ok(x) => x,
Err(_) => {
return (
StatusCode::UNPROCESSABLE_ENTITY,
Json(json!({ "errore": "ID non valido"})),
)
}
};
let csv_content = fs::read_to_string(&filename).unwrap();
let mut rdr = csv::Reader::from_reader(csv_content.as_bytes());
let header = get_header(rdr.headers().unwrap());
let mut teachers = Vec::new();
for record in rdr.records() {
let record = match record {
Ok(x) => x,
Err(_) => {
return (
StatusCode::UNPROCESSABLE_ENTITY,
Json(json!({ "errore": "Formato non supportato"})),
)
}
};
if let Some(teacher) = record.get(header.teacher as usize) {
if !teacher.is_empty() {
teachers.push(teacher.to_owned());
}
}
}
if !teachers.is_empty() {
(StatusCode::OK, Json(json!(teachers)))
} else {
(
StatusCode::UNPROCESSABLE_ENTITY,
Json(json!({ "errore": "classe non trovata"})),
)
}
}
#[derive(Deserialize)]
pub struct GetClassesQuery {
id: u8,
}
fn is_valid_class(class: &str) -> bool {
class.len() == 5
&& class.chars().next().unwrap().is_digit(6)
&& class.chars().skip(1).all(|x| x.is_alphabetic())
}
pub async fn get_classes(Query(params): Query<GetClassesQuery>) -> impl IntoResponse {
let filename = match download_pdf(params.id).await {
Ok(x) => x,
Err(_) => {
return (
StatusCode::UNPROCESSABLE_ENTITY,
Json(json!({ "errore": "ID non valido"})),
)
}
};
let csv_content = fs::read_to_string(&filename).unwrap();
let mut rdr = csv::Reader::from_reader(csv_content.as_bytes());
let header = get_header(rdr.headers().unwrap());
let mut classes: Vec<HashMap<char, HashSet<String>>> = vec![HashMap::new(); 5];
for record in rdr.records() {
let record = record.unwrap();
for (i, cell) in record.iter().enumerate() {
for (_, range) in header.weekdays.clone() {
if range.contains(&i) && is_valid_class(cell) {
let value = classes
[cell.chars().next().unwrap().to_digit(6).unwrap() as usize - 1usize]
.entry(cell.chars().nth(1).unwrap())
.or_default();
value.insert(cell[2..].to_string().to_lowercase());
}
}
}
}
if classes.is_empty() {
(
StatusCode::UNPROCESSABLE_ENTITY,
Json(json!({ "errore": "classe non trovata"})),
)
} else {
(StatusCode::OK, Json(json!(classes)))
}
}