server: add another test and tweak fallback extraction logic

This commit is contained in:
Bill Thiede 2025-08-31 13:19:40 -07:00
parent 6ff9b2cd54
commit 4526d99de9

View File

@ -92,6 +92,18 @@ pub fn extract_calendar_metadata_from_mail(
// Try to extract start/end dates from subject
if start_date.is_none() || end_date.is_none() {
if let Some(subject) = m.headers.get_first_value("Subject") {
// Pattern: New event: Dentist appt @ Tue Sep 23, 2025 3pm - 4pm (PDT) (tconvertino@gmail.com)
if let Some(caps) = regex::Regex::new(r"New event: [^@]+@ ([A-Za-z]{3}) ([A-Za-z]{3}) (\d{1,2}), (\d{4}) (\d{1,2})(?::(\d{2}))? ?([ap]m) ?- ?(\d{1,2})(?::(\d{2}))? ?([ap]m)").ok().and_then(|re| re.captures(&subject)) {
let month = &caps[2];
let day = &caps[3];
let year = &caps[4];
let date_str = format!("{} {} {}", month, day, year);
if let Ok(date) = chrono::NaiveDate::parse_from_str(&date_str, "%b %d %Y") {
let ymd = date.format("%Y%m%d").to_string();
start_date = Some(ymd.clone());
end_date = Some(ymd);
}
} else {
// Pattern: from Thu Sep 11 to Fri Jan 30, 2026
if let Some(caps) = regex::Regex::new(r"from [A-Za-z]{3} ([A-Za-z]{3}) (\d{1,2}) to [A-Za-z]{3} ([A-Za-z]{3}) (\d{1,2}), (\d{4})").ok().and_then(|re| re.captures(&subject)) {
let start_month = &caps[1];
@ -147,6 +159,7 @@ pub fn extract_calendar_metadata_from_mail(
}
}
}
}
// Try to extract summary from body if still missing
if summary.is_none() {
if let Body::PlainText(t) = body {
@ -2093,6 +2106,32 @@ fn parse_ical_datetime_tz(dt: &str, tz: Tz) -> Option<chrono::DateTime<Tz>> {
#[cfg(test)]
mod tests {
#[test]
fn google_calendar_email_3_single_event_metadata() {
use mailparse::parse_mail;
let raw_email = include_str!("../../server/testdata/google-calendar-example-3.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);
// Assert metadata extraction
assert_eq!(meta.summary, Some("Dentist appt".to_string()));
// Organizer: from From header, extract email address
assert_eq!(meta.organizer, Some("tconvertino@gmail.com".to_string()));
// Dates: should extract Sep 23, 2025, 3pm-4pm
assert_eq!(meta.start_date, Some("20250923".to_string()));
assert_eq!(meta.end_date, Some("20250923".to_string()));
// Should not be recurring
if let Some(ref html) = meta.body_html {
assert!(html.contains("Dentist appt"), "HTML should contain the summary");
assert!(html.contains("20250923"), "HTML should contain the event date");
assert!(!html.contains("Repeats"), "HTML should not mention recurrence");
} else {
panic!("No body_html rendered");
}
}
#[test]
fn google_calendar_email_2_metadata_no_recurrence() {
use mailparse::parse_mail;