1use anyhow::{anyhow, Context, Result};
2use reqwest::Client;
3use serde::Deserialize;
4use std::{fs::File, io::Read, path::PathBuf};
5use tracing::info;
6
7use crate::{create_client, AccessToken, CLI};
8
9#[derive(Debug, Clone)]
10pub struct Config {
11 pub access_token: AccessToken,
12 pub course_id: u64,
13 pub base_url: String,
14 pub client: Client,
15}
16
17#[derive(Debug, Clone, Deserialize)]
18struct ConfigFile {
19 pub access_token: Option<AccessToken>,
20 pub course_id: Option<u64>,
21 pub base_url: Option<String>,
22}
23
24impl Config {
25 pub fn get(command_line_options: &CLI) -> Result<Self> {
26 let config_file_path = dirs::config_dir()
27 .context("Unable to get config dir for system")?
28 .join("grading")
29 .join("config.toml");
30
31 let config_contents = ConfigFile::read_from_file(&config_file_path)?;
32 info!("Config File: {:#?}", config_contents);
33
34 let access_token = command_line_options
35 .access_token
36 .clone()
37 .map(AccessToken)
38 .or(config_contents.access_token)
39 .ok_or(anyhow!("Access token not configured!"))?;
40 Ok(Self {
41 access_token: access_token.to_owned(),
42 course_id: command_line_options
43 .course_id
44 .or(config_contents.course_id)
45 .ok_or(anyhow!("Course id not configured!"))?,
46 base_url: command_line_options
47 .base_url
48 .clone()
49 .or(config_contents.base_url)
50 .ok_or(anyhow!("Base URL not configured!"))?,
51 client: create_client(access_token)?,
52 })
53 }
54}
55
56impl ConfigFile {
57 pub fn read_from_file(path: &PathBuf) -> Result<Self> {
58 let config_file = File::open(path);
59
60 let mut buffer = String::new();
61 if let Ok(mut file) = config_file {
62 file.read_to_string(&mut buffer)
63 .context("Unable to read file contents.")?;
64 }
65
66 toml::from_str(&buffer).context("Unable to parse config as TOML")
67 }
68}