crabmail

Static HTML email archive viewer in Rust
git clone git://git.alexwennerberg.com/crabmail
Log | Files | Refs | README | LICENSE

commit 2a04a1d730f4c0ef8dd1ce6f03d2dfc13fa01386
parent 1bccade8a1eea68a3bd2689abfe4a1ddcbdcdf27
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Tue, 14 Dec 2021 15:25:10 -0800

add reply count

Diffstat:
Msrc/filters.rs | 1-
Msrc/main.rs | 24+++++++++++++++++-------
Mtemplates/threadlist.html | 4++--
3 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/src/filters.rs b/src/filters.rs @@ -1,4 +1,3 @@ -use mailparse::{parse_mail, MailHeaderMap, ParsedMail}; use std::time::{SystemTime, UNIX_EPOCH}; pub fn time_ago(amount: &u64) -> askama::Result<String> { diff --git a/src/main.rs b/src/main.rs @@ -35,6 +35,13 @@ struct Email { date: u64, // unix epoch. received date body: String, mime: String, + replies: u64, + hash: String, +} + +struct MailThread<'a> { + root: &'a Email, + replies: Vec<&'a Email>, // sorted } impl Email { @@ -64,7 +71,6 @@ impl Email { #[cfg(feature = "html")] fn parse_html_body(email: &ParsedMail) -> String { - use ammonia; use std::collections::HashSet; use std::iter::FromIterator; // TODO dont initialize each time @@ -131,6 +137,8 @@ fn local_parse_email(data: &[u8]) -> Result<Email> { date, body, mime, + replies: 0, + hash: String::new(), }); } @@ -177,11 +185,11 @@ fn main() -> Result<()> { email_index.insert(email.id.clone(), email); } - let mut thread_roots: Vec<&Email> = email_index + let mut thread_roots: Vec<Email> = email_index .iter() .filter_map(|(_, v)| { if v.in_reply_to.is_none() { - return Some(v); + return Some(v.clone()); } return None; }) @@ -191,7 +199,7 @@ fn main() -> Result<()> { std::fs::create_dir(&out_dir).ok(); let thread_dir = &out_dir.join("threads"); std::fs::create_dir(thread_dir).ok(); - for root in thread_roots.iter() { + for root in &mut thread_roots { let mut thread_ids = vec![]; let mut current: Vec<String> = vec![root.id.clone()]; while current.len() > 0 { @@ -210,12 +218,14 @@ fn main() -> Result<()> { .collect(); messages.sort_by_key(|a| a.date); + root.replies = messages.len() as u64 - 1; + root.hash = root.hash(); let mut file = OpenOptions::new() .create(true) .write(true) .truncate(true) - .open(thread_dir.join(format!("{}.html", root.hash())))?; + .open(thread_dir.join(format!("{}.html", root.hash)))?; file.write(Thread { root, messages }.render()?.as_bytes()) .ok(); } @@ -254,7 +264,7 @@ struct Thread<'a> { #[derive(Template)] #[template(path = "threadlist.html")] -struct ThreadList<'a> { +struct ThreadList { // message root - messages: Vec<&'a Email>, + messages: Vec<Email>, } diff --git a/templates/threadlist.html b/templates/threadlist.html @@ -5,12 +5,12 @@ <hr class="thin"> {% for message in messages %} <div class="message-sum"> - <a href="threads/{{message.date}}.html" class="threadlink">{{message.subject}}</a> + <a href="threads/{{message.hash}}.html" class="threadlink">{{message.subject}}</a> <br> <a href="mailto:{{message.from.addr}}" class="addr">{%match message.from.display_name %} {% when Some with (name) %} {{name}}{% when none %}{{message.from.addr}}{% endmatch %}</a> -<span class="timeago">{{message.date | time_ago}}</span> + <span class="timeago">{{message.date | time_ago}} ยท {{message.replies}} replies</span> <br> </div> {% endfor %}