mirror of
https://git.alemi.dev/guestbook.rs.git
synced 2024-12-19 02:54:52 +01:00
feat: added crude email notifier
also default to console notifier enabled
This commit is contained in:
parent
53c84839b8
commit
6c6c0fd62b
5 changed files with 106 additions and 11 deletions
|
@ -25,11 +25,13 @@ axum = "0.6.20"
|
|||
sqlx = { version = "0.7.3", features = ["runtime-tokio", "tls-rustls", "any"] }
|
||||
# notification providers
|
||||
teloxide = { version = "0.12.2", features = ["macros"], optional = true }
|
||||
mail-send = { version = "0.4.6", optional = true }
|
||||
tokio-rustls = { version = "0.25.0", optional = true }
|
||||
|
||||
[features]
|
||||
default = [
|
||||
"mysql", "sqlite", "postgres",
|
||||
"telegram",
|
||||
"telegram", "email"
|
||||
]
|
||||
# db drivers
|
||||
mysql = ["sqlx/mysql"]
|
||||
|
@ -37,3 +39,4 @@ sqlite = ["sqlx/sqlite"]
|
|||
postgres = ["sqlx/postgres"]
|
||||
# notifier providers
|
||||
telegram = ["dep:teloxide"]
|
||||
email = ["dep:mail-send", "dep:tokio-rustls"]
|
||||
|
|
|
@ -17,20 +17,40 @@ pub struct ConfigOverrides {
|
|||
pub date: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ConfigNotifiers {
|
||||
pub providers: Vec<ConfigNotifierProvider>,
|
||||
pub providers: Vec<NotifierProvider>,
|
||||
}
|
||||
|
||||
// by default enable console notifier
|
||||
impl Default for ConfigNotifiers {
|
||||
fn default() -> Self {
|
||||
ConfigNotifiers {
|
||||
providers: vec![NotifierProvider::Console],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub enum ConfigNotifierProvider {
|
||||
ConsoleNotifier,
|
||||
pub enum NotifierProvider {
|
||||
Console,
|
||||
|
||||
#[cfg(feature = "telegram")]
|
||||
TelegramNotifier {
|
||||
Telegram {
|
||||
token: String,
|
||||
chat_id: i64,
|
||||
},
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
Email {
|
||||
server: String,
|
||||
port: u16,
|
||||
username: String,
|
||||
password: String,
|
||||
from: String,
|
||||
to: String,
|
||||
subject: String,
|
||||
},
|
||||
}
|
||||
|
||||
fn _true() -> bool { true }
|
||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -2,7 +2,7 @@ use std::{net::SocketAddr, io::Write};
|
|||
use clap::{Parser, Subcommand};
|
||||
use config::ConfigOverrides;
|
||||
|
||||
use crate::{storage::StorageProvider, routes::Context, notifications::console::ConsoleTracingNotifier, config::{Config, ConfigNotifierProvider}};
|
||||
use crate::{storage::StorageProvider, routes::Context, notifications::console::ConsoleTracingNotifier, config::{Config, NotifierProvider}};
|
||||
|
||||
mod notifications;
|
||||
|
||||
|
@ -64,9 +64,9 @@ async fn main() {
|
|||
match args.action {
|
||||
CliAction::Default => {
|
||||
let mut cfg = Config::default();
|
||||
cfg.notifiers.providers.push(ConfigNotifierProvider::ConsoleNotifier);
|
||||
cfg.notifiers.providers.push(NotifierProvider::Console);
|
||||
#[cfg(feature = "telegram")]
|
||||
cfg.notifiers.providers.push(ConfigNotifierProvider::TelegramNotifier { token: "asd".into(), chat_id: -1 });
|
||||
cfg.notifiers.providers.push(NotifierProvider::Telegram { token: "asd".into(), chat_id: -1 });
|
||||
println!("{}", toml::to_string(&cfg).unwrap());
|
||||
},
|
||||
CliAction::Review { batch } => {
|
||||
|
@ -112,18 +112,31 @@ async fn main() {
|
|||
|
||||
for notifier in config.notifiers.providers {
|
||||
match notifier {
|
||||
ConfigNotifierProvider::ConsoleNotifier => {
|
||||
NotifierProvider::Console => {
|
||||
tracing::info!("registering console notifier");
|
||||
state.register(Box::new(ConsoleTracingNotifier {}));
|
||||
},
|
||||
|
||||
#[cfg(feature = "telegram")]
|
||||
ConfigNotifierProvider::TelegramNotifier { token, chat_id } => {
|
||||
NotifierProvider::Telegram { token, chat_id } => {
|
||||
tracing::info!("registering telegram notifier for chat {}", chat_id);
|
||||
state.register(Box::new(
|
||||
notifications::telegram::TGNotifier::new(&token, chat_id)
|
||||
));
|
||||
},
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
NotifierProvider::Email {
|
||||
server, port, username, password, from, to, subject
|
||||
} => {
|
||||
tracing::info!("registering email notifier to {} on server {}:{} ('{}')", to, server, port, subject);
|
||||
state.register(Box::new(
|
||||
notifications::email::EmailNotifier::new(
|
||||
&server, port, &username, &password, &from, &to, &subject
|
||||
).await
|
||||
));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
56
src/notifications/email.rs
Normal file
56
src/notifications/email.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
use mail_send::{SmtpClientBuilder, SmtpClient, mail_builder::MessageBuilder};
|
||||
use tokio::{sync::Mutex, net::TcpStream};
|
||||
use tokio_rustls::client::TlsStream;
|
||||
|
||||
use crate::model::Page;
|
||||
|
||||
use super::NotificationProcessor;
|
||||
|
||||
pub struct EmailNotifier {
|
||||
client: Mutex<SmtpClient<TlsStream<TcpStream>>>,
|
||||
from: String,
|
||||
to: String,
|
||||
subject: String,
|
||||
}
|
||||
|
||||
impl EmailNotifier {
|
||||
pub async fn new(
|
||||
server: &str,
|
||||
port: u16,
|
||||
username: &str,
|
||||
password: &str,
|
||||
from: &str,
|
||||
to: &str,
|
||||
subject: &str,
|
||||
) -> Self {
|
||||
let client = SmtpClientBuilder::new(server, port)
|
||||
.implicit_tls(false)
|
||||
.credentials((username, password))
|
||||
.connect()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
EmailNotifier {
|
||||
client: Mutex::new(client),
|
||||
from: from.to_string(),
|
||||
to: to.to_string(),
|
||||
subject: subject.to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl NotificationProcessor<Page> for EmailNotifier {
|
||||
async fn process(&self, notification: &Page) {
|
||||
let message = MessageBuilder::new()
|
||||
.from((notification.author.as_str(), notification.contact.as_ref().unwrap_or(&self.from).as_str()))
|
||||
.to(vec![("Guestbook", self.to.as_str())])
|
||||
.subject(&self.subject)
|
||||
.text_body(¬ification.body);
|
||||
|
||||
if let Err(e) = self.client.lock().await.send(message).await {
|
||||
tracing::error!("could not send message via email: {}", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -2,6 +2,9 @@
|
|||
#[cfg(feature = "telegram")]
|
||||
pub mod telegram;
|
||||
|
||||
#[cfg(feature = "email")]
|
||||
pub mod email;
|
||||
|
||||
pub mod console;
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue