Correctly build the timetable from scratch

This commit is contained in:
Mylloon 2023-09-26 23:08:41 +02:00
parent b3fec12292
commit 189b77cc4f
Signed by: Anri
GPG key ID: A82D63DFF8D1317F
3 changed files with 92 additions and 14 deletions

View file

@ -55,10 +55,9 @@ async fn main() {
level, level,
pathway.to_uppercase() pathway.to_uppercase()
); );
let timetable = let timetable = timetable::timetable(level, args.semester, args.year, &user_agent).await;
timetable::timetable(level, args.semester, args.year, pathway, &user_agent).await;
/* println!("Récupération des informations par rapport à l'année..."); println!("Récupération des informations par rapport à l'année...");
let info = info::info(&user_agent).await; let info = info::info(&user_agent).await;
if args.export.is_some() { if args.export.is_some() {
@ -74,5 +73,5 @@ async fn main() {
println!("Affichage..."); println!("Affichage...");
timetable::display(timetable, args.cl); timetable::display(timetable, args.cl);
println!("Vous devrez peut-être mettre votre terminal en plein écran si ce n'est pas déjà le cas."); println!("Vous devrez peut-être mettre votre terminal en plein écran si ce n'est pas déjà le cas.");
} */ }
} }

View file

@ -4,7 +4,7 @@ use scraper::{Html, Selector};
use std::collections::HashMap; use std::collections::HashMap;
use crate::utils::{ use crate::utils::{
self, capitalize, self,
models::{Position, TabChar}, models::{Position, TabChar},
}; };
@ -15,7 +15,6 @@ pub async fn timetable(
level: i8, level: i8,
semester_opt: Option<i8>, semester_opt: Option<i8>,
year_opt: Option<i32>, year_opt: Option<i32>,
pathway: &str,
user_agent: &str, user_agent: &str,
) -> (Vec<String>, (usize, Vec<models::Day>)) { ) -> (Vec<String>, (usize, Vec<models::Day>)) {
let semester = get_semester(semester_opt); let semester = get_semester(semester_opt);
@ -30,23 +29,92 @@ pub async fn timetable(
let sel_table = Selector::parse("table").unwrap(); let sel_table = Selector::parse("table").unwrap();
let sel_tbody = Selector::parse("tbody").unwrap(); let sel_tbody = Selector::parse("tbody").unwrap();
let sel_td = Selector::parse("td").unwrap(); let sel_td = Selector::parse("td").unwrap();
let sel_small = Selector::parse("small").unwrap();
let sel_b = Selector::parse("b").unwrap();
// Find the timetable // Find the timetable
let raw_timetable = document.select(&sel_table).next().unwrap(); let raw_timetable = document.select(&sel_table).next().unwrap();
/* We are now iterating over all the 15-minute intervals to find courses */ let mut schedules = Vec::new();
for element in raw_timetable for hour in 8..=20 {
for minute in &[0, 15, 30, 45] {
let hour_str = format!("{}h{:02}", hour, minute);
schedules.push(hour_str);
}
}
let mut timetable: Vec<models::Day> = Vec::new();
raw_timetable
.select(&sel_tbody) .select(&sel_tbody)
.next() .next()
.unwrap() .unwrap()
.select(&sel_td) .select(&sel_td)
{ .filter(|element| element.value().attr("title").is_some())
if let Some(i) = element.value().attr("title") { .for_each(|i| {
println!("{}", i) let matches =
Regex::new(r"(?P<type>COURS|TD|TP) (?P<name>.*) : (?P<day>(lundi|mardi|mercredi|jeudi|vendredi)) (?P<startime>.*) \(durée : (?P<duration>.*)\)")
.unwrap()
.captures(i.value().attr("title").unwrap())
.unwrap();
let day: &str = matches
.name("day")
.unwrap()
.as_str();
let binding = i.select(&sel_b).last().unwrap().inner_html();
let course = models::Course{
typee: match matches
.name("type")
.unwrap()
.as_str() {
"COURS" => models::Type::Cours,
"TP" => models::Type::TP,
"TD" => models::Type::TD,
_ => panic!("Unknown type of course")
},
name: matches
.name("name")
.unwrap()
.as_str().to_owned(),
professor: match i.select(&sel_small).last().unwrap().inner_html() {
i if i.starts_with("<span") => None,
i => Some(i),
},
room: Regex::new(r"(<table.*<\/table>|<br>.*?<br>.*?)<br>(?P<location>.*?)<br>")
.unwrap()
.captures(&binding)
.unwrap().name("location")
.unwrap()
.as_str().to_owned(),
start: schedules.iter().position(|r| r == matches
.name("startime")
.unwrap()
.as_str()).unwrap(),
size: i.value().attr("rowspan").unwrap().parse::<usize >().unwrap(),
dtstart: None,
dtend: None,
};
// Search for the day in the timetable
if let Some(existing_day) = timetable.iter_mut().find(|x| x.name == day) {
existing_day.courses.push(Some(course));
} else {
// Day with the name doesn't exist, create a new Day
timetable.push(models::Day {
name: day.to_owned(),
courses: vec![Some(course)],
});
} }
});
if !check_consistency(&schedules, &timetable) {
panic!("Error when building the timetable.");
} }
todo!() (schedules, (semester as usize, timetable))
} }
/// Get timetable webpage /// Get timetable webpage

View file

@ -1,5 +1,15 @@
#[derive(Clone)] #[derive(Clone, Debug)]
pub enum Type {
Cours,
TP,
TD,
}
#[derive(Clone, Debug)]
pub struct Course { pub struct Course {
/// Type du cours
pub typee: Type,
/// Course's name /// Course's name
pub name: String, pub name: String,
@ -27,6 +37,7 @@ pub struct Course {
pub dtend: Option<chrono::DateTime<chrono::Utc>>, pub dtend: Option<chrono::DateTime<chrono::Utc>>,
} }
#[derive(Debug)]
pub struct Day { pub struct Day {
/// Day's name /// Day's name
pub name: String, pub name: String,