webweg/raw_types.rs
1use serde::{Deserialize, Serialize};
2use std::fmt::Display;
3
4/// One possible result you can get by searching for a particular course.
5#[derive(Debug, Serialize, Deserialize)]
6pub struct RawWebRegSearchResultItem {
7 /// The maximum number of units you can get.
8 #[serde(rename = "UNIT_TO")]
9 max_units: f32,
10
11 /// The subject code. For example, `CSE` or `MATH` are both possible option.
12 #[serde(rename = "SUBJ_CODE")]
13 pub subj_code: String,
14
15 /// The course title. For example, `Abstract Algebra II`.
16 #[serde(rename = "CRSE_TITLE")]
17 pub course_title: String,
18
19 /// The minimum number of units you can get.
20 #[serde(rename = "UNIT_FROM")]
21 min_units: f32,
22
23 /// The course code. For example, `100B`.
24 #[serde(rename = "CRSE_CODE")]
25 pub course_code: String,
26}
27
28impl Display for RawWebRegSearchResultItem {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 write!(
31 f,
32 "[{} {}] {} ({})",
33 self.subj_code.trim(),
34 self.course_code.trim(),
35 self.course_title.trim(),
36 self.max_units
37 )
38 }
39}
40
41/// A meeting. Note that this doesn't represent a class by itself, but rather a "piece" of that
42/// class. For example, one `WebRegMeeting` can represent a discussion while another can
43/// represent a lecture.
44#[derive(Debug, Serialize, Deserialize)]
45pub struct RawWebRegMeeting {
46 /// The hour part of the end time. For example, if this meeting ends at 11:50 AM, then
47 /// this would be `11`.
48 #[serde(rename = "END_HH_TIME")]
49 pub end_time_hr: i16,
50
51 /// The minutes part of the end time. For example, if this meeting ends at 11:50 AM, then
52 /// this would be `50`.
53 #[serde(rename = "END_MM_TIME")]
54 pub end_time_min: i16,
55
56 /// The section capacity. For example, if this section has a limit of 196, then this would be
57 /// `196`.
58 #[serde(rename = "SCTN_CPCTY_QTY")]
59 pub section_capacity: i64,
60
61 /// The number of students enrolled in this section.
62 #[serde(rename = "SCTN_ENRLT_QTY")]
63 pub enrolled_count: i64,
64
65 /// The section ID. Each section has a unique number identifier.
66 #[serde(rename = "SECTION_NUMBER")]
67 pub section_id: String,
68
69 /// The number of students currently on the waitlist.
70 #[serde(rename = "COUNT_ON_WAITLIST")]
71 pub count_on_waitlist: i64,
72
73 /// The room code. For example, if the meeting is in CENTR 119, then this would be `119`.
74 #[serde(rename = "ROOM_CODE")]
75 pub room_code: String,
76
77 /// The minute part of the meeting start time. For example, if this meeting starts at 11:00 AM,
78 /// then this would be `0`.
79 #[serde(rename = "BEGIN_MM_TIME")]
80 pub start_time_min: i16,
81
82 /// The hours part of the start time. For example, if this meeting starts at 11:00 AM, then
83 /// this would be `11`.
84 #[serde(rename = "BEGIN_HH_TIME")]
85 pub start_time_hr: i16,
86
87 /// The days that this meeting will take place. This string will only consist of the following:
88 /// - `1`: Monday
89 /// - `2`: Tuesday
90 /// - `3`: Wednesday
91 /// - `4`: Thursday
92 /// - `5`: Friday
93 ///
94 /// For example, if a class is meeting MWF, this would be `135`.
95 #[serde(rename = "DAY_CODE")]
96 pub day_code: String,
97
98 /// The instructor(s).
99 #[serde(rename = "PERSON_FULL_NAME")]
100 pub person_full_name: String,
101
102 /// Special meeting type, if any. If this is a normal meeting, this will be a string with a
103 /// two spaces.
104 #[serde(rename = "FK_SPM_SPCL_MTG_CD")]
105 pub special_meeting: String,
106
107 /// The building code. For example, if the meeting will take place at Center Hall, this would
108 /// be `CENTR`.
109 #[serde(rename = "BLDG_CODE")]
110 pub bldg_code: String,
111
112 /// The meeting type. See https://registrar.ucsd.edu/StudentLink/instr_codes.html. Note that
113 /// this will improperly record final exams, midterms, and other special events as lectures.
114 /// So, you need to check `special_meeting` also.
115 #[serde(rename = "FK_CDI_INSTR_TYPE")]
116 pub meeting_type: String,
117
118 /// The section code. For example, this could be `A00` or `B01`.
119 #[serde(rename = "SECT_CODE")]
120 pub sect_code: String,
121
122 /// The number of available seats.
123 #[serde(rename = "AVAIL_SEAT")]
124 pub avail_seat: i64,
125
126 /// The date that this meeting starts. Note that this (`start_date`) and `section_start_date`
127 /// will have different dates if the meeting that this `WebRegEvent` represents is a one-day
128 /// event (e.g. final exam).
129 #[serde(rename = "START_DATE")]
130 pub start_date: String,
131
132 /// The date that this section officially starts.
133 #[serde(rename = "SECTION_START_DATE")]
134 pub section_start_date: String,
135
136 /// How this particular entry is displayed. From my understanding, it looks like:
137 /// - `AC`: A section that can be enrolled or planned.
138 /// - `NC`: A section that cannot be enrolled or planned (see CSE 8A Discussions).
139 /// - `CA`: Canceled.
140 #[serde(rename = "FK_SST_SCTN_STATCD")]
141 pub display_type: String,
142
143 /// No idea what this does, but I'm assuming this tells you if the section
144 /// is visible on WebReg.
145 /// - `" "` (an empty space) or `"Y"` if it is visible, and
146 /// - `"N"` if it is not visible.
147 #[serde(rename = "PRINT_FLAG")]
148 pub print_flag: String,
149}
150
151impl RawWebRegMeeting {
152 /// Whether the meeting is visible on WebReg.
153 ///
154 /// I don't know if this actually works.
155 ///
156 /// # Returns
157 /// `true` if the meeting is visible on WebReg, and `false` otherwise.
158 pub fn is_visible(&self) -> bool {
159 self.print_flag.as_str() == "Y" || self.print_flag == " "
160 }
161}
162
163/// A meeting that you have enrolled in. Note that this doesn't represent a class by itself, but
164/// rather a "piece" of that class. For example, one `ScheduledMeeting` can represent a discussion
165/// while another can represent a lecture. Additionally, each `ScheduledMeeting` can only represent
166/// one meeting per week (so, for example, a MWF lecture would have 3 entries).
167#[derive(Serialize, Deserialize, Debug)]
168pub struct RawScheduledMeeting {
169 /// The section ID. Each section has a unique number identifier.
170 #[serde(rename = "SECTION_HEAD")]
171 pub section_id: i64,
172
173 /// Number of units that this class is being taken for (e.g. 4.00)
174 #[serde(rename = "SECT_CREDIT_HRS")]
175 pub sect_credit_hrs: f32,
176
177 /// The minute part of the meeting start time. For example, if this meeting starts at 11:00 AM,
178 /// then this would be `0`.
179 #[serde(rename = "BEGIN_MM_TIME")]
180 pub start_time_min: i16,
181
182 /// The hours part of the start time. For example, if this meeting starts at 11:00 AM, then
183 /// this would be `11`.
184 #[serde(rename = "BEGIN_HH_TIME")]
185 pub start_time_hr: i16,
186
187 /// The hour part of the end time. For example, if this meeting ends at 11:50 AM, then
188 /// this would be `11`.
189 #[serde(rename = "END_HH_TIME")]
190 pub end_time_hr: i16,
191
192 /// The minutes part of the end time. For example, if this meeting ends at 11:50 AM, then
193 /// this would be `50`.
194 #[serde(rename = "END_MM_TIME")]
195 pub end_time_min: i16,
196
197 /// The subject code. For example, `CSE` or `MATH` are both possible option.
198 #[serde(rename = "SUBJ_CODE")]
199 pub subj_code: String,
200
201 /// The room code. For example, if the meeting is in CENTR 119, then this would be `119`.
202 #[serde(rename = "ROOM_CODE")]
203 pub room_code: String,
204
205 /// The course title. For example, `Abstract Algebra II`.
206 #[serde(rename = "CRSE_TITLE")]
207 pub course_title: String,
208
209 /// The grading option. Some common options are `P/NP` or `L`, the former being pass/no pass
210 /// and the latter being letter.
211 #[serde(rename = "GRADE_OPTION")]
212 pub grade_option: String,
213
214 /// The day that this meeting starts. For lectures, this will usually be the first day of the
215 /// quarter; for midterms and finals, these will be given different dates.
216 #[serde(rename = "START_DATE")]
217 pub start_date: String,
218
219 /// The course code. For example, `100B`.
220 #[serde(rename = "CRSE_CODE")]
221 pub course_code: String,
222
223 /// The day code. Unlike in `WebRegMeeting`, this stores at most 1 number.
224 #[serde(rename = "DAY_CODE")]
225 pub day_code: String,
226
227 /// The professor teaching this course.
228 #[serde(rename = "PERSON_FULL_NAME")]
229 pub person_full_name: String,
230
231 /// Special meeting type, if any. If this is a normal meeting, this will be a string with a
232 /// two spaces. Note that
233 #[serde(rename = "FK_SPM_SPCL_MTG_CD")]
234 pub special_meeting: String,
235
236 /// The meeting type. See https://registrar.ucsd.edu/StudentLink/instr_codes.html. Note that
237 /// this will properly show the event type.
238 #[serde(rename = "FK_CDI_INSTR_TYPE")]
239 pub meeting_type: String,
240
241 /// The building code. For example, if the meeting will take place at Center Hall, this would
242 /// be `CENTR`.
243 #[serde(rename = "BLDG_CODE")]
244 pub bldg_code: String,
245
246 /// The current enrollment status. This can be one of:
247 /// - `EN`: Enrolled
248 /// - `WT`: Waitlisted
249 /// - `PL`: Planned
250 #[serde(rename = "ENROLL_STATUS")]
251 pub enroll_status: String,
252
253 /// The section code. For example, this could be `A00` or `B01`.
254 #[serde(rename = "SECT_CODE")]
255 pub sect_code: String,
256
257 /// The maximum number of students that can enroll in this section. Note that this is an
258 /// `Option` type; this is because this value won't exist if you can't directly enroll in the
259 /// section (e.g. you can't directly enroll in a lecture but you can directly enroll in a
260 /// lecture + discussion).
261 #[serde(rename = "SCTN_CPCTY_QTY")]
262 pub section_capacity: Option<i64>,
263
264 /// The number of students enrolled in this section. See `section_capacity` for information.
265 #[serde(rename = "SCTN_ENRLT_QTY")]
266 pub enrolled_count: Option<i64>,
267
268 /// The number of students currently on the waitlist.
269 #[serde(rename = "COUNT_ON_WAITLIST")]
270 pub count_on_waitlist: Option<i64>,
271
272 /// Your waitlist position. This will either be an empty string if there is no waitlist,
273 /// or your waitlist position if you are on the waitlist.
274 #[serde(rename = "WT_POS")]
275 pub waitlist_pos: String,
276}
277
278/// An enum that represents a prerequisite type. Generally, WebReg displays prerequisites as either
279/// a course requirement or a test requirement.
280///
281/// If we're working with a course requirement, then WebReg will categorize each course requirement
282/// by its `PREREQ_SEQ_ID`. For example, if course prerequisite A and B has PREREQ_SEQ_ID 1 and
283/// course prerequisite C has PREREQ_SEQ_ID 2, then this means that the prerequisites for this
284/// course is
285/// - one of A or B, and
286/// - C.
287#[derive(Serialize, Deserialize, Debug)]
288#[serde(tag = "TYPE")]
289pub enum RawPrerequisite {
290 /// Whether the prerequisite is a test/exam.
291 #[serde(rename = "TEST")]
292 Test(RawTestPrerequisite),
293
294 /// Whether the prerequisite is a course.
295 #[serde(rename = "COURSE")]
296 Course(RawCoursePrerequisite),
297}
298
299// Don't use inline struct in enum since that makes pattern matching unnecessary later.
300#[derive(Serialize, Deserialize, Debug)]
301pub struct RawTestPrerequisite {
302 /// The name of the test/exam.
303 #[serde(rename = "TEST_TITLE")]
304 pub test_title: String,
305}
306
307#[derive(Serialize, Deserialize, Debug)]
308pub struct RawCoursePrerequisite {
309 /// The subject code. For example, `CSE` or `MATH` are both possible option.
310 #[serde(rename = "SUBJECT_CODE")]
311 pub subject_code: String,
312
313 /// The group that this prerequisite is in. For example, if there are two prerequisites
314 /// with ID 1, then this means you just need ONE of those two prerequisites.
315 #[serde(rename = "PREREQ_SEQ_ID")]
316 pub prereq_seq_id: String,
317
318 /// The name of the course.
319 #[serde(rename = "CRSE_TITLE")]
320 pub course_title: String,
321
322 /// The course code. For example, `100A` is a possible option.
323 #[serde(rename = "COURSE_CODE")]
324 pub course_code: String,
325
326 // This always seem to be 450 or 600 or some multiple of 50.
327 #[serde(rename = "GRADE_SEQ_ID")]
328 pub grade_seq_id: String,
329}
330
331#[derive(Serialize, Deserialize)]
332pub struct RawEvent {
333 /// The location of the event.
334 #[serde(rename = "LOCATION")]
335 pub location: String,
336
337 /// The start time. Guaranteed to be length 4, where the first
338 /// two characters is the hour and the last two are minutes.
339 #[serde(rename = "START_TIME")]
340 pub start_time: String,
341
342 /// The end time. Guaranteed to be length 4, where the first
343 /// two characters is the hour and the last two are minutes.
344 #[serde(rename = "END_TIME")]
345 pub end_time: String,
346
347 /// A description of the event. AKA the name of the event.
348 #[serde(rename = "DESCRIPTION")]
349 pub description: String,
350
351 /// The days that this event will occur, represented as a binary
352 /// string. This is guaranteed to be length 7, where `0` means the
353 /// day is not selected and `1` means the day is selected. The first
354 /// bit will always be Monday, the second will always be Tuesday,
355 /// and the last bit will always be Sunday. In other words, the binary
356 /// string is formatted like so:
357 /// ```txt
358 /// MON TUE WED THU FRI SAT SUN
359 /// ```
360 /// So, for example, if we have `1010111`, then this means that Monday,
361 /// Wednesday, Friday, Saturday, and Sunday are selected.
362 #[serde(rename = "DAYS")]
363 pub days: String,
364
365 /// The timestamp, representing when the event was created. Use this
366 /// value to remove an event.
367 #[serde(rename = "TIME_STAMP")]
368 pub time_stamp: String,
369}
370
371// For those interested, a department and a subject are NOT the
372// same things, despite having many similar elements.
373//
374// The best way to think about it is: a department can have
375// multiple *subjects*.
376
377#[derive(Serialize, Deserialize)]
378pub struct RawSubjectElement {
379 /// The subject description. For example,
380 /// `Mathematics`.
381 #[serde(rename = "LONG_DESC")]
382 pub long_desc: String,
383
384 /// The subject code. For example, `MATH`.
385 #[serde(rename = "SUBJECT_CODE")]
386 pub subject_code: String,
387}
388
389#[derive(Serialize, Deserialize)]
390pub struct RawDepartmentElement {
391 /// The department code. For example, `MATH`.
392 #[serde(rename = "DEP_CODE")]
393 pub dep_code: String,
394
395 /// The department description. For example,
396 /// `Mathematics`.
397 #[serde(rename = "DEP_DESC")]
398 pub dep_desc: String,
399}
400
401#[derive(Serialize, Deserialize)]
402pub struct RawTermListItem {
403 /// The term description (e.g., Fall 2023).
404 #[serde(rename = "termDesc")]
405 pub term_desc: String,
406 /// The sequence ID.
407 #[serde(rename = "seqId")]
408 pub seq_id: i64,
409 /// The term code (e.g., FA23).
410 #[serde(rename = "termCode")]
411 pub term_code: String,
412}
413
414#[derive(Serialize, Deserialize)]
415pub struct RawCourseTextItem {
416 /// This partitioning of the course text information.
417 #[serde(rename = "TEXT")]
418 pub text: String,
419 /// The course code, where the subject and number is separated by a colon (e.g., `CSE:100`).
420 #[serde(rename = "SUBJCRSE")]
421 pub subj_crse: String,
422}
423
424#[derive(Serialize, Deserialize)]
425pub struct RawSectionTextItem {
426 /// The course section number (e.g., `123456`).
427 #[serde(rename = "SECTNUM")]
428 pub sectnum: String,
429
430 /// This partitioning of the subject text information.
431 #[serde(rename = "TEXT")]
432 pub text: String,
433}