use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use chrono::{DateTime, Local};
use log::{info, warn};
use crate::cli::Cli;
use crate::config::Config;
use crate::config::rich_metadata::RichMetadata;
#[derive(Default, Debug)]
pub struct Metadata {
pub filestem: String,
pub author: String,
pub datetime: DateTime<Local>,
pub extension: Option<String>,
pub header: Option<String>,
pub footer: Option<String>,
pub extra_metadata: Option<Vec<String>>,
}
impl Metadata {
fn determine_filestem(cli: &Cli) -> String {
let filename = &cli.filename;
let filestem = PathBuf::from(&filename)
.file_stem()
.unwrap()
.to_str()
.unwrap()
.to_string();
filestem
}
fn determine_extension(cli: &Cli, config: &Config) -> Option<String> {
match cli.get_extension_if_exists() {
Some(extension) => {
info!("Extension provided: {}", extension);
Some(extension)
}
None => {
info!("Extension not provided. Using extension from config file");
match &config.extension {
Some(extension) => Some(extension.clone()),
None => {
warn!("Extension not found in config file. Not using extension");
None
}
}
}
}
}
fn determine_author(cli: &Cli, config: &Config) -> String {
match &cli.author {
Some(author) => {
info!("Author provided: {}", author);
author.clone()
}
None => {
info!("Author not provided. Using author from config file");
match &config.author {
Some(author) => author.clone(),
None => {
warn!("Author not found in config file. Using current user to author");
whoami::username()
}
}
}
}
}
pub fn to_config_file<P: AsRef<Path>>(&self, config_file: P) -> Result<(), Box<dyn std::error::Error>> {
let mut config = Config::new();
config.set_author(self.author.clone());
config.set_extension(self.extension.clone());
config.set_header(self.header.clone());
config.set_footer(self.footer.clone());
config.set_rich(RichMetadata {
extra_metadata: self.extra_metadata.clone().unwrap_or_default(),
});
config.create_config_file(config_file)
}
pub fn from(cli: &Cli, config: &Config) -> Self {
let filestem = Metadata::determine_filestem(cli);
let author = Metadata::determine_author(cli, config);
let datetime = Local::now();
let extension = Metadata::determine_extension(cli, config);
Metadata {
filestem,
author,
datetime,
extension,
header: config.header.clone(),
footer: config.footer.clone(),
extra_metadata: match &config.rich {
Some(rich) => Some(rich.extra_metadata.clone()),
None => None,
},
}
}
pub fn write_to_doc(&self, new_file: &mut File, cli: &Cli) -> Result<(), std::io::Error>{
new_file.write(
format!(
"{}",
match self.extension {
Some(ref extension) => match extension.as_str() {
"md" => "# ".to_string(),
_ => "".to_string(),
},
None => "".to_string(),
}
)
.as_bytes(),
)?;
new_file.write(format!("{}\n\n", &self.filestem).as_bytes())?;
new_file.write(
format!(
"created: {}\n\
author: {}\n\n",
self.datetime.format("%Y-%m-%d %H:%M:%S"),
&self.author
)
.as_bytes(),
)?;
match cli.enrich {
true => {
match &self.extra_metadata {
Some(extra_metadata) => {
for metadata in extra_metadata {
new_file.write(format!("{}: \n", metadata).as_bytes())?;
}
new_file.write("\n".as_bytes())?;
}
None => (),
}
}
false => (),
}
new_file.write(
format!(
"{}\n",
match &self.header {
Some(header) => header,
None => "",
}
)
.as_bytes(),
)?;
new_file.write("\n".as_bytes())?;
new_file.write(
format!(
"{}",
match &self.footer {
Some(footer) => footer,
None => "",
}
)
.as_bytes(),
)?;
new_file.flush()?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_determine_filestem() {
let mut cli = Cli::default();
cli.filename = "test".to_string();
let filestem = Metadata::determine_filestem(&cli);
assert_eq!(filestem, "test");
}
#[test]
fn test_determine_extension_in_filename() {
let mut cli = Cli::default();
cli.filename = "test.txt".to_string();
let config = Config::new();
let extension = Metadata::determine_extension(&cli, &config);
assert!(extension.is_some_and(|ext| ext == "txt"));
}
#[test]
fn test_determine_extension_is_none() {
let mut cli = Cli::default();
cli.filename = "test".to_string();
let config = Config::new();
let extension = Metadata::determine_extension(&cli, &config);
assert!(extension.is_none());
}
#[test]
fn test_determine_extension_in_config() {
let mut cli = Cli::default();
cli.filename = "test".to_string();
let mut config = Config::new();
config.extension = Some("md".to_string());
let extension = Metadata::determine_extension(&cli, &config);
assert!(extension.is_some_and(|ext| ext == "md"));
}
#[test]
fn test_determine_extension_in_filename_and_config() {
let mut cli = Cli::default();
cli.filename = "test.md".to_string();
let mut config = Config::new();
config.extension = Some("txt".to_string());
let extension = Metadata::determine_extension(&cli, &config);
assert!(extension.is_some_and(|ext| ext == "md"));
}
#[test]
fn test_determine_author_in_cli() {
let mut cli = Cli::default();
cli.filename = "test".to_string();
cli.author = Option::from("testuser".to_string());
let config = Config::new();
let author = Metadata::determine_author(&cli, &config);
assert_eq!(author, "testuser");
}
#[test]
fn test_determine_author_in_config() {
let mut cli = Cli::default();
cli.filename = "test".to_string();
cli.author = None;
let mut config = Config::new();
config.set_author("testuser".to_string());
let author = Metadata::determine_author(&cli, &config);
assert_eq!(author, "testuser");
}
#[test]
fn test_determine_author_in_cli_and_config() {
let mut cli = Cli::default();
cli.filename = "test".to_string();
cli.author = Option::from("cliuser".to_string());
let mut config = Config::new();
config.set_author("configuser".to_string());
let author = Metadata::determine_author(&cli, &config);
assert_eq!(author, "cliuser");
}
#[test]
fn test_determine_author_whoami() {
let mut cli = Cli::default();
cli.filename = "test".to_string();
cli.author = None;
let config = Config::new();
let author = Metadata::determine_author(&cli, &config);
assert_eq!(author, whoami::username());
}
#[test]
fn test_metadata_from() {
let mut cli = Cli::default();
cli.filename = "test".to_string();
cli.author = Option::from("testuser".to_string());
let mut config = Config::new();
config.extension = Some("md".to_string());
config.set_author("configuser".to_string());
let metadata = Metadata::from(&cli, &config);
assert_eq!(metadata.filestem, "test");
assert_eq!(metadata.author, "testuser");
assert!(metadata.extension.is_some_and(|ext| ext == "md"));
}
}