feat: read and load email config
This commit is contained in:
parent
607d2350b6
commit
c1ac50c497
6 changed files with 128 additions and 47 deletions
|
@ -1,5 +1,5 @@
|
|||
debug = true
|
||||
source_code = "https://git.batsense.net/libre-solutions/vanigam"
|
||||
source_code = "https://git.batsense.net/libre-solutions/vanikam"
|
||||
allow_registration = true
|
||||
|
||||
[server]
|
||||
|
@ -12,7 +12,7 @@ port = 7000
|
|||
#IP address. Enter 0.0.0.0 to listen on all available addresses
|
||||
ip= "0.0.0.0"
|
||||
# enter your hostname, eg: example.com
|
||||
domain = "localhost:7000"
|
||||
hostname = "http://localhost:7000"
|
||||
#cookie_secret = ""
|
||||
|
||||
[database]
|
||||
|
@ -24,3 +24,10 @@ domain = "localhost:7000"
|
|||
# pool = 4
|
||||
url = "postgres://example.org" # hack for tests to run successfully
|
||||
pool = 4
|
||||
|
||||
[email]
|
||||
username="vanikam_mailer"
|
||||
password="vanikam_mailer_password"
|
||||
server_hostname="smtp.vanikam.example.com"
|
||||
from="vanikam@example.com"
|
||||
reply_to="vanikam@example.com"
|
||||
|
|
|
@ -2,12 +2,7 @@
|
|||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use lettre::{
|
||||
message::header::ContentType, transport::smtp::authentication::Credentials, AsyncSmtpTransport,
|
||||
Message, Tokio1Executor,
|
||||
};
|
||||
use lettre::{transport::smtp::authentication::Credentials, AsyncSmtpTransport, Tokio1Executor};
|
||||
|
||||
use crate::settings::Settings;
|
||||
|
||||
|
@ -16,25 +11,14 @@ pub struct LettreMailer {
|
|||
mailer: AsyncSmtpTransport<Tokio1Executor>,
|
||||
from: String,
|
||||
reply_to: String,
|
||||
to: String,
|
||||
}
|
||||
|
||||
impl LettreMailer {
|
||||
pub async fn new(s: &Settings) -> Self {
|
||||
let email = Message::builder()
|
||||
.from("NoBody <nobody@domain.tld>".parse().unwrap())
|
||||
.reply_to("Yuin <yuin@domain.tld>".parse().unwrap())
|
||||
.to("Hei <hei@domain.tld>".parse().unwrap())
|
||||
.subject("Happy new async year")
|
||||
.header(ContentType::TEXT_PLAIN)
|
||||
.body(String::from("Be happy with async!"))
|
||||
.unwrap();
|
||||
let creds = Credentials::new(s.email.username.clone(), s.email.password.clone());
|
||||
|
||||
let creds = Credentials::new("smtp_username".to_owned(), "smtp_password".to_owned());
|
||||
|
||||
// Open a remote connection to gmail
|
||||
let mailer: AsyncSmtpTransport<Tokio1Executor> =
|
||||
AsyncSmtpTransport::<Tokio1Executor>::relay("smtp.gmail.com")
|
||||
AsyncSmtpTransport::<Tokio1Executor>::relay(&s.email.server_hostname)
|
||||
.unwrap()
|
||||
.credentials(creds)
|
||||
.build();
|
||||
|
@ -42,14 +26,7 @@ impl LettreMailer {
|
|||
Self {
|
||||
mailer,
|
||||
from: String::default(), // TODO: create settings module to read config
|
||||
to: String::default(),
|
||||
reply_to: String::default(),
|
||||
}
|
||||
|
||||
// Send the email
|
||||
// match mailer.send(email).await {
|
||||
// Ok(_) => println!("Email sent successfully!"),
|
||||
// Err(e) => panic!("Could not send email: {e:?}"),
|
||||
// };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ async fn main() {
|
|||
log::info!(
|
||||
"Starting server at: {} {}",
|
||||
socket_addr,
|
||||
settings.server.domain
|
||||
settings.server.hostname
|
||||
);
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
|
|
83
src/settings/email.rs
Normal file
83
src/settings/email.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use std::env;
|
||||
|
||||
use config::{builder::DefaultState, ConfigBuilder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Validate, Eq, PartialEq)]
|
||||
pub struct Email {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub server_hostname: String,
|
||||
#[validate(email)]
|
||||
pub from: String,
|
||||
#[validate(email)]
|
||||
pub reply_to: String,
|
||||
}
|
||||
|
||||
impl Email {
|
||||
pub fn env_override(mut s: ConfigBuilder<DefaultState>) -> ConfigBuilder<DefaultState> {
|
||||
for (parameter, env_var_name) in [
|
||||
("email.username", "VANIKAM_email_USERNAME"),
|
||||
("email.password", "VANIKAM_email_PASSWORD"),
|
||||
("email.server_hostname", "VANIKAM_email_SERVER_HOSTNAME"),
|
||||
("email.from", "VANIKAM_email_FROM"),
|
||||
("email.reply_to", "VANIKAM_email_REPLY_TO"),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
if let Ok(val) = env::var(env_var_name) {
|
||||
log::debug!("Overriding [{parameter}] with environment variable {env_var_name}");
|
||||
s = s.set_override(parameter, val).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::env_helper;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_db_env_override() {
|
||||
let init_settings = crate::settings::Settings::new().unwrap();
|
||||
env_helper!(
|
||||
init_settings,
|
||||
"VANIKAM_email_USERNAME",
|
||||
"email_username",
|
||||
email.username
|
||||
);
|
||||
env_helper!(
|
||||
init_settings,
|
||||
"VANIKAM_email_PASSWORD",
|
||||
"email_password",
|
||||
email.password
|
||||
);
|
||||
env_helper!(
|
||||
init_settings,
|
||||
"VANIKAM_email_FROM",
|
||||
"from@example.com",
|
||||
email.from
|
||||
);
|
||||
env_helper!(
|
||||
init_settings,
|
||||
"VANIKAM_email_REPLY_TO",
|
||||
"reploy_to@example.com",
|
||||
email.reply_to
|
||||
);
|
||||
env_helper!(
|
||||
init_settings,
|
||||
"VANIKAM_email_SERVER_HOSTNAME",
|
||||
"smtp.example.com",
|
||||
email.server_hostname
|
||||
);
|
||||
}
|
||||
}
|
|
@ -7,33 +7,36 @@ use std::{env, fs};
|
|||
|
||||
use config::builder::DefaultState;
|
||||
use config::{Config, ConfigBuilder, ConfigError, File};
|
||||
|
||||
use serde::Deserialize;
|
||||
use url::Url;
|
||||
use validator::Validate;
|
||||
|
||||
pub mod database;
|
||||
pub mod email;
|
||||
pub mod server;
|
||||
|
||||
use database::{DBType, Database};
|
||||
use email::Email;
|
||||
use server::Server;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Validate, Deserialize, Eq, PartialEq)]
|
||||
pub struct Settings {
|
||||
pub debug: bool,
|
||||
pub log: String,
|
||||
#[validate(url)]
|
||||
pub source_code: String,
|
||||
pub allow_registration: bool,
|
||||
pub database: Database,
|
||||
pub server: Server,
|
||||
// pub smtp: Option<Smtp>,
|
||||
pub email: Email,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
fn env_override(mut s: ConfigBuilder<DefaultState>) -> ConfigBuilder<DefaultState> {
|
||||
for (parameter, env_var_name) in [
|
||||
("debug", "VANIGAM_debug"),
|
||||
("source_code", "VANIGAM_source_code"),
|
||||
("allow_registration", "VANIGAM_allow_registration"),
|
||||
("debug", "VANIKAM_debug"),
|
||||
("source_code", "VANIKAM_source_code"),
|
||||
("allow_registration", "VANIKAM_allow_registration"),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
|
@ -44,9 +47,17 @@ impl Settings {
|
|||
}
|
||||
|
||||
s = Database::env_override(s);
|
||||
s = Email::env_override(s);
|
||||
Server::env_override(s)
|
||||
}
|
||||
|
||||
fn run_validations(&self) {
|
||||
self.validate().unwrap();
|
||||
self.email.validate().unwrap();
|
||||
self.database.validate().unwrap();
|
||||
self.server.validate().unwrap();
|
||||
}
|
||||
|
||||
pub fn new() -> Result<Self, ConfigError> {
|
||||
let mut s = Config::builder();
|
||||
|
||||
|
@ -66,7 +77,7 @@ impl Settings {
|
|||
.set_default("log", "INFO")
|
||||
.expect("unable to set log default config");
|
||||
|
||||
if let Ok(path) = env::var("VANIGAM_CONFIG") {
|
||||
if let Ok(path) = env::var("VANIKAM_CONFIG") {
|
||||
let absolute_path = Path::new(&path).canonicalize().unwrap();
|
||||
log::info!(
|
||||
"Loading config file from {}",
|
||||
|
@ -94,6 +105,7 @@ impl Settings {
|
|||
settings.check_url();
|
||||
|
||||
settings.database.set_database_type();
|
||||
settings.run_validations();
|
||||
|
||||
Ok(settings)
|
||||
}
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
use std::env;
|
||||
|
||||
use config::{builder::DefaultState, ConfigBuilder};
|
||||
use serde::Deserialize;
|
||||
use std::env;
|
||||
use validator::Validate;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Validate, Deserialize, Eq, PartialEq)]
|
||||
pub struct Server {
|
||||
pub port: u32,
|
||||
pub domain: String,
|
||||
#[validate(url)]
|
||||
pub hostname: String,
|
||||
pub ip: String,
|
||||
pub cookie_secret: String,
|
||||
}
|
||||
|
@ -22,9 +24,9 @@ impl Server {
|
|||
pub fn env_override(mut s: ConfigBuilder<DefaultState>) -> ConfigBuilder<DefaultState> {
|
||||
for (parameter, env_var_name) in [
|
||||
("server.port", "PORT"),
|
||||
("server.domain", "VANIGAM_server_DOMAIN"),
|
||||
("server.cookie_secret", "VANIGAM_server_COOKIE_SECRET"),
|
||||
("server.ip", "VANIGAM_server_IP"),
|
||||
("server.hostname", "VANIKAM_server_HOSTNAME"),
|
||||
("server.cookie_secret", "VANIKAM_server_COOKIE_SECRET"),
|
||||
("server.ip", "VANIKAM_server_IP"),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
|
@ -50,14 +52,14 @@ mod tests {
|
|||
env_helper!(init_settings, "PORT", 22, server.port);
|
||||
env_helper!(
|
||||
init_settings,
|
||||
"VANIGAM_server_DOMAIN",
|
||||
"test_server_env_override.org",
|
||||
server.domain
|
||||
"VANIKAM_server_HOSTNAME",
|
||||
"https://test_server_env_override.org",
|
||||
server.hostname
|
||||
);
|
||||
env_helper!(init_settings, "VANIGAM_server_IP", "1.1.1.1", server.ip);
|
||||
env_helper!(init_settings, "VANIKAM_server_IP", "1.1.1.1", server.ip);
|
||||
env_helper!(
|
||||
init_settings,
|
||||
"VANIGAM_server_COOKIE_SECRET",
|
||||
"VANIKAM_server_COOKIE_SECRET",
|
||||
"asdfasdflkjhasdlkfhalksdf",
|
||||
server.cookie_secret
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue