manaba_sdk/scrape/
report.rs

1use crate::assignment::{AssignmentDate, AssignmentReceptibleState, AssignmentSubmitState};
2use crate::error::Result;
3use crate::{Client, Course};
4use scraper::Selector;
5
6#[derive(Debug)]
7pub struct Report {
8    pub title: String,
9    pub submit_state: AssignmentSubmitState,
10    pub receptiable_state: AssignmentReceptibleState,
11    pub start_date: Option<AssignmentDate>,
12    pub due_date: Option<AssignmentDate>,
13}
14
15impl Client {
16    pub async fn get_reports(&self, course: &Course) -> Result<Vec<Report>> {
17        let url = format!("{}_report", course.id);
18        let html = self.get_html(reqwest::Method::GET, url).await?;
19
20        let selector = Selector::parse("table.stdlist tr:not(.title)")?;
21        let reports_element = html.select(&selector);
22
23        let reports = reports_element
24            .map(|report_element| {
25                let selector = Selector::parse("td").unwrap();
26                let mut rows = report_element.select(&selector);
27
28                let title = {
29                    let row = rows.next().unwrap();
30                    let selector = Selector::parse("a").unwrap();
31                    let report_title_element = row.select(&selector).next().unwrap();
32                    report_title_element.inner_html()
33                };
34
35                let (receptiable_state, submit_state) = {
36                    let row = rows.next().unwrap();
37
38                    let selector = Selector::parse("div").unwrap();
39                    let receptiable_state = row.select(&selector).next().map_or(
40                        AssignmentReceptibleState::NotStarted,
41                        |state| match state.inner_html().as_str() {
42                            "受付中" => AssignmentReceptibleState::Open,
43                            "受付終了" => AssignmentReceptibleState::Closed,
44                            _ => AssignmentReceptibleState::NotStarted,
45                        },
46                    );
47
48                    let selector = Selector::parse("span").unwrap();
49                    let submit_state = row.select(&selector).next().map_or(
50                        AssignmentSubmitState::Done,
51                        |submit_state| {
52                            if submit_state.inner_html() == "未提出" {
53                                AssignmentSubmitState::Todo
54                            } else {
55                                AssignmentSubmitState::Done
56                            }
57                        },
58                    );
59
60                    (receptiable_state, submit_state)
61                };
62
63                let start_date = {
64                    let row = rows.next().unwrap();
65                    let date = row.inner_html();
66                    if date.is_empty() {
67                        None
68                    } else {
69                        Some(AssignmentDate::new(&date))
70                    }
71                };
72
73                let due_date = {
74                    let row = rows.next().unwrap();
75                    let date = row.inner_html();
76                    if date.is_empty() {
77                        None
78                    } else {
79                        Some(AssignmentDate::new(&date))
80                    }
81                };
82
83                Report {
84                    title,
85                    receptiable_state,
86                    submit_state,
87                    start_date,
88                    due_date,
89                }
90            })
91            .collect::<Vec<Report>>();
92
93        Ok(reports)
94    }
95}