diff --git a/.env.example b/.env.example index 9028c4d..133e6cb 100644 --- a/.env.example +++ b/.env.example @@ -96,14 +96,11 @@ # Enable drawing canvas in submission form. Drawings are stored as PNG files in DATA_DIR/drawings/. # BOOK_ENABLE_DRAWINGS=false +# Label for the drawing canvas. +# BOOK_LABEL_DRAWING=Draw (optional): + # Drawing canvas width in pixels. # BOOK_CANVAS_WIDTH=400 # Drawing canvas height in pixels. # BOOK_CANVAS_HEIGHT=200 - -# Enable voice note recording in submission form. Voice notes are stored as WebM files in DATA_DIR/voice_notes/. -# BOOK_ENABLE_VOICE_NOTES=false - -# Maximum voice note duration in seconds. Max file size is derived as duration * 10KB. -# BOOK_VOICE_NOTE_MAX_DURATION=20 diff --git a/Cargo.lock b/Cargo.lock index 9bcad99..83157cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -458,7 +458,7 @@ dependencies = [ [[package]] name = "guestbook" -version = "0.2.3" +version = "0.2.2" dependencies = [ "axum", "base64 0.22.1", diff --git a/Cargo.toml b/Cargo.toml index a6d96a5..bb6d3a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "guestbook" -version = "0.2.3" +version = "0.2.2" edition = "2021" -description = "A standalone guestbook to let visitors to your site leave behind written messages, drawings, and voice notes, with spam-prevention and moderation via Telegram bot." +description = "A configurable web guestbook made to be easy to use, with entries in plain text files, an optional drawing canvas, honeypots and captchas to deter spam, and moderation via Telegram bot." license = "MIT" repository = "https://git.ily.rs/lew/guestbook" diff --git a/README.md b/README.md index 0f3e54f..6dc28ea 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,14 @@ `guestbook` is a self-hosted guestbook web service with: - entries stored in plaintext, -- a [drawing canvas](#drawing) for visitors to sketch alongside their message, -- [voice notes](#voice-notes) for visitors to record a short audio clip, -- notifications and moderation via [Telegram](#telegram), +- optional [drawing canvas](#drawing) for visitors to sketch alongside their message, +- notifications and moderation via [Telegram](#telegram) (including drawing previews), - spam prevention via honeypot and/or [captcha](#captcha), -- fairly customisable [styling](#customisation), +- completely customisable [styling](#customisation), and more, written in Rust, and inspired by [t0.vc/g](https://t0.vc/g). -`guestbook` is a single binary that serves a single-page guestbook aimed at personal sites. There's a form for visitors to submit a name, message, and optionally a link to their own site. Visitors can also draw a picture or leave a voice note if those features are enabled. Entries are written to plain text files with TOML frontmatter, and are initially marked as pending. The frontmatter can be manually edited to mark entries as approved or denied, or a Telegram bot can be hooked up for notifications and moderation (drawings are sent as photos and voice notes as voice messages so you can review them before approving). Running the Telegram bot just requires handing over a bot token, and it'll run off the same binary. +`guestbook` is a single binary that serves a single-page guestbook aimed at personal sites. There's a form for visitors to submit a name, message, and optionally a link to their own site. Visitors can also draw a picture if the drawing feature is enabled. Entries are written to plain text files with TOML frontmatter, and are initially marked as pending. The frontmatter can be manually edited to mark entries as approved or denied, or a Telegram bot can be hooked up for notifications and moderation (drawings are sent as photos so you can see them before approving). Running the Telegram bot just requires handing over a bot token, and it'll run off the same binary. Everything is configured through environment variables (see [`.env.example`](#default-config) for the defaults). If you're hosting with Nix, there's a flake that can set up the `guestbook` service end-to-end, running on a systemd service with a Caddy reverse proxy. Optionally, just ignore the flake and set up all the extra stuff yourself. @@ -183,21 +182,6 @@ Running `guestbook` with no env vars will give you a working guestbook on `local # Supports {{title}} and {{style}} placeholders. Use "##, + label = config.label_drawing, w = config.canvas_width, h = config.canvas_height, ) @@ -109,70 +88,6 @@ pub fn render_form(config: &Config) -> String { String::new() }; - let voice_note_section = if config.enable_voice_notes { - format!( - r##"add a voice note "##, - max_dur = config.voice_note_max_duration, - ) - } else { - String::new() - }; - format!( r#"{prompt}
@@ -182,7 +97,8 @@ pub fn render_form(config: &Config) -> String { {captcha_section} -{drawing_section}{voice_note_section} +{drawing_section} +
"#, prompt = config.form_prompt, label_name = config.label_name, @@ -192,7 +108,6 @@ pub fn render_form(config: &Config) -> String { th = config.textarea_height, captcha_section = captcha_section, drawing_section = drawing_section, - voice_note_section = voice_note_section, button = config.button_text, ) } @@ -280,22 +195,14 @@ fn render_entry(entry: &Entry, config: &Config) -> String { }; let drawing_html = if !entry.meta.drawing.is_empty() { format!( - "", + "\n", escape_html(&entry.meta.drawing) ) } else { String::new() }; - let voice_note_html = if !entry.meta.voice_note.is_empty() { - format!( - "", - escape_html(&entry.meta.voice_note) - ) - } else { - String::new() - }; format!( - "\n{header}\n{drawing_html}{voice_note_html}\n{body}\n\n{}\n", + "\n{header}\n{drawing_html}\n{body}\n\n{}\n", config.separator ) } @@ -327,10 +234,9 @@ mod tests { captcha_exact: false, captcha_casesensitive: false, enable_drawings: false, + label_drawing: "Draw (optional):".into(), canvas_width: 400, canvas_height: 200, - enable_voice_notes: false, - voice_note_max_duration: 20, template: None, success_template: None, separator: "---".into(), @@ -353,7 +259,6 @@ mod tests { date: date.into(), website: String::new(), drawing: String::new(), - voice_note: String::new(), status: Status::Approved, }, body: body.into(), @@ -521,20 +426,21 @@ mod tests { } #[test] - fn test_render_form_shows_drawing_toggle_when_enabled() { + fn test_render_form_shows_canvas_when_drawings_enabled() { let mut config = test_config(); config.enable_drawings = true; let form = render_form(&config); - assert!(form.contains("add a drawing")); - assert!(form.contains("guestbook-drawing-toggle")); + assert!(form.contains("")); } - - #[test] - fn test_render_entry_with_voice_note() { - let config = test_config(); - let mut entry = make_entry("alice", "2026-04-10", "Hello!"); - entry.meta.voice_note = "1744300800_abcd1234.webm".into(); - let form = render_form(&config); - let html = render_page(DEFAULT_TEMPLATE, &config, &[entry], &form); - assert!(html.contains(r#"