feat: added crude email notifier

also default to console notifier enabled
This commit is contained in:
əlemi 2024-01-03 04:25:31 +01:00
parent 53c84839b8
commit 6c6c0fd62b
Signed by: alemi
GPG key ID: A4895B84D311642C
5 changed files with 106 additions and 11 deletions

View file

@ -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"]

View file

@ -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 }

View file

@ -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
));
}
}
}

View 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(&notification.body);
if let Err(e) = self.client.lock().await.send(message).await {
tracing::error!("could not send message via email: {}", e);
}
}
}

View file

@ -2,6 +2,9 @@
#[cfg(feature = "telegram")]
pub mod telegram;
#[cfg(feature = "email")]
pub mod email;
pub mod console;