server: render calendar summary before any pre-existing text

This commit is contained in:
Bill Thiede 2025-08-19 11:17:11 -07:00
parent cc994df4e5
commit a8a5089ed3
3 changed files with 146 additions and 24 deletions

145
Cargo.lock generated
View File

@ -1364,7 +1364,7 @@ dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa 1.0.15",
"phf",
"phf 0.11.3",
"smallvec 1.15.1",
]
@ -1377,7 +1377,7 @@ dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa 1.0.15",
"phf",
"phf 0.11.3",
"smallvec 1.15.1",
]
@ -2053,7 +2053,7 @@ version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
dependencies = [
"unicode-width",
"unicode-width 0.2.1",
]
[[package]]
@ -2518,6 +2518,33 @@ dependencies = [
"utf8-width",
]
[[package]]
name = "html2text"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74cda84f06c1cc83476f79ae8e2e892b626bdadafcb227baec54c918cadc18a0"
dependencies = [
"html5ever 0.26.0",
"markup5ever 0.11.0",
"tendril",
"unicode-width 0.1.14",
"xml5ever",
]
[[package]]
name = "html5ever"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
dependencies = [
"log",
"mac",
"markup5ever 0.11.0",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "html5ever"
version = "0.29.1"
@ -3250,6 +3277,7 @@ dependencies = [
"futures 0.3.31",
"headers",
"html-escape",
"html2text",
"ical",
"icalendar",
"letterbox-notmuch 0.17.34",
@ -3554,6 +3582,20 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "markup5ever"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016"
dependencies = [
"log",
"phf 0.10.1",
"phf_codegen 0.10.0",
"string_cache",
"string_cache_codegen",
"tendril",
]
[[package]]
name = "markup5ever"
version = "0.14.1"
@ -3561,8 +3603,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18"
dependencies = [
"log",
"phf",
"phf_codegen",
"phf 0.11.3",
"phf_codegen 0.11.3",
"string_cache",
"string_cache_codegen",
"tendril",
@ -4353,6 +4395,15 @@ dependencies = [
"sha2 0.10.9",
]
[[package]]
name = "phf"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [
"phf_shared 0.10.0",
]
[[package]]
name = "phf"
version = "0.11.3"
@ -4360,7 +4411,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
dependencies = [
"phf_macros",
"phf_shared",
"phf_shared 0.11.3",
]
[[package]]
name = "phf_codegen"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
dependencies = [
"phf_generator 0.10.0",
"phf_shared 0.10.0",
]
[[package]]
@ -4369,8 +4430,18 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
dependencies = [
"phf_generator",
"phf_shared",
"phf_generator 0.11.3",
"phf_shared 0.11.3",
]
[[package]]
name = "phf_generator"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
dependencies = [
"phf_shared 0.10.0",
"rand 0.8.5",
]
[[package]]
@ -4379,7 +4450,7 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [
"phf_shared",
"phf_shared 0.11.3",
"rand 0.8.5",
]
@ -4389,20 +4460,29 @@ version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
dependencies = [
"phf_generator",
"phf_shared",
"phf_generator 0.11.3",
"phf_shared 0.11.3",
"proc-macro2",
"quote",
"syn 2.0.104",
]
[[package]]
name = "phf_shared"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
dependencies = [
"siphasher 0.3.11",
]
[[package]]
name = "phf_shared"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
dependencies = [
"siphasher",
"siphasher 1.0.1",
]
[[package]]
@ -5434,8 +5514,8 @@ dependencies = [
"fxhash",
"log",
"new_debug_unreachable",
"phf",
"phf_codegen",
"phf 0.11.3",
"phf_codegen 0.11.3",
"precomputed-hash",
"servo_arc",
"smallvec 1.15.1",
@ -5453,8 +5533,8 @@ dependencies = [
"fxhash",
"log",
"new_debug_unreachable",
"phf",
"phf_codegen",
"phf 0.11.3",
"phf_codegen 0.11.3",
"precomputed-hash",
"servo_arc",
"smallvec 1.15.1",
@ -5687,6 +5767,12 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "siphasher"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "siphasher"
version = "1.0.1"
@ -5995,7 +6081,7 @@ checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
dependencies = [
"new_debug_unreachable",
"parking_lot 0.12.4",
"phf_shared",
"phf_shared 0.11.3",
"precomputed-hash",
"serde",
]
@ -6006,8 +6092,8 @@ version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0"
dependencies = [
"phf_generator",
"phf_shared",
"phf_generator 0.11.3",
"phf_shared 0.11.3",
"proc-macro2",
"quote",
]
@ -7077,6 +7163,12 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "unicode-width"
version = "0.2.1"
@ -7381,8 +7473,8 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414"
dependencies = [
"phf",
"phf_codegen",
"phf 0.11.3",
"phf_codegen 0.11.3",
"string_cache",
"string_cache_codegen",
]
@ -7782,6 +7874,17 @@ version = "0.8.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7"
[[package]]
name = "xml5ever"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4034e1d05af98b51ad7214527730626f019682d797ba38b51689212118d8e650"
dependencies = [
"log",
"mac",
"markup5ever 0.11.0",
]
[[package]]
name = "xtracing"
version = "0.3.2"

View File

@ -12,6 +12,7 @@ version.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
html2text = "0.6"
ammonia = "4.1.0"
anyhow = "1.0.98"
askama = { version = "0.14.0", features = ["derive"] }

View File

@ -328,25 +328,43 @@ pub fn extract_alternative(
return extract_related(sp, part_addr);
}
}
let mut ical_summary: Option<String> = None;
for sp in &m.subparts {
if sp.ctype.mimetype.as_str() == TEXT_CALENDAR {
let body = sp.get_body()?;
let summary = render_ical_summary(&body)?;
return Ok(Body::html(summary));
ical_summary = Some(summary);
break;
}
}
for sp in &m.subparts {
if sp.ctype.mimetype.as_str() == TEXT_HTML {
let body = sp.get_body()?;
return Ok(Body::html(body));
if let Some(ref summary) = ical_summary {
// Prepend summary to HTML body
let combined = format!("{}<hr>{}", summary, body);
return Ok(Body::html(combined));
} else {
return Ok(Body::html(body));
}
}
}
for sp in &m.subparts {
if sp.ctype.mimetype.as_str() == TEXT_PLAIN {
let body = sp.get_body()?;
return Ok(Body::text(body));
if let Some(ref summary) = ical_summary {
// Prepend summary to plain text body (strip HTML tags)
let summary_text = html2text::from_read(summary.as_bytes(), 80);
let combined = format!("{}\n\n{}", summary_text.trim(), body);
return Ok(Body::text(combined));
} else {
return Ok(Body::text(body));
}
}
}
if let Some(summary) = ical_summary {
return Ok(Body::html(summary));
}
Err(ServerError::StringError(format!(
"extract_alternative failed to find suitable subpart, searched: {:?}",
handled_types