#![feature(custom_attribute)]
use reformation::Reformation;
#[macro_use]
extern crate failure_derive;
#[macro_use]
extern crate unhtml_derive;
use crate::err::DeserializeError;
use std::str::FromStr;
use unhtml::{self, VecFromHtml};
#[derive(FromHtml)]
pub struct HiddenForm {
#[html(
selector = "input[type=\"hidden\"][name=\"__EVENTTARGET\"]",
attr = "value",
default = ""
)]
pub event_target: String,
#[html(
selector = "input[type=\"hidden\"][name=\"__EVENTARGUMENT\"]",
attr = "value",
default = ""
)]
pub event_argument: String,
#[html(
selector = "input[type=\"hidden\"][name=\"__VIEWSTATE\"]",
attr = "value"
)]
pub view_state: String,
}
#[derive(FromHtml)]
pub struct LoginPage {
#[html(selector = "#Form1")]
pub hidden_form: HiddenForm,
}
#[derive(FromHtml)]
pub struct SelectMenu {
#[html(
selector = "option[selected=\"selected\"]",
attr = "value",
default = ""
)]
pub selected: String,
#[html(selector = "option", attr = "value")]
pub all_options: Vec<String>,
}
#[derive(FromHtml)]
pub struct Course {
#[html(selector = "td:nth-child(1) > a", attr = "inner")]
pub code: String,
#[html(selector = "td:nth-child(2) > a", attr = "inner")]
pub name: String,
#[html(selector = "td:nth-child(3) > a", attr = "inner")]
pub teacher_name: String,
#[html(selector = "td:nth-child(4)", attr = "inner")]
pub semester: String,
#[html(selector = "td:nth-child(5)", attr = "inner")]
pub times: String,
#[html(selector = "td:nth-child(6)", attr = "inner")]
pub places: String,
}
#[derive(FromHtml)]
pub struct CoursesPage {
#[html(selector = "#xskb_form")]
pub hidden_form: HiddenForm,
#[html(selector = "#xnd")]
pub school_year: SelectMenu,
#[html(selector = "#xqd")]
pub semester: SelectMenu,
#[html(selector = "#xsgrid > tbody > tr:nth-child(1n + 2)")]
pub courses: Vec<Course>,
}
#[derive(Reformation)]
#[reformation(r"{year}年{month}月{day}日\({start_hour}:{start_min}-{end_hour}:{end_min}\)")]
pub struct ExamTime {
pub year: i32,
pub month: u32,
pub day: u32,
pub start_hour: u32,
pub start_min: u32,
pub end_hour: u32,
pub end_min: u32,
}
pub enum OptionalExamTime {
Some(ExamTime),
None,
}
impl FromStr for OptionalExamTime {
type Err = DeserializeError;
fn from_str(raw_time: &str) -> Result<Self, Self::Err> {
match raw_time {
" " => Ok(OptionalExamTime::None),
other => Ok(OptionalExamTime::Some(ExamTime::parse(other)?)),
}
}
}
#[derive(FromHtml)]
pub struct Exam {
#[html(selector = "td:nth-child(1)", attr = "inner")]
pub identifier: String,
#[html(selector = "td:nth-child(2)", attr = "inner")]
pub name: String,
#[html(selector = "td:nth-child(3)", attr = "inner")]
pub credit: f32,
#[html(selector = "td:nth-child(4)", attr = "inner")]
pub relearning: String,
#[html(selector = "td:nth-child(6)", attr = "inner")]
pub semester: String,
#[html(selector = "td:nth-child(7)", attr = "inner")]
pub final_exam_time: OptionalExamTime,
#[html(selector = "td:nth-child(8)", attr = "inner")]
pub final_exam_place: String,
#[html(selector = "td:nth-child(9)", attr = "inner")]
pub final_exam_seat: String,
#[html(selector = "td:nth-child(10)", attr = "inner")]
pub mid_exam_time: OptionalExamTime,
#[html(selector = "td:nth-child(11)", attr = "inner")]
pub mid_exam_place: String,
#[html(selector = "td:nth-child(12)", attr = "inner")]
pub mid_exam_seat: String,
}
#[derive(FromHtml)]
pub struct ExamsPage {
#[html(selector = "#_ctl0")]
pub hidden_form: HiddenForm,
#[html(selector = "#xnd")]
pub school_year: SelectMenu,
#[html(selector = "#xqd")]
pub semester: SelectMenu,
#[html(selector = "#DataGrid1 > tbody > tr:nth-child(1n + 2)")]
pub exams: Vec<Exam>,
}
#[derive(FromHtml)]
pub struct ObjectMovedPage {
#[html(selector = "a", attr = "href")]
pub to: String,
}
#[derive(FromHtml)]
pub struct MajorScoresPage {
#[html(selector = "#DataGrid1 > tbody > tr:nth-child(1n + 2)")]
pub scores: Vec<MajorScore>,
#[html(selector = "#Label1", attr = "inner")]
pub summary_table: MajorSummaryTable,
}
#[derive(FromHtml)]
pub struct MajorScore {
#[html(selector = "td:nth-child(1)", attr = "inner")]
pub identifier: String,
#[html(selector = "td:nth-child(2)", attr = "inner")]
pub course_name: String,
#[html(selector = "td:nth-child(3)", attr = "inner")]
pub raw_score: String,
#[html(selector = "td:nth-child(4)", attr = "inner")]
pub final_score: f32,
#[html(selector = "td:nth-child(5)", attr = "inner")]
pub credit: f32,
#[html(selector = "td:nth-child(6)", attr = "inner")]
pub grade_point: f32,
#[html(selector = "td:nth-child(7)", attr = "inner")]
pub school_year: String,
}
pub struct MajorSummaryTable {
pub gpa: KVPattern,
pub total_credit: KVPattern,
}
impl FromStr for MajorSummaryTable {
type Err = DeserializeError;
fn from_str(data: &str) -> Result<Self, Self::Err> {
let patterns = data
.split(" ")
.collect::<Vec<&str>>();
Ok(Self {
gpa: KVPattern::parse(patterns[0])?,
total_credit: KVPattern::parse(patterns[1])?,
})
}
}
#[derive(FromHtml)]
pub struct Score {
#[html(selector = "td:nth-child(1)", attr = "inner")]
pub identifier: String,
#[html(selector = "td:nth-child(2)", attr = "inner")]
pub course_name: String,
#[html(selector = "td:nth-child(3)", attr = "inner")]
pub raw_score: String,
#[html(selector = "td:nth-child(4)", attr = "inner")]
pub credit: f32,
#[html(selector = "td:nth-child(5)", attr = "inner")]
pub grade_point: f32,
#[html(selector = "td:nth-child(6)", attr = "inner")]
pub makeup_score: String,
}
#[derive(FromHtml)]
pub struct ScoresPage {
#[html(selector = "#DataGrid1 > tbody > tr:nth-child(1n + 2)")]
pub scores: Vec<Score>,
}
#[derive(FromHtml)]
pub struct ScoresBasePage {
#[html(selector = "#Form1")]
pub hidden_form: HiddenForm,
#[html(selector = "#ddlXN")]
pub school_year: SelectMenu,
}
#[derive(Reformation)]
#[reformation(r"{key}={value}")]
pub struct KVPattern {
pub key: String,
pub value: f32,
}
#[derive(FromHtml)]
pub struct TotalCreditPage {
#[html(selector = "#lb_yhxf", attr = "inner")]
pub credit: f32,
}
mod err;
#[cfg(test)]
mod tests;