1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! 课表对象,一个对象存储有相同课程、相同行课节次和相同星期的一批行课安排
use serde::{Deserialize, Serialize};
use serde_with::{StringWithSeparator, formats::CommaSeparator, serde_as};
use super::{Course, CourseDayTime};
use crate::{
errors::mycqu::MyCQUResult,
mycqu::utils::mycqu_request_handler,
session::{Client, Session},
utils::{
ApiModel,
consts::{MYCQU_API_ENROLL_TIMETABLE_URL, MYCQU_API_TIMETABLE_URL},
datetimes::WeekStrHelper,
models::Period,
response_json_map,
},
};
/// 课表对象,一个对象存储有相同课程、相同行课节次和相同星期的一批行课安排
#[serde_as]
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct CourseTimetable {
/// 对应的课程
#[serde(flatten)]
pub course: Course,
/// 学生数
#[serde_as(deserialize_as = "Option<serde_with::DisplayFromStr>")]
#[serde(alias = "selectedStuNum")]
#[serde(default)]
pub stu_num: Option<u16>,
/// 行课地点,无则为[`None`]
#[serde(alias = "position")]
#[serde(default)]
pub classroom: Option<String>,
/// 行课周数
#[serde_as(deserialize_as = "serde_with::PickFirst<(_, WeekStrHelper)>")]
#[serde(alias = "teachingWeekFormat")]
#[serde(alias = "weeks")]
pub weeks: Vec<Period>,
/// 行课的星期和节次
///
/// 若时间是整周(如真实地占用整周的军训和某些实习、虚拟地使用一周的思修实践)则为[`None`]
#[serde_as(deserialize_as = "serde_with::DefaultOnError")]
#[serde(flatten)]
#[serde(default)]
pub day_time: Option<CourseDayTime>,
/// 是否真实地占用整周(如军训和某些实习是真实地占用、思修实践是“虚拟地占用”)
#[serde_as(deserialize_as = "serde_with::DefaultOnNull")]
#[serde(alias = "wholeWeekOccupy")]
#[serde(default)]
pub whole_week: bool,
/// 行课教室名称
#[serde(alias = "roomName")]
#[serde(default)]
pub classroom_name: Option<String>,
/// 实验课各次实验内容
#[serde_as(
deserialize_as = "serde_with::DefaultOnNull<StringWithSeparator::<CommaSeparator, String>>"
)]
#[serde(alias = "exprProjectName")]
#[serde(default)]
pub expr_projects: Vec<String>,
}
impl CourseTimetable {
/// 通过具有教务网权限的会话([`Session`]),获取当前学期课表([`Vec<CourseTimetable>`])
///
/// # Examples
/// ```rust, no_run
/// # use serde::de::Unexpected::Option;
/// # use rsmycqu::mycqu::access_mycqu;
/// # use rsmycqu::mycqu::course::{CourseTimetable, CQUSession};
/// # use rsmycqu::session::{Client, Session};
/// # use rsmycqu::sso::login;
///
/// # async fn fetch_curr_timetable() {
/// # let client = Client::default();
/// # let mut session = Session::new();
/// let cqu_session = CQUSession { id: Some(1234), year: 2023, is_autumn: true };
/// login(&client, &mut session, "your_auth", "your_password", false).await.unwrap();
/// access_mycqu(&client, &mut session).await.unwrap();
/// let user = CourseTimetable::fetch_curr(&client, &session, "2020xxxx", cqu_session.id.unwrap());
/// # }
/// ```
pub async fn fetch_curr(
client: &Client,
session: &Session,
student_id: impl AsRef<str>,
cqu_session_id: u16,
) -> MyCQUResult<Vec<Self>> {
let response = mycqu_request_handler(client, session, |client| {
client
.post(MYCQU_API_TIMETABLE_URL)
.query(&[("sessionId", cqu_session_id)])
.json(&vec![student_id.as_ref()])
})
.await?;
let (mut res, raw_response) = response_json_map(response).await?;
Self::extract_array(&mut res, "classTimetableVOList", &raw_response)
}
/// 通过具有教务网权限的会话([`Session`]),获取用户已选课程的课表([`Vec<CourseTimetable>`])
///
/// # Examples
/// ```rust, no_run
/// # use serde::de::Unexpected::Option;
/// # use rsmycqu::mycqu::access_mycqu;
/// # use rsmycqu::mycqu::course::{CourseTimetable, CQUSession};
/// # use rsmycqu::session::{Client, Session};
/// # use rsmycqu::sso::login;
///
/// # async fn fetch_curr_timetable() {
/// # let client = Client::default();
/// # let mut session = Session::new();
/// let cqu_session = CQUSession { id: Some(1234), year: 2023, is_autumn: true };
/// login(&client, &mut session, "your_auth", "your_password", false).await.unwrap();
/// access_mycqu(&client, &mut session).await.unwrap();
/// let user = CourseTimetable::fetch_enroll(&client, &session, "2020xxxx");
/// # }
/// ```
pub async fn fetch_enroll(
client: &Client,
session: &Session,
student_id: impl AsRef<str>,
) -> MyCQUResult<Vec<Self>> {
let response = mycqu_request_handler(client, session, |client| {
client.get(format!(
"{}/{}",
MYCQU_API_ENROLL_TIMETABLE_URL,
student_id.as_ref()
))
})
.await?;
let (mut res, raw_response) = response_json_map(response).await?;
Self::extract_array(&mut res, "data", &raw_response)
}
}
impl ApiModel for CourseTimetable {}