server: fix date parsing w/ TZ and cal widget highlight

This commit is contained in:
2025-09-11 16:31:43 -07:00
parent 2c1c7abf0a
commit 3889b855a5
2 changed files with 227 additions and 16 deletions

View File

@@ -1837,39 +1837,42 @@ pub fn render_ical_summary(ical_data: &str) -> Result<String, ServerError> {
}
}
// Always use America/Los_Angeles for Google Calendar events if no TZID is present
let event_tz: Tz = tzid
.as_deref()
.unwrap_or("America/Los_Angeles")
.parse()
.unwrap_or(chrono_tz::America::Los_Angeles);
// Parse start/end as chrono DateTime
let (local_fmt_start, local_fmt_end, event_days, recurrence_display) =
if let Some(dtstart) = dtstart {
let tz: Tz = tzid
.as_deref()
.unwrap_or("UTC")
.parse()
.unwrap_or(chrono_tz::UTC);
let fallback = chrono::DateTime::<chrono::Utc>::from_timestamp(0, 0)
.map(|dt| dt.with_timezone(&tz))
.map(|dt| dt.with_timezone(&event_tz))
.unwrap_or_else(|| {
tz.with_ymd_and_hms(1970, 1, 1, 0, 0, 0)
event_tz
.with_ymd_and_hms(1970, 1, 1, 0, 0, 0)
.single()
.unwrap_or_else(|| tz.timestamp_opt(0, 0).single().unwrap())
.unwrap_or_else(|| event_tz.timestamp_opt(0, 0).single().unwrap())
});
let start = parse_ical_datetime_tz(dtstart, tz).unwrap_or(fallback);
let start = parse_ical_datetime_tz(dtstart, event_tz).unwrap_or(fallback);
let end = dtend
.and_then(|d| parse_ical_datetime_tz(d, tz))
.and_then(|d| parse_ical_datetime_tz(d, event_tz))
.unwrap_or(start);
let local_start = start.with_timezone(&Local);
let local_end = end.with_timezone(&Local);
// Use the event's TZ for all calendar grid/highlighting logic
let allday =
dtstart.len() == 8 && (dtend.map(|s| s.len() == 8).unwrap_or(false));
let fmt_start = if allday {
local_start.format("%a %b %e, %Y").to_string()
start.format("%a %b %e, %Y").to_string()
} else {
local_start.format("%-I:%M %p %a %b %e, %Y").to_string()
start.format("%-I:%M %p %a %b %e, %Y").to_string()
};
let fmt_end = if allday {
local_end.format("%a %b %e, %Y").to_string()
end.format("%a %b %e, %Y").to_string()
} else {
local_end.format("%-I:%M %p %a %b %e, %Y").to_string()
end.format("%-I:%M %p %a %b %e, %Y").to_string()
};
// All calendar grid and event_days logic below uses start/end in event's TZ
// Recurrence support: parse RRULE and generate event_days accordingly
let mut days = vec![];
@@ -2144,6 +2147,39 @@ fn parse_ical_datetime_tz(dt: &str, tz: Tz) -> Option<chrono::DateTime<Tz>> {
#[cfg(test)]
mod tests {
#[test]
fn google_calendar_email_thursday_highlights_thursday() {
use mailparse::parse_mail;
let raw_email = include_str!("../../server/testdata/google-calendar-example-thursday.eml");
let parsed = parse_mail(raw_email.as_bytes()).expect("parse_mail");
let mut part_addr = vec![];
let body = extract_body(&parsed, &mut part_addr).expect("extract_body");
let meta = extract_calendar_metadata_from_mail(&parsed, &body);
// Assert detection as Google Calendar
assert!(meta.is_google_calendar_event);
// Debug: print the rendered HTML for inspection
let html = meta.body_html.expect("body_html");
println!("Rendered HTML: {}", html);
// Check that the calendar table highlights Thursday, not Friday
// Look for a table header row with days of week (allow whitespace)
let thursday_idx = html
.find(">\n Thu<")
.or_else(|| html.find(">Thu<"))
.expect("Should have a Thursday column");
let friday_idx = html
.find(">\n Fri<")
.or_else(|| html.find(">Fri<"))
.expect("Should have a Friday column");
// Find the first highlighted cell (background:#ffd700)
let highlight_idx = html
.find("background:#ffd700")
.expect("Should highlight a day");
// The highlight should be closer to Thursday than Friday
assert!(
highlight_idx > thursday_idx && highlight_idx < friday_idx,
"Thursday should be highlighted, not Friday"
);
}
use super::*;
#[test]
fn google_calendar_email_3_single_event_metadata() {