diff --git a/server/src/email_extract.rs b/server/src/email_extract.rs
index 6afd0b6..1fce386 100644
--- a/server/src/email_extract.rs
+++ b/server/src/email_extract.rs
@@ -189,10 +189,6 @@ pub fn extract_calendar_metadata_from_mail(
}
}
// Fallback: if body_html is still None, generate a minimal calendar HTML using all available metadata
- let summary_val = summary.clone().unwrap_or_default();
- let organizer_val = organizer.clone().unwrap_or_default();
- let start_val = start_date.clone().unwrap_or_default();
- let end_val = end_date.clone().unwrap_or_default();
// Improved recurrence detection: check for common recurrence phrases in subject, HTML, and plain text body
let mut has_recurrence = false;
let recurrence_phrases = [
@@ -220,31 +216,54 @@ pub fn extract_calendar_metadata_from_mail(
}
}
}
- let recurrence_html: &str = if has_recurrence { "
Repeats
" } else { "" };
- let minimal_html = format!(
- r#""#,
- html_escape::encode_text(&summary_val),
- html_escape::encode_text(&organizer_val),
- html_escape::encode_text(&start_val),
- html_escape::encode_text(&end_val),
- recurrence_html
- );
let needs_ical_flex = summary.is_some() || start_date.is_some() || end_date.is_some() || has_recurrence;
if needs_ical_flex {
+ let summary_val = summary.clone().unwrap_or_default();
+ let organizer_val = organizer.clone().unwrap_or_default();
+ let start_val = start_date.clone().unwrap_or_default();
+ let end_val = end_date.clone().unwrap_or_default();
+ let recurrence_display = if has_recurrence { "Repeats".to_string() } else { String::new() };
+ let template = IcalSummaryTemplate {
+ summary: &summary_val,
+ local_fmt_start: &start_val,
+ local_fmt_end: &end_val,
+ organizer: &organizer_val,
+ organizer_cn: "",
+ all_days: vec![],
+ event_days: vec![],
+ caption: String::new(),
+ description_paragraphs: &[],
+ today: Some(chrono::Local::now().date_naive()),
+ recurrence_display,
+ };
+ let fallback_html = template.render().unwrap_or_else(|_| String::from(""));
match &mut body_html {
Some(existing) => {
- if !existing.starts_with(&minimal_html) {
- *existing = format!("{}{}", minimal_html, existing);
+ if !existing.starts_with(&fallback_html) {
+ *existing = format!("{}{}", fallback_html, existing);
}
},
None => {
- body_html = Some(minimal_html);
+ body_html = Some(fallback_html);
}
}
}
- // Final guarantee: if body_html is still None, set to minimal ical-flex HTML with empty fields
+ // Final guarantee: if body_html is still None, set to minimal ical-flex HTML with empty fields using the template
if body_html.is_none() {
- body_html = Some("".to_string());
+ let template = IcalSummaryTemplate {
+ summary: "",
+ local_fmt_start: "",
+ local_fmt_end: "",
+ organizer: "",
+ organizer_cn: "",
+ all_days: vec![],
+ event_days: vec![],
+ caption: String::new(),
+ description_paragraphs: &[],
+ today: Some(chrono::Local::now().date_naive()),
+ recurrence_display: String::new(),
+ };
+ body_html = Some(template.render().unwrap_or_else(|_| String::from("")));
}
// Improved fallback: extract summary, start_date, end_date, and recurrence from subject/body if not found
@@ -314,11 +333,7 @@ pub fn extract_calendar_metadata_from_mail(
}
}
// Try to detect recurrence from subject
- if recurrence_html.is_empty() {
- if subject.to_lowercase().contains("recurr") || subject.to_lowercase().contains("repeat") {
- // recurrence_html assignment removed; handled at HTML generation
- }
- }
+ // recurrence detection and rendering is now handled by the template logic
}
// Try to extract summary from body if still missing
if summary.is_none() {
@@ -2154,19 +2169,20 @@ mod tests {
// Calendar widget should be rendered
let html = meta.body_html.expect("body_html");
println!("Rendered HTML for verification:\n{}", html);
- // Check that the HTML contains the summary, organizer, start, and end times
- assert!(html.contains(">McClure BLT<"), "HTML should contain the summary/title");
- assert!(html.contains(">calendar-notification@google.com<"), "HTML should contain the organizer");
- assert!(html.contains(">20250911 to 20260131<"), "HTML should contain the start and end times");
+ // Check that the HTML contains the summary, organizer, start, and end times with labels
+ assert!(html.contains("Summary: McClure BLT"), "HTML should contain the labeled summary/title");
+ assert!(html.contains("Organizer: calendar-notification@google.com"), "HTML should contain the labeled organizer");
+ assert!(html.contains("Start: 20250911"), "HTML should contain the labeled start time");
+ assert!(html.contains("End: 20260131"), "HTML should contain the labeled end time");
if !html.contains("ical-flex") {
println!("FAIL: html did not contain 'ical-flex':\n{}", html);
}
assert!(html.contains("ical-flex"), "Calendar widget should be rendered");
// Recurrence info should be present
- if !(html.contains("Repeats") || html.contains("recurr") || html.contains("RRULE")) {
+ if !(html.contains("Repeats: Repeats") || html.contains("recurr") || html.contains("RRULE")) {
println!("FAIL: html did not contain recurrence info:\n{}", html);
}
- assert!(html.contains("Repeats") || html.contains("recurr") || html.contains("RRULE"), "Recurrence info should be present in HTML");
+ assert!(html.contains("Repeats: Repeats") || html.contains("recurr") || html.contains("RRULE"), "Recurrence info should be present in HTML");
}
use super::*;
#[test]