contact-form/src/config.rs

155 lines
3.9 KiB
Rust
Raw Normal View History

2022-10-29 17:09:56 +00:00
use anyhow::{Context, Result};
2022-10-28 22:41:02 +00:00
use serde::Deserialize;
2023-02-23 16:10:24 +00:00
use std::{env, fs::File, io::BufReader};
2022-10-28 22:41:02 +00:00
2023-02-23 16:10:24 +00:00
/// Email server credentials.
2022-10-28 22:41:02 +00:00
#[derive(Deserialize)]
2023-02-25 17:08:21 +00:00
pub struct EmailCredentials {
pub domain: String,
pub username: String,
2022-10-28 22:41:02 +00:00
pub password: String,
}
2023-02-25 17:08:21 +00:00
#[derive(Deserialize)]
pub struct Email {
pub from: String,
pub to: String,
pub credentials: EmailCredentials,
}
2023-02-23 16:10:24 +00:00
/// UTC offset for time formatting.
2022-10-28 22:41:02 +00:00
#[derive(Deserialize)]
2023-02-23 02:22:31 +00:00
pub struct UtcOffset {
pub hours: i8,
pub minutes: i8,
2022-12-03 16:08:23 +00:00
}
2023-02-25 17:08:21 +00:00
#[derive(Deserialize)]
#[serde(tag = "type")]
pub enum CustomFieldType {
Text,
Textarea { rows: u8 },
}
#[derive(Deserialize)]
pub struct CustomField {
2023-02-25 20:14:58 +00:00
pub key: String,
2023-02-25 17:08:21 +00:00
pub label: String,
#[serde(default)]
pub required_feedback: Option<String>,
pub field_type: CustomFieldType,
}
2023-02-23 16:10:24 +00:00
/// Error messages for localization.
2022-12-03 16:08:23 +00:00
#[derive(Deserialize)]
pub struct ErrorMessages {
pub captcha_error: String,
pub email_error: String,
}
2023-02-25 17:08:21 +00:00
fn default_name_label() -> String {
"Name".to_string()
}
fn default_name_required_feedback() -> String {
"Please enter your name".to_string()
}
#[derive(Deserialize)]
pub struct NameField {
#[serde(default = "default_name_label")]
pub label: String,
#[serde(default = "default_name_required_feedback")]
pub required_feedback: String,
}
fn default_email_label() -> String {
"Email".to_string()
}
fn default_email_required_feedback() -> String {
"Please enter your email".to_string()
}
#[derive(Deserialize)]
pub struct EmailField {
#[serde(default = "default_email_label")]
pub label: String,
#[serde(default = "default_email_required_feedback")]
pub required_feedback: String,
}
fn default_captcha_label() -> String {
"Enter the code above".to_string()
}
fn default_captcha_required_feedback() -> String {
"Please enter code from the image above".to_string()
}
2022-12-03 16:08:23 +00:00
#[derive(Deserialize)]
2023-02-25 17:08:21 +00:00
pub struct CaptchaField {
#[serde(default = "default_captcha_label")]
2022-12-03 16:08:23 +00:00
pub label: String,
2023-02-25 17:08:21 +00:00
#[serde(default = "default_captcha_required_feedback")]
pub required_feedback: String,
2022-12-03 16:08:23 +00:00
}
2023-02-23 16:10:24 +00:00
/// Localization strings.
2022-12-03 16:08:23 +00:00
#[derive(Deserialize)]
pub struct Strings {
pub description: String,
pub title: String,
2023-02-25 17:08:21 +00:00
pub optional: String,
2022-12-03 16:08:23 +00:00
pub submit: String,
pub success: String,
2023-02-25 17:08:21 +00:00
pub message_from: String,
pub name_field: NameField,
pub email_field: EmailField,
pub captcha_field: CaptchaField,
pub error_messages: ErrorMessages,
}
fn default_lang() -> String {
"en".to_string()
}
2022-10-28 22:41:02 +00:00
#[derive(Deserialize)]
2023-02-25 17:08:21 +00:00
pub struct StateConfig {
2023-02-23 16:10:24 +00:00
/// The path prefix of all routes.
2022-10-28 22:41:02 +00:00
pub path_prefix: String,
2023-02-25 17:08:21 +00:00
pub custom_fields: Vec<CustomField>,
/// The language tag of the HTML file.
#[serde(default = "default_lang")]
pub lang: String,
pub strings: Strings,
}
/// Configuration.
#[derive(Deserialize)]
pub struct Config {
2023-02-23 16:10:24 +00:00
/// The server socket address including port.
2023-02-23 02:22:31 +00:00
pub socket_address: String,
2023-02-25 17:08:21 +00:00
pub email: Email,
2023-02-23 02:22:31 +00:00
pub log_file: String,
pub utc_offset: UtcOffset,
2023-02-25 17:08:21 +00:00
#[serde(flatten)]
pub state_config: StateConfig,
2022-10-28 22:41:02 +00:00
}
impl Config {
2023-02-23 16:17:25 +00:00
/// Parses the configuration from the config path in the environment variable.
2023-02-23 16:10:24 +00:00
pub fn build() -> Result<Self> {
// The environment variable with the path to the config file.
2022-10-28 22:41:02 +00:00
let config_file_var = "CF_CONFIG_FILE";
let config_path = env::var(config_file_var)
2022-10-29 17:09:56 +00:00
.with_context(|| format!("Environment variable {config_file_var} missing!"))?;
2022-10-28 22:41:02 +00:00
2023-02-23 16:10:24 +00:00
let file = File::open(&config_path)
2022-10-29 17:09:56 +00:00
.with_context(|| format!("Can not open the config file at the path {config_path}"))?;
2023-02-23 16:10:24 +00:00
let reader = BufReader::new(file);
2023-02-25 17:08:21 +00:00
let mut config: Self =
2023-02-23 16:10:24 +00:00
serde_yaml::from_reader(reader).context("Can not parse the YAML config file!")?;
2022-10-28 22:41:02 +00:00
2023-02-25 17:08:21 +00:00
// Add a space at the end for the email subject.
config.state_config.strings.message_from =
config.state_config.strings.message_from.trim().to_string() + " ";
2022-10-29 17:09:56 +00:00
Ok(config)
2022-10-28 22:41:02 +00:00
}
}