195 lines
5.4 KiB
Rust
195 lines
5.4 KiB
Rust
use actix_web::{get, HttpResponse};
|
|
use anyhow::Result;
|
|
use deunicode::deunicode;
|
|
use fancy_regex::Regex;
|
|
use lazy_static::lazy_static;
|
|
use serde::Serialize;
|
|
use std::collections::HashMap;
|
|
|
|
use crate::config;
|
|
|
|
lazy_static! {
|
|
static ref CLASS_REGEX: Regex = Regex::new(r"(9|10)\s?(?!R)[a-z]").unwrap();
|
|
}
|
|
|
|
#[derive(Serialize, Debug)]
|
|
pub struct Class {
|
|
pub name: String,
|
|
pub students: Vec<User>,
|
|
}
|
|
|
|
#[derive(Serialize, Debug)]
|
|
pub struct User {
|
|
pub username: String,
|
|
pub first_name: String,
|
|
pub last_name: String,
|
|
}
|
|
|
|
#[derive(Serialize, Debug)]
|
|
pub struct GetStudentsResponse {
|
|
pub error: Option<String>,
|
|
pub classes: Vec<Class>,
|
|
pub teachers: Vec<User>,
|
|
}
|
|
|
|
fn escape_username(s: &str) -> String {
|
|
deunicode(
|
|
&s.to_lowercase()
|
|
.chars()
|
|
.filter(|c| !c.is_whitespace())
|
|
.collect::<String>(),
|
|
)
|
|
}
|
|
|
|
async fn students(
|
|
client: &mut untis::Client,
|
|
usernames: &mut HashMap<String, usize>,
|
|
) -> Result<Vec<Class>> {
|
|
Ok(futures::future::try_join_all(
|
|
client
|
|
.classes()
|
|
.await?
|
|
.iter()
|
|
.filter(|c| CLASS_REGEX.is_match(&c.name).unwrap())
|
|
.map(|c| async {
|
|
Ok::<_, anyhow::Error>(Class {
|
|
name: c.name.to_owned(),
|
|
students: client
|
|
.student_reports(c.id)
|
|
.await?
|
|
.into_iter()
|
|
.map(|s| User {
|
|
username: escape_username(&s.name),
|
|
first_name: s.fore_name,
|
|
last_name: s.long_name,
|
|
})
|
|
.collect(),
|
|
})
|
|
}),
|
|
)
|
|
.await?
|
|
.into_iter()
|
|
.map(|c| Class {
|
|
name: c.name,
|
|
students: c
|
|
.students
|
|
.into_iter()
|
|
.map(|s| User {
|
|
username: {
|
|
let escaped = escape_username(&s.username);
|
|
match usernames.get_mut(&escaped) {
|
|
Some(x) => {
|
|
*x += 1;
|
|
format!("{}{}", escaped, x)
|
|
}
|
|
None => {
|
|
usernames.insert(escaped.to_owned(), 1);
|
|
escaped
|
|
}
|
|
}
|
|
},
|
|
first_name: s.first_name,
|
|
last_name: s.last_name,
|
|
})
|
|
.collect(),
|
|
})
|
|
.collect())
|
|
}
|
|
|
|
async fn teachers(
|
|
client: &mut untis::Client,
|
|
usernames: &mut HashMap<String, usize>,
|
|
) -> Result<Vec<User>> {
|
|
Ok(client
|
|
.teacher_reports()
|
|
.await?
|
|
.into_iter()
|
|
.filter_map(|t| {
|
|
if t.long_name.starts_with("Abi-Aufsicht")
|
|
|| t.long_name == "SBBZ"
|
|
|| t.long_name == "N.N."
|
|
|| t.long_name == "Werkrealschule"
|
|
{
|
|
None
|
|
} else {
|
|
Some(User {
|
|
username: {
|
|
let escaped = escape_username(&t.name);
|
|
match usernames.get_mut(&escaped) {
|
|
Some(x) => {
|
|
*x += 1;
|
|
format!("{}{}", escaped, x)
|
|
}
|
|
None => {
|
|
usernames.insert(escaped.to_owned(), 1);
|
|
escaped
|
|
}
|
|
}
|
|
},
|
|
first_name: t.fore_name,
|
|
last_name: t.long_name,
|
|
})
|
|
}
|
|
})
|
|
.collect())
|
|
}
|
|
|
|
#[get("/v1/users")]
|
|
pub async fn get_users() -> HttpResponse {
|
|
let mut client = match config::untis_from_env() {
|
|
Ok(x) => x,
|
|
Err(x) => {
|
|
return HttpResponse::InternalServerError().json(GetStudentsResponse {
|
|
error: Some(x.to_string()),
|
|
classes: vec![],
|
|
teachers: vec![],
|
|
})
|
|
}
|
|
};
|
|
if let Err(x) = client.login().await {
|
|
return HttpResponse::InternalServerError().json(GetStudentsResponse {
|
|
error: Some(x.to_string()),
|
|
classes: vec![],
|
|
teachers: vec![],
|
|
});
|
|
}
|
|
|
|
let mut usernames = HashMap::<String, usize>::new();
|
|
let classes = match students(&mut client, &mut usernames).await {
|
|
Ok(x) => x,
|
|
Err(x) => {
|
|
return HttpResponse::InternalServerError().json(GetStudentsResponse {
|
|
error: Some(x.to_string()),
|
|
classes: vec![],
|
|
teachers: vec![],
|
|
})
|
|
}
|
|
};
|
|
let teachers = match teachers(&mut client, &mut usernames).await {
|
|
Ok(x) => x,
|
|
Err(x) => {
|
|
return HttpResponse::InternalServerError().json(GetStudentsResponse {
|
|
error: Some(x.to_string()),
|
|
classes: vec![],
|
|
teachers: vec![],
|
|
})
|
|
}
|
|
};
|
|
|
|
if let Err(x) = client.logout().await {
|
|
return HttpResponse::InternalServerError().json(GetStudentsResponse {
|
|
error: Some(x.to_string()),
|
|
classes: vec![],
|
|
teachers: vec![],
|
|
});
|
|
}
|
|
|
|
HttpResponse::Ok()
|
|
.content_type(mime::APPLICATION_JSON)
|
|
.json(GetStudentsResponse {
|
|
error: None,
|
|
classes,
|
|
teachers,
|
|
})
|
|
}
|