use std::{error::Error, fs, path::Path};
use log::{debug, error, warn};
use serde::{Deserialize, Serialize};
use crate::{utils, CONFIG_PATH};
#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct UserConf {
pub(crate) username: String,
pub(crate) group: String,
pub(crate) password: bool,
pub(crate) greeting: bool,
}
impl UserConf {
pub(crate) fn update_greeting(mut self) -> Self {
debug!("Greeting value will be update");
self.greeting = true;
self
}
}
impl Default for UserConf {
fn default() -> Self {
Self {
username: String::from("root"),
group: String::from("wheel"),
password: true,
greeting: true,
}
}
}
#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct RudoConf {
pub(crate) impuser: String,
}
impl Default for RudoConf {
fn default() -> Self {
Self {
impuser: String::from("root"),
}
}
}
#[derive(Serialize, Deserialize, Clone)]
pub(crate) struct Config {
pub(crate) rudo: RudoConf,
pub(crate) user: Vec<UserConf>,
}
impl Config {
fn create_config_file(&self) -> Result<(), Box<dyn Error>> {
let config_path = Path::new(CONFIG_PATH);
debug!("Creating default data for configuration file");
let config_file = serde_yaml::to_string(&self)?;
debug!("Creating configuration file at {}", CONFIG_PATH);
utils::create_file(config_path, 0o640, &config_file)?;
Ok(())
}
pub(crate) fn update_user(mut self, impuser: String) -> Self {
debug!("User value will be update");
self.rudo.impuser = impuser;
self
}
}
impl Default for Config {
fn default() -> Self {
Self {
rudo: RudoConf::default(),
user: vec![UserConf::default()],
}
}
}
pub(crate) fn init_conf() -> Result<Config, Box<dyn Error>> {
debug!("Begin initializing default configuration for further use");
let mut conf = Config::default();
let path = Path::new(CONFIG_PATH);
debug!("Verifying that {} exist", CONFIG_PATH);
if path.exists() && path.is_file() {
debug!("Loading {}", CONFIG_PATH);
let result = read_config_file();
if let Err(err) = result {
error!("{}", err);
return Err(err);
}
debug!("Returning the content of the configuration file");
conf = result?;
} else if path.exists() && path.is_dir() {
let err = format!("Error: {} is a directory", CONFIG_PATH);
error!("{}", err);
return Err(From::from(err));
} else {
warn!("{} doesn't exist! Creating it", CONFIG_PATH);
eprintln!("{} doesn't exist! Creating it", CONFIG_PATH);
conf.create_config_file()?;
}
Ok(conf)
}
pub(crate) fn read_config_file() -> Result<Config, Box<dyn Error>> {
let config_path = Path::new(CONFIG_PATH);
debug!("Opening configuration file at {}", CONFIG_PATH);
let buffer = fs::read_to_string(config_path)?;
debug!("Transform data to a structure with serde");
let config: Config = serde_yaml::from_str(&buffer)?;
Ok(config)
}
pub(crate) fn extract_userconf(conf: Vec<UserConf>, username: &str) -> UserConf {
let mut user = UserConf::default();
for cf in conf {
if cf.username == username {
user = cf;
}
}
user
}
#[cfg(test)]
mod tests {
use super::{extract_userconf, Config, Error, UserConf};
#[test]
fn test_update_greeting() -> Result<(), Box<dyn Error>> {
let conf = UserConf {
username: String::from("nano"),
group: String::from("micro"),
password: false,
greeting: false,
};
let conf2 = conf.update_greeting();
if conf2.greeting {
Ok(())
} else {
Err(From::from("Test failed to update greeting value!"))
}
}
#[test]
fn test_update_user() -> Result<(), Box<dyn Error>> {
let conf = Config::default();
let conf2 = conf.update_user(String::from("nano"));
if conf2.rudo.impuser == "nano" {
Ok(())
} else {
Err(From::from("Test failed to update impuser value!"))
}
}
#[test]
fn test_extract_userconf() -> Result<(), Box<dyn Error>> {
let conf = UserConf::default();
let conf2 = vec![conf];
if extract_userconf(conf2, "root").username == "root" {
Ok(())
} else {
Err(From::from("Test failed when extracting the userconf"))
}
}
}