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
|
debug = true
|
||||||
source_code = "https://git.batsense.net/libre-solutions/vanigam"
|
source_code = "https://git.batsense.net/libre-solutions/vanikam"
|
||||||
allow_registration = true
|
allow_registration = true
|
||||||
|
|
||||||
[server]
|
[server]
|
||||||
|
@ -12,7 +12,7 @@ port = 7000
|
||||||
#IP address. Enter 0.0.0.0 to listen on all available addresses
|
#IP address. Enter 0.0.0.0 to listen on all available addresses
|
||||||
ip= "0.0.0.0"
|
ip= "0.0.0.0"
|
||||||
# enter your hostname, eg: example.com
|
# enter your hostname, eg: example.com
|
||||||
domain = "localhost:7000"
|
hostname = "http://localhost:7000"
|
||||||
#cookie_secret = ""
|
#cookie_secret = ""
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
|
@ -24,3 +24,10 @@ domain = "localhost:7000"
|
||||||
# pool = 4
|
# pool = 4
|
||||||
url = "postgres://example.org" # hack for tests to run successfully
|
url = "postgres://example.org" # hack for tests to run successfully
|
||||||
pool = 4
|
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
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
use std::sync::Arc;
|
use lettre::{transport::smtp::authentication::Credentials, AsyncSmtpTransport, Tokio1Executor};
|
||||||
|
|
||||||
use lettre::{
|
|
||||||
message::header::ContentType, transport::smtp::authentication::Credentials, AsyncSmtpTransport,
|
|
||||||
Message, Tokio1Executor,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
|
|
||||||
|
@ -16,25 +11,14 @@ pub struct LettreMailer {
|
||||||
mailer: AsyncSmtpTransport<Tokio1Executor>,
|
mailer: AsyncSmtpTransport<Tokio1Executor>,
|
||||||
from: String,
|
from: String,
|
||||||
reply_to: String,
|
reply_to: String,
|
||||||
to: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LettreMailer {
|
impl LettreMailer {
|
||||||
pub async fn new(s: &Settings) -> Self {
|
pub async fn new(s: &Settings) -> Self {
|
||||||
let email = Message::builder()
|
let creds = Credentials::new(s.email.username.clone(), s.email.password.clone());
|
||||||
.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("smtp_username".to_owned(), "smtp_password".to_owned());
|
|
||||||
|
|
||||||
// Open a remote connection to gmail
|
|
||||||
let mailer: AsyncSmtpTransport<Tokio1Executor> =
|
let mailer: AsyncSmtpTransport<Tokio1Executor> =
|
||||||
AsyncSmtpTransport::<Tokio1Executor>::relay("smtp.gmail.com")
|
AsyncSmtpTransport::<Tokio1Executor>::relay(&s.email.server_hostname)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.credentials(creds)
|
.credentials(creds)
|
||||||
.build();
|
.build();
|
||||||
|
@ -42,14 +26,7 @@ impl LettreMailer {
|
||||||
Self {
|
Self {
|
||||||
mailer,
|
mailer,
|
||||||
from: String::default(), // TODO: create settings module to read config
|
from: String::default(), // TODO: create settings module to read config
|
||||||
to: String::default(),
|
|
||||||
reply_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!(
|
log::info!(
|
||||||
"Starting server at: {} {}",
|
"Starting server at: {} {}",
|
||||||
socket_addr,
|
socket_addr,
|
||||||
settings.server.domain
|
settings.server.hostname
|
||||||
);
|
);
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
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::builder::DefaultState;
|
||||||
use config::{Config, ConfigBuilder, ConfigError, File};
|
use config::{Config, ConfigBuilder, ConfigError, File};
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
use validator::Validate;
|
||||||
|
|
||||||
pub mod database;
|
pub mod database;
|
||||||
|
pub mod email;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|
||||||
use database::{DBType, Database};
|
use database::{DBType, Database};
|
||||||
|
use email::Email;
|
||||||
use server::Server;
|
use server::Server;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Eq, PartialEq)]
|
#[derive(Debug, Clone, Validate, Deserialize, Eq, PartialEq)]
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
pub debug: bool,
|
pub debug: bool,
|
||||||
pub log: String,
|
pub log: String,
|
||||||
|
#[validate(url)]
|
||||||
pub source_code: String,
|
pub source_code: String,
|
||||||
pub allow_registration: bool,
|
pub allow_registration: bool,
|
||||||
pub database: Database,
|
pub database: Database,
|
||||||
pub server: Server,
|
pub server: Server,
|
||||||
// pub smtp: Option<Smtp>,
|
pub email: Email,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Settings {
|
impl Settings {
|
||||||
fn env_override(mut s: ConfigBuilder<DefaultState>) -> ConfigBuilder<DefaultState> {
|
fn env_override(mut s: ConfigBuilder<DefaultState>) -> ConfigBuilder<DefaultState> {
|
||||||
for (parameter, env_var_name) in [
|
for (parameter, env_var_name) in [
|
||||||
("debug", "VANIGAM_debug"),
|
("debug", "VANIKAM_debug"),
|
||||||
("source_code", "VANIGAM_source_code"),
|
("source_code", "VANIKAM_source_code"),
|
||||||
("allow_registration", "VANIGAM_allow_registration"),
|
("allow_registration", "VANIKAM_allow_registration"),
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
{
|
{
|
||||||
|
@ -44,9 +47,17 @@ impl Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
s = Database::env_override(s);
|
s = Database::env_override(s);
|
||||||
|
s = Email::env_override(s);
|
||||||
Server::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> {
|
pub fn new() -> Result<Self, ConfigError> {
|
||||||
let mut s = Config::builder();
|
let mut s = Config::builder();
|
||||||
|
|
||||||
|
@ -66,7 +77,7 @@ impl Settings {
|
||||||
.set_default("log", "INFO")
|
.set_default("log", "INFO")
|
||||||
.expect("unable to set log default config");
|
.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();
|
let absolute_path = Path::new(&path).canonicalize().unwrap();
|
||||||
log::info!(
|
log::info!(
|
||||||
"Loading config file from {}",
|
"Loading config file from {}",
|
||||||
|
@ -94,6 +105,7 @@ impl Settings {
|
||||||
settings.check_url();
|
settings.check_url();
|
||||||
|
|
||||||
settings.database.set_database_type();
|
settings.database.set_database_type();
|
||||||
|
settings.run_validations();
|
||||||
|
|
||||||
Ok(settings)
|
Ok(settings)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
// SPDX-FileCopyrightText: 2024 Aravinth Manivannan <realaravinth@batsense.net>
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
use std::env;
|
||||||
|
|
||||||
use config::{builder::DefaultState, ConfigBuilder};
|
use config::{builder::DefaultState, ConfigBuilder};
|
||||||
use serde::Deserialize;
|
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 struct Server {
|
||||||
pub port: u32,
|
pub port: u32,
|
||||||
pub domain: String,
|
#[validate(url)]
|
||||||
|
pub hostname: String,
|
||||||
pub ip: String,
|
pub ip: String,
|
||||||
pub cookie_secret: String,
|
pub cookie_secret: String,
|
||||||
}
|
}
|
||||||
|
@ -22,9 +24,9 @@ impl Server {
|
||||||
pub fn env_override(mut s: ConfigBuilder<DefaultState>) -> ConfigBuilder<DefaultState> {
|
pub fn env_override(mut s: ConfigBuilder<DefaultState>) -> ConfigBuilder<DefaultState> {
|
||||||
for (parameter, env_var_name) in [
|
for (parameter, env_var_name) in [
|
||||||
("server.port", "PORT"),
|
("server.port", "PORT"),
|
||||||
("server.domain", "VANIGAM_server_DOMAIN"),
|
("server.hostname", "VANIKAM_server_HOSTNAME"),
|
||||||
("server.cookie_secret", "VANIGAM_server_COOKIE_SECRET"),
|
("server.cookie_secret", "VANIKAM_server_COOKIE_SECRET"),
|
||||||
("server.ip", "VANIGAM_server_IP"),
|
("server.ip", "VANIKAM_server_IP"),
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
{
|
{
|
||||||
|
@ -50,14 +52,14 @@ mod tests {
|
||||||
env_helper!(init_settings, "PORT", 22, server.port);
|
env_helper!(init_settings, "PORT", 22, server.port);
|
||||||
env_helper!(
|
env_helper!(
|
||||||
init_settings,
|
init_settings,
|
||||||
"VANIGAM_server_DOMAIN",
|
"VANIKAM_server_HOSTNAME",
|
||||||
"test_server_env_override.org",
|
"https://test_server_env_override.org",
|
||||||
server.domain
|
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!(
|
env_helper!(
|
||||||
init_settings,
|
init_settings,
|
||||||
"VANIGAM_server_COOKIE_SECRET",
|
"VANIKAM_server_COOKIE_SECRET",
|
||||||
"asdfasdflkjhasdlkfhalksdf",
|
"asdfasdflkjhasdlkfhalksdf",
|
||||||
server.cookie_secret
|
server.cookie_secret
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue