mirror of
https://github.com/Xevion/banner.git
synced 2026-01-31 04:23:34 -06:00
refactor: consolidate types, remove dead code, and fix minor bugs
Replace DayOfWeek with chrono::Weekday via extension traits, unify RateLimitConfig into the config module, and remove the unused time command, BannerState, and ClassDetails stub. Fix open_only query parameter to respect false values and correct 12-hour time display.
This commit is contained in:
+16
-21
@@ -1,8 +1,8 @@
|
||||
//! Google Calendar command implementation.
|
||||
|
||||
use crate::banner::{Course, DayOfWeek, MeetingScheduleInfo};
|
||||
use crate::banner::{Course, MeetingScheduleInfo};
|
||||
use crate::bot::{Context, Error, utils};
|
||||
use chrono::NaiveDate;
|
||||
use chrono::{NaiveDate, Weekday};
|
||||
use std::collections::HashMap;
|
||||
use tracing::info;
|
||||
use url::Url;
|
||||
@@ -39,25 +39,18 @@ pub async fn gcal(
|
||||
1.. => {
|
||||
// Sort meeting times by start time of their TimeRange
|
||||
let mut sorted_meeting_times = meeting_times.to_vec();
|
||||
sorted_meeting_times.sort_unstable_by(|a, b| {
|
||||
// Primary sort: by start time
|
||||
match (&a.time_range, &b.time_range) {
|
||||
(Some(a_time), Some(b_time)) => a_time.start.cmp(&b_time.start),
|
||||
(Some(_), None) => std::cmp::Ordering::Less,
|
||||
(None, Some(_)) => std::cmp::Ordering::Greater,
|
||||
(None, None) => a.days.bits().cmp(&b.days.bits()),
|
||||
}
|
||||
});
|
||||
MeetingScheduleInfo::sort_by_start_time(&mut sorted_meeting_times);
|
||||
|
||||
let links = sorted_meeting_times
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let link = generate_gcal_url(&course, m)?;
|
||||
let days = m.days_string().unwrap_or_else(|| "TBA".to_string());
|
||||
let detail = match &m.time_range {
|
||||
Some(range) => {
|
||||
format!("{} {}", m.days_string().unwrap(), range.format_12hr())
|
||||
format!("{days} {}", range.format_12hr())
|
||||
}
|
||||
None => m.days_string().unwrap(),
|
||||
None => days,
|
||||
};
|
||||
Ok(LinkDetail { link, detail })
|
||||
})
|
||||
@@ -105,7 +98,9 @@ fn generate_gcal_url(
|
||||
"CRN: {}\nInstructor: {}\nDays: {}",
|
||||
course.course_reference_number,
|
||||
instructor_name,
|
||||
meeting_time.days_string().unwrap()
|
||||
meeting_time
|
||||
.days_string()
|
||||
.unwrap_or_else(|| "TBA".to_string())
|
||||
);
|
||||
|
||||
// The event location
|
||||
@@ -133,13 +128,13 @@ fn generate_rrule(meeting_time: &MeetingScheduleInfo, end_date: NaiveDate) -> St
|
||||
let by_day = days_of_week
|
||||
.iter()
|
||||
.map(|day| match day {
|
||||
DayOfWeek::Monday => "MO",
|
||||
DayOfWeek::Tuesday => "TU",
|
||||
DayOfWeek::Wednesday => "WE",
|
||||
DayOfWeek::Thursday => "TH",
|
||||
DayOfWeek::Friday => "FR",
|
||||
DayOfWeek::Saturday => "SA",
|
||||
DayOfWeek::Sunday => "SU",
|
||||
Weekday::Mon => "MO",
|
||||
Weekday::Tue => "TU",
|
||||
Weekday::Wed => "WE",
|
||||
Weekday::Thu => "TH",
|
||||
Weekday::Fri => "FR",
|
||||
Weekday::Sat => "SA",
|
||||
Weekday::Sun => "SU",
|
||||
})
|
||||
.collect::<Vec<&str>>()
|
||||
.join(",");
|
||||
|
||||
+12
-26
@@ -1,6 +1,6 @@
|
||||
//! ICS command implementation for generating calendar files.
|
||||
|
||||
use crate::banner::{Course, MeetingScheduleInfo};
|
||||
use crate::banner::{Course, MeetingDays, MeetingScheduleInfo, WeekdayExt};
|
||||
use crate::bot::{Context, Error, utils};
|
||||
use chrono::{Datelike, NaiveDate, Utc};
|
||||
use serenity::all::CreateAttachment;
|
||||
@@ -61,7 +61,14 @@ impl Holiday {
|
||||
}
|
||||
}
|
||||
|
||||
/// University holidays that should be excluded from class schedules
|
||||
/// University holidays excluded from class schedules.
|
||||
///
|
||||
/// WARNING: These dates are specific to the UTSA 2024-2025 academic calendar and must be
|
||||
/// updated each academic year. Many of these holidays fall on different dates annually
|
||||
/// (e.g., Labor Day is the first Monday of September, Thanksgiving is the fourth Thursday
|
||||
/// of November). Ideally these would be loaded from a configuration file or computed
|
||||
/// dynamically from federal/university calendar rules.
|
||||
// TODO: Load holiday dates from configuration or compute dynamically per academic year.
|
||||
const UNIVERSITY_HOLIDAYS: &[(&str, Holiday)] = &[
|
||||
("Labor Day", Holiday::Single { month: 9, day: 1 }),
|
||||
(
|
||||
@@ -132,12 +139,7 @@ pub async fn ics(
|
||||
|
||||
// Sort meeting times by start time
|
||||
let mut sorted_meeting_times = meeting_times.to_vec();
|
||||
sorted_meeting_times.sort_unstable_by(|a, b| match (&a.time_range, &b.time_range) {
|
||||
(Some(a_time), Some(b_time)) => a_time.start.cmp(&b_time.start),
|
||||
(Some(_), None) => std::cmp::Ordering::Less,
|
||||
(None, Some(_)) => std::cmp::Ordering::Greater,
|
||||
(None, None) => a.days.bits().cmp(&b.days.bits()),
|
||||
});
|
||||
MeetingScheduleInfo::sort_by_start_time(&mut sorted_meeting_times);
|
||||
|
||||
// Generate ICS content
|
||||
let (ics_content, excluded_holidays) =
|
||||
@@ -352,26 +354,10 @@ fn generate_event_content(
|
||||
Ok((event_content, Vec::new()))
|
||||
}
|
||||
|
||||
/// Convert chrono::Weekday to the custom DayOfWeek enum
|
||||
fn chrono_weekday_to_day_of_week(weekday: chrono::Weekday) -> crate::banner::meetings::DayOfWeek {
|
||||
use crate::banner::meetings::DayOfWeek;
|
||||
match weekday {
|
||||
chrono::Weekday::Mon => DayOfWeek::Monday,
|
||||
chrono::Weekday::Tue => DayOfWeek::Tuesday,
|
||||
chrono::Weekday::Wed => DayOfWeek::Wednesday,
|
||||
chrono::Weekday::Thu => DayOfWeek::Thursday,
|
||||
chrono::Weekday::Fri => DayOfWeek::Friday,
|
||||
chrono::Weekday::Sat => DayOfWeek::Saturday,
|
||||
chrono::Weekday::Sun => DayOfWeek::Sunday,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a class meets on a specific date based on its meeting days
|
||||
fn class_meets_on_date(meeting_time: &MeetingScheduleInfo, date: NaiveDate) -> bool {
|
||||
let weekday = chrono_weekday_to_day_of_week(date.weekday());
|
||||
let meeting_days = meeting_time.days_of_week();
|
||||
|
||||
meeting_days.contains(&weekday)
|
||||
let day: MeetingDays = date.weekday().into();
|
||||
meeting_time.days.contains(day)
|
||||
}
|
||||
|
||||
/// Get holiday dates that fall within the course date range and would conflict with class meetings
|
||||
|
||||
@@ -4,10 +4,8 @@ pub mod gcal;
|
||||
pub mod ics;
|
||||
pub mod search;
|
||||
pub mod terms;
|
||||
pub mod time;
|
||||
|
||||
pub use gcal::gcal;
|
||||
pub use ics::ics;
|
||||
pub use search::search;
|
||||
pub use terms::terms;
|
||||
pub use time::time;
|
||||
|
||||
@@ -4,8 +4,12 @@ use crate::banner::{SearchQuery, Term};
|
||||
use crate::bot::{Context, Error};
|
||||
use anyhow::anyhow;
|
||||
use regex::Regex;
|
||||
use std::sync::LazyLock;
|
||||
use tracing::info;
|
||||
|
||||
static RANGE_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(\d{1,4})-(\d{1,4})?").unwrap());
|
||||
static WILDCARD_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(\d+)(x+)").unwrap());
|
||||
|
||||
/// Search for courses with various filters
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
pub async fn search(
|
||||
@@ -82,8 +86,7 @@ fn parse_course_code(input: &str) -> Result<(i32, i32), Error> {
|
||||
|
||||
// Handle range format (e.g, "3000-3999")
|
||||
if input.contains('-') {
|
||||
let re = Regex::new(r"(\d{1,4})-(\d{1,4})?").unwrap();
|
||||
if let Some(captures) = re.captures(input) {
|
||||
if let Some(captures) = RANGE_RE.captures(input) {
|
||||
let low: i32 = captures[1].parse()?;
|
||||
let high = if captures.get(2).is_some() {
|
||||
captures[2].parse()?
|
||||
@@ -110,8 +113,7 @@ fn parse_course_code(input: &str) -> Result<(i32, i32), Error> {
|
||||
return Err(anyhow!("Wildcard format must be exactly 4 characters"));
|
||||
}
|
||||
|
||||
let re = Regex::new(r"(\d+)(x+)").unwrap();
|
||||
if let Some(captures) = re.captures(input) {
|
||||
if let Some(captures) = WILDCARD_RE.captures(input) {
|
||||
let prefix: i32 = captures[1].parse()?;
|
||||
let x_count = captures[2].len();
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
//! Time command implementation for course meeting times.
|
||||
|
||||
use crate::bot::{Context, Error, utils};
|
||||
use tracing::info;
|
||||
|
||||
/// Get meeting times for a specific course
|
||||
#[poise::command(slash_command, prefix_command)]
|
||||
pub async fn time(
|
||||
ctx: Context<'_>,
|
||||
#[description = "Course Reference Number (CRN)"] crn: i32,
|
||||
) -> Result<(), Error> {
|
||||
ctx.defer().await?;
|
||||
|
||||
let course = utils::get_course_by_crn(&ctx, crn).await?;
|
||||
|
||||
// TODO: Implement actual meeting time retrieval and display
|
||||
ctx.say(format!(
|
||||
"Meeting time display for '{}' is not yet implemented.",
|
||||
course.display_title()
|
||||
))
|
||||
.await?;
|
||||
|
||||
info!(crn = %crn, "time command completed");
|
||||
Ok(())
|
||||
}
|
||||
@@ -14,7 +14,6 @@ pub fn get_commands() -> Vec<poise::Command<Data, Error>> {
|
||||
vec![
|
||||
commands::search(),
|
||||
commands::terms(),
|
||||
commands::time(),
|
||||
commands::ics(),
|
||||
commands::gcal(),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user