// Copyright (C) 2021 Aravinth Manivannan // SPDX-FileCopyrightText: 2023 Aravinth Manivannan // // SPDX-License-Identifier: AGPL-3.0-or-later use std::env; use std::fs; use std::path::Path; use config::{Config, ConfigError, Environment, File}; use log::{debug, warn}; use serde::Deserialize; use serde::Serialize; use sqlx::types::Uuid; use url::Url; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Server { pub port: u32, pub domain: String, pub cookie_secret: String, pub cookie_secret2: String, pub ip: String, pub proxy_has_tls: bool, } impl Server { #[cfg(not(tarpaulin_include))] pub fn get_ip(&self) -> String { format!("{}:{}", self.ip, self.port) } } // //#[derive(Debug, Clone, Serialize, Deserialize)] //struct DatabaseBuilder { // pub port: u32, // pub hostname: String, // pub username: String, // pub password: String, // pub name: String, // pub url: String, //} // //impl DatabaseBuilder { // #[cfg(not(tarpaulin_include))] // fn extract_database_url(url: &Url) -> Self { // debug!("Databse name: {}", url.path()); // let mut path = url.path().split('/'); // path.next(); // let name = path.next().expect("no database name").to_string(); // DatabaseBuilder { // port: url.port().expect("Enter database port").into(), // hostname: url.host().expect("Enter database host").to_string(), // username: url.username().into(), // url: url.to_string(), // password: url.password().expect("Enter database password").into(), // name, // } // } //} #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Database { pub url: String, pub pool: u32, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Footer { pub about: Url, pub privacy: Url, pub security: Url, pub donate: Url, pub thanks: Url, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Publish { pub dir: String, pub duration: u64, } impl Publish { fn create_root_dir(&self) { let root = Path::new(&self.dir); if root.exists() { if !root.is_dir() { std::fs::remove_file(&root).unwrap(); std::fs::create_dir_all(&root).unwrap(); } } else { std::fs::create_dir_all(&root).unwrap(); } } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Settings { pub debug: bool, pub allow_registration: bool, pub database: Database, pub server: Server, pub source_code: String, pub support_email: String, pub default_campaign: String, pub footer: Footer, pub publish: Publish, } #[cfg(not(tarpaulin_include))] impl Settings { pub fn new() -> Result { let mut s = Config::builder(); const CURRENT_DIR: &str = "./config/default.toml"; const ETC: &str = "/etc/mcaptcha-survey/config.toml"; if let Ok(path) = env::var("SURVEY_CONFIG") { s = s.add_source(File::with_name(&path)); } else if Path::new(CURRENT_DIR).exists() { // merging default config from file s = s.add_source(File::with_name(CURRENT_DIR)); } else if Path::new(ETC).exists() { s = s.add_source(File::with_name(ETC)); } else { log::warn!("configuration file not found"); } s = s.add_source(Environment::with_prefix("MCAPTCHA").separator("__")); match env::var("PORT") { Ok(val) => { s = s.set_override("server.port", val).unwrap(); } Err(e) => warn!("couldn't interpret PORT: {}", e), } match env::var("DATABASE_URL") { Ok(val) => { Url::parse(&val).expect("couldn't parse Database URL"); s = s.set_override("database.url", val).unwrap(); } Err(e) => warn!("couldn't interpret DATABASE_URL: {}", e), } let settings = s.build()?.try_deserialize::()?; settings.check_url(); settings.check_uuid(); Ok(settings) } fn check_url(&self) { Url::parse(&self.source_code) .expect("Please enter a URL for source_code in settings"); } #[cfg(not(tarpaulin_include))] fn check_uuid(&self) { use std::str::FromStr; Uuid::from_str(&self.default_campaign) .expect("Please enter a UUID for default_campaign in settings"); } } //#[cfg(not(tarpaulin_include))] //fn check_url(s: &Config) { // let url = s // .get::("source_code") // .expect("Couldn't access source_code"); // // Url::parse(&url).expect("Please enter a URL for source_code in settings"); //} //