feat: read and load email config

This commit is contained in:
Aravinth Manivannan 2024-05-18 19:40:48 +05:30
parent 607d2350b6
commit c1ac50c497
Signed by: realaravinth
GPG key ID: F8F50389936984FF
6 changed files with 128 additions and 47 deletions

View file

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

View file

@ -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:?}"),
// };
}
}

View file

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

View file

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

View file

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