commit dc47475c4de3c82970a8f915f1889c065a9c00e4
parent b47633660a6c8f2682062b2b9e97894410cebec7
Author: alex wennerberg <alex@alexwennerberg.com>
Date: Thu, 17 Mar 2022 21:32:22 -0700
added some html stufz
Diffstat:
4 files changed, 72 insertions(+), 26 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "anyhow"
-version = "1.0.52"
+version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
+checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
[[package]]
name = "cfg-if"
@@ -47,9 +47,9 @@ dependencies = [
[[package]]
name = "mail-parser"
-version = "0.4.4"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f31ffdaf350a570dac60afd70433dca8b2a4027f98064a8fca68549a54d2326"
+checksum = "545e2643e5f923cdea238bb826277e68967797f7d50523932d10a87dfcc940ac"
dependencies = [
"encoding_rs",
"serde",
@@ -75,9 +75,9 @@ checksum = "fcde141f0a9acabd38860369eeb0d69f1756d19c5948672c211e82e0519edd61"
[[package]]
name = "once_cell"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
+checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "proc-macro2"
@@ -119,9 +119,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.86"
+version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
+checksum = "ebd69e719f31e88618baa1eaa6ee2de5c9a1c004f1e9ecdb58e8352a13f20a01"
dependencies = [
"proc-macro2",
"quote",
diff --git a/src/main.rs b/src/main.rs
@@ -26,7 +26,7 @@ const PAGE_SIZE: i32 = 100;
// TODO
impl Lists {
- fn write_lists(&self) {
+ fn write_lists(&mut self) {
std::fs::create_dir_all(&self.out_dir);
let css = include_bytes!("style.css");
write_if_unchanged(&self.out_dir.join("style.css"), css);
@@ -35,8 +35,10 @@ impl Lists {
if Config::global().include_gemini {
write_if_unchanged(&base_path.with_extension("gmi"), self.to_gmi().as_bytes());
}
- for list in &self.lists {
- list.persist()
+ for list in &mut self.lists {
+ list.persist();
+ // todo somewhat awkward
+ write_if_unchanged(&list.out_dir.join("style.css"), css);
}
}
}
@@ -63,7 +65,7 @@ enum Format {
}
impl List {
- fn persist(&self) {
+ fn persist(&mut self) {
// let written = hashset
self.write_index();
self.write_threads();
@@ -95,11 +97,10 @@ impl List {
// write_if_unchanged(&self.out_dir.join("atom.xml"), self.to_xml().as_bytes());
}
- fn write_threads(&self) {
+ fn write_threads(&mut self) {
// files written = HashSet
let thread_dir = self.out_dir.join("threads");
std::fs::create_dir_all(&thread_dir).unwrap();
- self.write_index();
for thread_ids in &self.thread_idx.threads {
// Load thread
let thread = Thread::new(thread_ids);
@@ -112,9 +113,12 @@ impl List {
if Config::global().include_gemini {
write_if_unchanged(&basepath.with_extension("gmi"), thread.to_gmi().as_bytes());
}
+ // this is a bit awkward
+ self.thread_topics.push(thread.messages[0].clone());
// for file in thread
// write raw file
}
+ self.write_index();
}
}
diff --git a/src/models.rs b/src/models.rs
@@ -13,6 +13,8 @@ use std::path::PathBuf;
// raw_email = "/{list_name}/messages/{message_id}.eml
// paginate index somehow (TBD)
+// TODO a better way to handle these is to use lifetimes rather than ownership
+// I should implement an iterator that writes each message without holding them in memory probably
pub struct Lists {
pub lists: Vec<List>,
pub out_dir: PathBuf,
@@ -28,13 +30,14 @@ impl Lists {
self.lists.push(List {
thread_idx,
config,
+ thread_topics: vec![],
out_dir: self.out_dir.join(name),
})
}
}
pub struct List {
pub thread_idx: ThreadIdx,
- // Thread topics
+ pub thread_topics: Vec<StrMessage>,
pub config: Subsection, // path
pub out_dir: PathBuf,
}
@@ -49,6 +52,7 @@ impl List {
Self {
thread_idx: ThreadIdx::default(),
config: sub,
+ thread_topics: vec![],
out_dir: Config::global().out_dir.join(name),
}
}
@@ -72,9 +76,11 @@ impl Thread {
// simplified, stringified-email for templating
// making everything owned because I'm l a z y
+#[derive(Debug, Clone)]
pub struct StrMessage {
pub id: String,
pub subject: String,
+ pub preview: String,
pub from: MailAddress,
pub date: String, // TODO better dates
pub body: String,
@@ -97,6 +103,7 @@ impl StrMessage {
}
// i suck at Cow and strings
+#[derive(Debug, Clone)]
pub struct MailAddress {
pub name: Option<String>,
pub address: String,
@@ -118,6 +125,10 @@ impl StrMessage {
let id = msg.get_message_id().unwrap_or("");
let subject = msg.get_subject().unwrap_or("(No Subject)");
let invalid_email = Addr::new(None, "invalid-email");
+ let preview = match msg.get_body_preview(100) {
+ Some(b) => b.to_string(),
+ None => String::new(),
+ };
let from = match msg.get_from() {
HeaderValue::Address(fr) => fr,
_ => &invalid_email,
@@ -143,6 +154,7 @@ impl StrMessage {
.map(|x| x.c_type.to_string())
.unwrap_or(String::new()),
from: from,
+ preview,
to: vec![],
cc: vec![],
date: date.to_owned(),
@@ -151,3 +163,9 @@ impl StrMessage {
}
}
}
+
+// Export the email, not as it originally is, but a "clean" version of it
+// Maybe based off of https://git.causal.agency/bubger/tree/export.c
+fn raw_export(msg: &Message) -> String {
+ String::new()
+}
diff --git a/src/templates/html.rs b/src/templates/html.rs
@@ -10,10 +10,11 @@ const header: &str = r#"<!DOCTYPE html>
<head>
<title>{title}</title>
<meta http-equiv='Permissions-Policy' content='interest-cohort=()'/>
-<link rel='stylesheet' type='text/css' href='../../style.css' />
+<link rel='stylesheet' type='text/css' href='../style.css' />
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=0' />
<link rel='icon' href='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📧</text></svg>'></head>
<meta name="description" content="{title}"/>
+</head>
<body>
"#;
@@ -26,12 +27,11 @@ Archive generated with <a href='https://crabmail.flounder.online/'>crabmail</a>
impl Lists {
pub fn to_html(&self) -> String {
+ let body = r#"<h1 class="page-title">{title}</h1>
+ <a href="atom.xml"><img alt="Atom Feed" src='{rss_svg}' /></a>"#;
template(
- r#"
- <h1>Mail Archives</h1>
- <hr>
- "#,
- &[("title", "tbd")],
+ &format!("{}{}{}", header, body, footer),
+ &[("rss_svg", RSS_SVG), ("title", "tbd")],
)
.unwrap()
}
@@ -40,25 +40,49 @@ impl Lists {
impl List {
pub fn to_html(&self) -> Vec<String> {
// TODO paginate
- let threads = String::new();
+ let mut threads = String::new();
+ for thread in &self.thread_topics {
+ threads.push_str(
+ &template(
+ r#"
+ <div class='message-sum'>
+ <a class="bigger" href="threads/{path_id}.html">{subject}</a>
+ <br>
+ {preview}<br>
+ joe@schmoe.com | n replies | last-reply-date
+ "#,
+ &[
+ ("path_id", &x(thread.pathescape_msg_id().to_str().unwrap())),
+ ("subject", &thread.subject),
+ ("date", &thread.date),
+ ("preview", &thread.preview),
+ ],
+ )
+ .unwrap(),
+ );
+ }
// TODO use summary??
let page = template(
r#"
{header}
<h1 class="page-title">
{title}
- </h1>
<a href="atom.xml">
- <img alt="Atom feed" src={rss_svg} />
- {threads}
+ <img alt="Atom feed" src='{rss_svg}' />
</a>
</h1>
+ {description}<br>
+ <a href="{mailto:list_email}">{list_email}</a>
+ <hr>
+ {threads}
{footer}
"#,
&[
("header", header),
+ ("description", &self.config.description),
("title", self.config.title.as_str()),
("threads", &threads),
+ ("list_email", &self.config.email),
("rss_svg", RSS_SVG),
("footer", footer),
],
@@ -157,7 +181,7 @@ impl Thread {
.unwrap(),
);
}
- out.push_str("</div><hr>");
+ out.push_str("</div><hr></body></html>");
// body
out
}