1use std::error::Error;
2use std::fs::File;
3use std::io::BufWriter;
4use std::{ffi::OsString, fs};
5
6use chrono::{DateTime, Utc};
7use inquire::validator::Validation;
8use serde::{Deserialize, Serialize};
9use strum::IntoEnumIterator;
10
11use crate::categories::Category;
12use crate::cmd::check::OsedaCheckError;
13use crate::github;
14
15pub fn read_and_validate_config(skip_git: bool) -> Result<OsedaConfig, OsedaCheckError> {
29 let config_str = fs::read_to_string("oseda-config.json").map_err(|_| {
30 OsedaCheckError::MissingConfig(format!(
31 "Could not find config file in {}",
32 std::env::current_dir().unwrap().to_str().unwrap()
33 ))
34 })?;
35
36 let conf: OsedaConfig = serde_json::from_str(&config_str)
37 .map_err(|_| OsedaCheckError::BadConfig("Could not parse oseda config file".to_owned()))?;
38
39 if !skip_git {
40 println!("Running git checks");
41 let gh_name = github::get_config("user.name").ok_or_else(|| {
42 OsedaCheckError::BadGitCredentials(
43 "Could not get git user.name from git config".to_owned(),
44 )
45 })?;
46
47 if gh_name != conf.author {
48 return Err(OsedaCheckError::BadGitCredentials(
49 "Config author does not match git credentials".to_owned(),
50 ));
51 }
52 }
53
54 let path = std::env::current_dir().map_err(|_| {
55 OsedaCheckError::DirectoryNameMismatch("Could not get path of working directory".to_owned())
56 })?;
57
58 let cwd = path.file_name().ok_or_else(|| {
59 OsedaCheckError::DirectoryNameMismatch("Could not resolve path name".to_owned())
60 })?;
61
62 if cwd != OsString::from(conf.title.clone()) {
63 return Err(OsedaCheckError::DirectoryNameMismatch(
64 "Config title does not match directory name".to_owned(),
65 ));
66 }
67
68 Ok(conf)
69}
70
71#[derive(Serialize, Deserialize)]
73pub struct OsedaConfig {
74 pub title: String,
75 pub author: String,
76 pub category: Vec<Category>,
77 pub last_updated: DateTime<Utc>,
79}
80
81pub fn create_conf() -> Result<OsedaConfig, Box<dyn Error>> {
87 let validator = |input: &str| {
91 if input.chars().count() < 2 {
92 Ok(Validation::Invalid(
93 ("Title must be longer than two characters").into(),
94 ))
95 } else {
96 Ok(Validation::Valid)
97 }
98 };
99
100 let mut title = inquire::Text::new("Title: ")
101 .with_validator(validator)
102 .prompt()?;
103
104 title = title.replace(" ", "-");
105
106 let categories = get_categories()?;
107
108 let user_name = github::get_config("user.name")
109 .ok_or("Could not get github username. Please ensure you are signed into github")?;
110
111 Ok(OsedaConfig {
112 title: title.trim().to_owned(),
113 author: user_name,
114 category: categories,
115 last_updated: get_time(),
116 })
117}
118
119fn get_categories() -> Result<Vec<Category>, Box<dyn Error>> {
125 let options: Vec<Category> = Category::iter().collect();
126
127 let selected_categories =
128 inquire::MultiSelect::new("Select categories", options.clone()).prompt()?;
129
130 println!("You selected:");
131 for category in selected_categories.iter() {
132 println!("- {:?}", category);
133 }
134
135 Ok(selected_categories)
136}
137
138pub fn update_time(mut conf: OsedaConfig) -> Result<(), Box<dyn Error>> {
148 conf.last_updated = get_time();
149
150 write_config(".", &conf)?;
151 Ok(())
152}
153
154fn get_time() -> DateTime<Utc> {
159 chrono::offset::Utc::now()
160}
161
162pub fn write_config(path: &str, conf: &OsedaConfig) -> Result<(), Box<dyn Error>> {
172 let file = File::create(format!("{}/oseda-config.json", path))?;
173 let writer = BufWriter::new(file);
174
175 serde_json::to_writer_pretty(writer, &conf)?;
176
177 Ok(())
178}