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}