From 46021c5d2cc412a8e4106c40f4967935071bed83 Mon Sep 17 00:00:00 2001 From: Bill Thiede Date: Tue, 2 Sep 2025 19:27:14 -0700 Subject: [PATCH] server: remove dupe and move code to more idomatic layout --- server/src/email_extract.rs | 123 +++++++++++++++++------------------- 1 file changed, 57 insertions(+), 66 deletions(-) diff --git a/server/src/email_extract.rs b/server/src/email_extract.rs index 5a8a5c9..3fac81b 100644 --- a/server/src/email_extract.rs +++ b/server/src/email_extract.rs @@ -1,3 +1,60 @@ +use std::io::{Cursor, Read}; + +use askama::Template; +use chrono::{Datelike, Local, LocalResult, TimeZone, Utc}; +use chrono_tz::Tz; +use mailparse::{parse_content_type, parse_mail, MailHeader, MailHeaderMap, ParsedMail}; +use quick_xml::de::from_str as xml_from_str; +use tracing::{error, info, warn}; +use zip::ZipArchive; + +use crate::{ + error::ServerError, + graphql::{Attachment, Body, DispositionType, Email, Html, PlainText, UnhandledContentType}, + linkify_html, +}; + +const APPLICATION_GZIP: &'static str = "application/gzip"; + +const APPLICATION_ZIP: &'static str = "application/zip"; +const IMAGE_JPEG: &'static str = "image/jpeg"; +const IMAGE_PJPEG: &'static str = "image/pjpeg"; +const IMAGE_PNG: &'static str = "image/png"; +const MESSAGE_RFC822: &'static str = "message/rfc822"; +const MULTIPART_ALTERNATIVE: &'static str = "multipart/alternative"; +const MULTIPART_MIXED: &'static str = "multipart/mixed"; +const MULTIPART_RELATED: &'static str = "multipart/related"; +const MULTIPART_REPORT: &'static str = "multipart/report"; +const TEXT_CALENDAR: &'static str = "text/calendar"; +const TEXT_HTML: &'static str = "text/html"; +const TEXT_PLAIN: &'static str = "text/plain"; + +// Inline Askama filters module for template use +mod filters { + // Usage: {{ items|batch(7) }} + pub fn batch( + items: &[T], + _: &dyn ::askama::Values, + size: usize, + ) -> askama::Result>> { + if size == 0 { + return Ok(vec![]); + } + let mut out = Vec::new(); + let mut chunk = Vec::with_capacity(size); + for item in items { + chunk.push(item.clone()); + if chunk.len() == size { + out.push(chunk); + chunk = Vec::with_capacity(size); + } + } + if !chunk.is_empty() { + out.push(chunk); + } + Ok(out) + } +} #[derive(Debug, PartialEq)] pub struct ExtractedCalendarMetadata { pub is_google_calendar_event: bool, @@ -443,72 +500,6 @@ pub fn extract_calendar_metadata_from_mail( body_html, } } -#[derive(Debug, PartialEq)] -pub struct ExtractedCalendarMetadata { - pub is_google_calendar_event: bool, - pub summary: Option, - pub organizer: Option, - pub start_date: Option, - pub end_date: Option, - pub body_html: Option, -} -// Inline Askama filters module for template use -mod filters { - // Usage: {{ items|batch(7) }} - pub fn batch( - items: &[T], - _: &dyn ::askama::Values, - size: usize, - ) -> askama::Result>> { - if size == 0 { - return Ok(vec![]); - } - let mut out = Vec::new(); - let mut chunk = Vec::with_capacity(size); - for item in items { - chunk.push(item.clone()); - if chunk.len() == size { - out.push(chunk); - chunk = Vec::with_capacity(size); - } - } - if !chunk.is_empty() { - out.push(chunk); - } - Ok(out) - } -} -use std::io::{Cursor, Read}; - -use askama::Template; -use chrono::{Datelike, Local, LocalResult, TimeZone, Utc}; -use chrono_tz::Tz; -use mailparse::{parse_content_type, parse_mail, MailHeader, MailHeaderMap, ParsedMail}; -use quick_xml::de::from_str as xml_from_str; -use tracing::{error, info, warn}; -use zip::ZipArchive; - -use crate::{ - error::ServerError, - graphql::{Attachment, Body, DispositionType, Email, Html, PlainText, UnhandledContentType}, - linkify_html, -}; - -const APPLICATION_GZIP: &'static str = "application/gzip"; - -const APPLICATION_ZIP: &'static str = "application/zip"; -const IMAGE_JPEG: &'static str = "image/jpeg"; -const IMAGE_PJPEG: &'static str = "image/pjpeg"; -const IMAGE_PNG: &'static str = "image/png"; -const MESSAGE_RFC822: &'static str = "message/rfc822"; -const MULTIPART_ALTERNATIVE: &'static str = "multipart/alternative"; -const MULTIPART_MIXED: &'static str = "multipart/mixed"; -const MULTIPART_RELATED: &'static str = "multipart/related"; -const MULTIPART_REPORT: &'static str = "multipart/report"; -const TEXT_CALENDAR: &'static str = "text/calendar"; -const TEXT_HTML: &'static str = "text/html"; -const TEXT_PLAIN: &'static str = "text/plain"; - pub fn email_addresses( _path: &str, m: &ParsedMail,