|
4 | 4 | # |
5 | 5 | # Table name: courses |
6 | 6 | # |
7 | | -# id :bigint not null, primary key |
8 | | -# course_number :integer not null |
9 | | -# credit_hours :integer |
10 | | -# crn :integer not null |
11 | | -# end_date :date not null |
12 | | -# grade_mode :string |
13 | | -# schedule_type :string not null |
14 | | -# seats_available :integer |
15 | | -# seats_capacity :integer |
16 | | -# section_number :string not null |
17 | | -# start_date :date not null |
18 | | -# status :string default("active"), not null |
19 | | -# subject :string not null |
20 | | -# title :string not null |
21 | | -# created_at :datetime not null |
22 | | -# updated_at :datetime not null |
23 | | -# term_id :bigint not null |
| 7 | +# id :bigint not null, primary key |
| 8 | +# course_number :integer not null |
| 9 | +# credit_hours :integer |
| 10 | +# crn :integer not null |
| 11 | +# end_date :date not null |
| 12 | +# grade_mode :string |
| 13 | +# is_section_linked :boolean default(FALSE), not null |
| 14 | +# link_identifier :string |
| 15 | +# schedule_type :string not null |
| 16 | +# seats_available :integer |
| 17 | +# seats_capacity :integer |
| 18 | +# section_number :string not null |
| 19 | +# start_date :date not null |
| 20 | +# status :string default("active"), not null |
| 21 | +# subject :string not null |
| 22 | +# title :string not null |
| 23 | +# created_at :datetime not null |
| 24 | +# updated_at :datetime not null |
| 25 | +# term_id :bigint not null |
24 | 26 | # |
25 | 27 | # Indexes |
26 | 28 | # |
27 | | -# index_courses_on_crn_and_term_id (crn,term_id) UNIQUE |
28 | | -# index_courses_on_status (status) |
29 | | -# index_courses_on_term_id (term_id) |
| 29 | +# index_courses_on_course_and_link_identifier (term_id,subject,course_number,link_identifier) |
| 30 | +# index_courses_on_crn_and_term_id (crn,term_id) UNIQUE |
| 31 | +# index_courses_on_status (status) |
| 32 | +# index_courses_on_term_id (term_id) |
30 | 33 | # |
31 | 34 | # Foreign Keys |
32 | 35 | # |
@@ -70,6 +73,48 @@ def prefix |
70 | 73 | subject =~ /\(([^)]+)\)/ ? $1 : subject |
71 | 74 | end |
72 | 75 |
|
| 76 | + # Banner writes linked sections as <slot><key>. The slot says what the section |
| 77 | + # is for within the pairing, and the key says which pairing it belongs to. In |
| 78 | + # CHEM 1000 the lecture "A1" goes with the labs "B1", and the lecture "A2" |
| 79 | + # with the labs "B2". |
| 80 | + # The public id is derived from the numeric id, not stored, so a list of them |
| 81 | + # is built rather than plucked. |
| 82 | + def self.public_id_for(id) |
| 83 | + "#{get_public_id_prefix}#{EncodedIds.configuration.separator}#{encode_id(id)}" |
| 84 | + end |
| 85 | + |
| 86 | + # Turns "crs_kw7coe30" back into the numeric id. Returns nil when the prefix |
| 87 | + # or the hash does not belong to a course. |
| 88 | + def self.id_from_public_id(value) |
| 89 | + separator = EncodedIds.configuration.separator |
| 90 | + parts = value.to_s.strip.split(separator) |
| 91 | + hash = parts.pop |
| 92 | + return nil unless parts.join(separator) == get_public_id_prefix |
| 93 | + |
| 94 | + decode_id(hash) |
| 95 | + end |
| 96 | + |
| 97 | + def link_slot |
| 98 | + link_identifier&.first |
| 99 | + end |
| 100 | + |
| 101 | + def link_key |
| 102 | + link_identifier.presence && link_identifier[1..].presence |
| 103 | + end |
| 104 | + |
| 105 | + # Sections a student has to register alongside this one: same course, same |
| 106 | + # link key, a different slot. Returns none when the section is not linked. |
| 107 | + def linked_sections |
| 108 | + return Course.none if link_key.blank? |
| 109 | + |
| 110 | + Course.active |
| 111 | + .where(term_id: term_id, subject: subject, course_number: course_number) |
| 112 | + .where("SUBSTRING(link_identifier FROM 2) = ?", link_key) |
| 113 | + .where.not(id: id) |
| 114 | + .where.not(link_identifier: nil) |
| 115 | + .where("LEFT(link_identifier, 1) <> ?", link_slot) |
| 116 | + end |
| 117 | + |
73 | 118 | # Returns deduplicated meeting times, preferring non-TBD locations when there are duplicates. |
74 | 119 | def filtered_meeting_times |
75 | 120 | mts = meeting_times.loaded? ? meeting_times : meeting_times.includes(rooms: :building) |
|
0 commit comments