rscalendar 0.1.2

Manage your Google Calendar
use std::collections::HashMap;
use std::path::PathBuf;

use anyhow::{Context, Result};
use serde::Deserialize;

#[derive(Debug, Default, Deserialize)]
#[serde(default)]
pub struct Config {
    pub calendar_name: Option<String>,
    pub no_browser: Option<bool>,
    pub properties: Option<HashMap<String, Vec<String>>>,
    pub check: Option<HashMap<String, Vec<String>>>,
}

impl Config {
    pub fn load() -> Self {
        let path = match config_path() {
            Ok(p) => p,
            Err(e) => {
                eprintln!("Warning: could not determine config path: {e}");
                return Self::default();
            }
        };
        if !path.exists() {
            return Self::default();
        }
        let config: Self = match std::fs::read_to_string(&path) {
            Ok(contents) => toml::from_str(&contents).unwrap_or_else(|e| {
                eprintln!("Warning: failed to parse {}: {e}", path.display());
                Self::default()
            }),
            Err(e) => {
                eprintln!("Warning: failed to read {}: {e}", path.display());
                Self::default()
            }
        };

        if let Some(properties) = &config.properties {
            for (key, values) in properties {
                if values.is_empty() {
                    eprintln!("Warning: property '{key}' in config.toml has an empty list of allowed values");
                }
            }
        }

        config
    }

    pub fn no_browser(&self) -> bool {
        self.no_browser.unwrap_or(false)
    }
}

pub fn config_dir() -> Result<PathBuf> {
    let mut dir = dirs::home_dir()
        .context("Could not determine home directory")?;
    dir.push(".config");
    dir.push("rscalendar");
    std::fs::create_dir_all(&dir)
        .context("Could not create config directory")?;
    Ok(dir)
}

pub fn config_path() -> Result<PathBuf> {
    Ok(config_dir()?.join("config.toml"))
}

pub fn credentials_path() -> Result<PathBuf> {
    let path = config_dir()?.join("credentials.json");
    if !path.exists() {
        eprintln!("Error: credentials.json not found at {}", path.display());
        eprintln!("Download OAuth2 credentials from Google Cloud Console and place them there.");
        std::process::exit(1);
    }
    Ok(path)
}

pub fn token_cache_path() -> Result<PathBuf> {
    Ok(config_dir()?.join("token_cache.json"))
}