cargo: gate telegram behind a default feature
This commit is contained in:
parent
de53e51c60
commit
9f0e3aae6d
6 changed files with 45 additions and 15 deletions
|
|
@ -6,10 +6,14 @@ description = "A configurable, self-hosted guestbook for the web, allowing visit
|
|||
license = "MIT"
|
||||
repository = "https://git.ily.rs/lew/guestbook"
|
||||
|
||||
[features]
|
||||
default = ["telegram"]
|
||||
telegram = ["dep:teloxide"]
|
||||
|
||||
[dependencies]
|
||||
axum = "0.8"
|
||||
tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync", "net"] }
|
||||
teloxide = { version = "0.13", features = ["macros"] }
|
||||
teloxide = { version = "0.13", features = ["macros"], optional = true }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
toml = "0.8"
|
||||
dotenvy = "0.15"
|
||||
|
|
@ -19,6 +23,9 @@ base64 = "0.22"
|
|||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 1
|
||||
|
||||
[dev-dependencies]
|
||||
tower = { version = "0.5", features = ["util"] }
|
||||
http-body-util = "0.1"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ pub struct Config {
|
|||
pub data_dir: PathBuf,
|
||||
pub site_title: String,
|
||||
|
||||
#[cfg(feature = "telegram")]
|
||||
pub telegram_bot_token: Option<String>,
|
||||
#[cfg(feature = "telegram")]
|
||||
pub telegram_chat_id: Option<i64>,
|
||||
pub enable_honeypot: bool,
|
||||
pub max_name_length: usize,
|
||||
|
|
@ -67,7 +69,9 @@ impl Config {
|
|||
.unwrap_or_else(|_| PathBuf::from("./data")),
|
||||
site_title: env::var("BOOK_SITE_TITLE").unwrap_or_else(|_| "guestbook".into()),
|
||||
|
||||
#[cfg(feature = "telegram")]
|
||||
telegram_bot_token: env::var("BOOK_TELEGRAM_BOT_TOKEN").ok(),
|
||||
#[cfg(feature = "telegram")]
|
||||
telegram_chat_id: env::var("BOOK_TELEGRAM_CHAT_ID")
|
||||
.ok()
|
||||
.map(|v| v.parse().map_err(|_| "BOOK_TELEGRAM_CHAT_ID must be an integer"))
|
||||
|
|
@ -188,7 +192,9 @@ mod tests {
|
|||
assert_eq!(config.listen_addr(), "127.0.0.1:9999");
|
||||
assert_eq!(config.data_dir, PathBuf::from("/tmp/gb"));
|
||||
assert_eq!(config.site_title, "test.rs");
|
||||
#[cfg(feature = "telegram")]
|
||||
assert_eq!(config.telegram_bot_token.as_deref(), Some("123:ABC"));
|
||||
#[cfg(feature = "telegram")]
|
||||
assert_eq!(config.telegram_chat_id, Some(12345));
|
||||
|
||||
// Clean up
|
||||
|
|
@ -221,7 +227,9 @@ mod tests {
|
|||
env::remove_var("BOOK_TELEGRAM_CHAT_ID");
|
||||
|
||||
let config = Config::from_env().unwrap();
|
||||
#[cfg(feature = "telegram")]
|
||||
assert!(config.telegram_bot_token.is_none());
|
||||
#[cfg(feature = "telegram")]
|
||||
assert!(config.telegram_chat_id.is_none());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ pub struct EntryMeta {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Entry {
|
||||
#[cfg_attr(not(feature = "telegram"), allow(dead_code))]
|
||||
pub id: String,
|
||||
pub meta: EntryMeta,
|
||||
pub body: String,
|
||||
|
|
@ -49,6 +50,7 @@ impl Entry {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "telegram", test))]
|
||||
/// Return the short ID (UUID portion after the underscore).
|
||||
pub fn short_id(&self) -> &str {
|
||||
self.id.split('_').last().unwrap_or(&self.id)
|
||||
|
|
@ -103,6 +105,7 @@ pub fn read_approved(dir: &Path) -> Vec<Entry> {
|
|||
read_by_status(dir, Status::Approved)
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "telegram", test))]
|
||||
/// Find a single entry by short ID (the UUID portion after the underscore).
|
||||
pub fn find_entry(dir: &Path, short_id: &str) -> Result<Entry, String> {
|
||||
let read_dir = std::fs::read_dir(dir).map_err(|e| e.to_string())?;
|
||||
|
|
@ -119,6 +122,7 @@ pub fn find_entry(dir: &Path, short_id: &str) -> Result<Entry, String> {
|
|||
Err("Not found.".into())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "telegram", test))]
|
||||
/// Delete an entry and its associated media files.
|
||||
/// `data_dir` is the parent directory containing entries/, drawings/, and voice_notes/.
|
||||
pub fn delete_entry(data_dir: &Path, short_id: &str) -> Result<String, String> {
|
||||
|
|
@ -148,6 +152,7 @@ pub fn delete_entry(data_dir: &Path, short_id: &str) -> Result<String, String> {
|
|||
Ok(entry.meta.name.clone())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "telegram", test))]
|
||||
/// Find an entry file by short ID prefix and update its status.
|
||||
pub fn set_status(dir: &Path, short_id: &str, status: Status) -> Result<String, String> {
|
||||
let mut entry = find_entry(dir, short_id)?;
|
||||
|
|
|
|||
34
src/main.rs
34
src/main.rs
|
|
@ -1,11 +1,11 @@
|
|||
mod config;
|
||||
mod entries;
|
||||
mod render;
|
||||
#[cfg(feature = "telegram")]
|
||||
mod telegram;
|
||||
mod web;
|
||||
|
||||
use std::sync::Arc;
|
||||
use teloxide::prelude::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
|
@ -18,25 +18,31 @@ async fn main() {
|
|||
|
||||
std::fs::create_dir_all(&entries_dir).expect("failed to create entries directory");
|
||||
|
||||
let (tx, rx) = tokio::sync::mpsc::channel::<(entries::Entry, Option<Vec<u8>>, Option<Vec<u8>>)>(32);
|
||||
let (tx, _rx) = tokio::sync::mpsc::channel::<(entries::Entry, Option<Vec<u8>>, Option<Vec<u8>>)>(32);
|
||||
|
||||
// Spawn telegram tasks if configured
|
||||
match (&config.telegram_bot_token, config.telegram_chat_id) {
|
||||
(Some(token), Some(chat_id)) => {
|
||||
let chat_id = ChatId(chat_id);
|
||||
let bot = Bot::new(token);
|
||||
#[cfg(feature = "telegram")]
|
||||
{
|
||||
use teloxide::prelude::*;
|
||||
match (&config.telegram_bot_token, config.telegram_chat_id) {
|
||||
(Some(token), Some(chat_id)) => {
|
||||
let chat_id = ChatId(chat_id);
|
||||
let bot = Bot::new(token);
|
||||
|
||||
let notify_bot = bot.clone();
|
||||
tokio::spawn(telegram::notification_task(notify_bot, chat_id, rx));
|
||||
let notify_bot = bot.clone();
|
||||
tokio::spawn(telegram::notification_task(notify_bot, chat_id, _rx));
|
||||
|
||||
let cmd_data_dir = config.data_dir.clone();
|
||||
tokio::spawn(telegram::bot_task(bot, chat_id, cmd_data_dir));
|
||||
}
|
||||
_ => {
|
||||
tracing::info!("telegram not configured, moderation notifications disabled");
|
||||
let cmd_data_dir = config.data_dir.clone();
|
||||
tokio::spawn(telegram::bot_task(bot, chat_id, cmd_data_dir));
|
||||
}
|
||||
_ => {
|
||||
tracing::info!("telegram not configured, moderation notifications disabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "telegram"))]
|
||||
tracing::info!("compiled without telegram support");
|
||||
|
||||
let state = Arc::new(web::AppState { config, tx });
|
||||
let app = web::router(state);
|
||||
|
||||
|
|
|
|||
|
|
@ -322,7 +322,9 @@ mod tests {
|
|||
data_dir: PathBuf::from("./data"),
|
||||
site_title: "test".into(),
|
||||
|
||||
#[cfg(feature = "telegram")]
|
||||
telegram_bot_token: None,
|
||||
#[cfg(feature = "telegram")]
|
||||
telegram_chat_id: None,
|
||||
enable_honeypot: true,
|
||||
max_name_length: 0,
|
||||
|
|
|
|||
|
|
@ -345,7 +345,9 @@ mod tests {
|
|||
data_dir: dir.to_path_buf(),
|
||||
site_title: "test".into(),
|
||||
|
||||
#[cfg(feature = "telegram")]
|
||||
telegram_bot_token: None,
|
||||
#[cfg(feature = "telegram")]
|
||||
telegram_chat_id: None,
|
||||
enable_honeypot: true,
|
||||
max_name_length: 0,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue