saturn_cli/
config.rs

1use crate::filenames::saturn_config;
2use anyhow::Result;
3use chrono::Duration;
4use fancy_duration::FancyDuration;
5use gcal::ClientParameters;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9pub enum DBType {
10    #[default]
11    UnixFile,
12    Google,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct Config {
17    db_type: DBType,
18    access_token: Option<String>,
19    access_token_expires_at: Option<chrono::NaiveDateTime>,
20    refresh_token: Option<String>,
21    refresh_token_expires_at: Option<chrono::NaiveDateTime>,
22    client_info: Option<(String, String)>,
23    redirect_url: Option<String>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    sync_duration: Option<FancyDuration<Duration>>,
26    default_duration: Option<FancyDuration<Duration>>,
27    use_24h_time: Option<bool>,
28    query_window: Option<FancyDuration<Duration>>,
29    calendar_id: String,
30}
31
32impl From<Config> for ClientParameters {
33    fn from(value: Config) -> Self {
34        Self {
35            client_id: value.client_id().unwrap_or_default(),
36            client_secret: value.client_secret().unwrap_or_default(),
37            redirect_url: value.redirect_url(),
38            access_key: value.access_token(),
39            expires_at: value.access_token_expires_at(),
40            refresh_token: value.refresh_token(),
41            refresh_token_expires_at: value.refresh_token_expires_at(),
42        }
43    }
44}
45
46impl Default for Config {
47    fn default() -> Self {
48        Self {
49            query_window: Some(FancyDuration::new(chrono::TimeDelta::try_days(30).unwrap_or_default())),
50            use_24h_time: Some(false),
51            db_type: DBType::UnixFile,
52            access_token: None,
53            access_token_expires_at: None,
54            refresh_token: None,
55            refresh_token_expires_at: None,
56            redirect_url: None,
57            client_info: None,
58            sync_duration: None,
59            default_duration: None,
60            calendar_id: "primary".to_string(),
61        }
62    }
63}
64
65impl Config {
66    pub fn load(filename: Option<std::path::PathBuf>) -> Result<Self> {
67        let path = filename.unwrap_or(saturn_config());
68        let mut io = std::fs::OpenOptions::new();
69        io.read(true);
70
71        match io.open(path) {
72            Ok(io) => Ok(serde_yaml::from_reader(io)?),
73            Err(_) => Ok(Self::default()),
74        }
75    }
76
77    pub fn save(&self, filename: Option<std::path::PathBuf>) -> Result<()> {
78        let path = filename.unwrap_or(saturn_config());
79        let mut io = std::fs::OpenOptions::new();
80        io.write(true);
81        io.truncate(true);
82        io.create(true);
83        let io = io.open(path)?;
84
85        Ok(serde_yaml::to_writer(io, self)?)
86    }
87
88    pub fn set_calendar_id(&mut self, calendar_id: String) {
89        self.calendar_id = calendar_id;
90    }
91
92    pub fn set_access_token(&mut self, access_token: Option<String>) {
93        self.access_token = access_token;
94    }
95
96    pub fn set_access_token_expires_at(&mut self, expires_at: Option<chrono::NaiveDateTime>) {
97        self.access_token_expires_at = expires_at;
98    }
99
100    pub fn set_refresh_token(&mut self, refresh_token: Option<String>) {
101        self.refresh_token = refresh_token;
102    }
103
104    pub fn set_refresh_token_expires_at(&mut self, expires_at: Option<chrono::NaiveDateTime>) {
105        self.refresh_token_expires_at = expires_at;
106    }
107
108    pub fn access_token(&self) -> Option<String> {
109        self.access_token.clone()
110    }
111
112    pub fn access_token_expires_at(&self) -> Option<chrono::NaiveDateTime> {
113        self.access_token_expires_at
114    }
115
116    pub fn refresh_token(&self) -> Option<String> {
117        self.refresh_token.clone()
118    }
119
120    pub fn refresh_token_expires_at(&self) -> Option<chrono::NaiveDateTime> {
121        self.refresh_token_expires_at
122    }
123
124    pub fn set_redirect_url(&mut self, redirect_url: Option<String>) {
125        self.redirect_url = redirect_url;
126    }
127
128    pub fn set_default_duration(&mut self, default_duration: Option<FancyDuration<Duration>>) {
129        self.default_duration = default_duration;
130    }
131
132    pub fn default_duration(&self) -> FancyDuration<Duration> {
133        if let Some(duration) = &self.default_duration {
134            duration.clone()
135        } else {
136            FancyDuration(chrono::TimeDelta::try_minutes(15).unwrap_or_default())
137        }
138    }
139
140    pub fn calendar_id(&self) -> String {
141        self.calendar_id.clone()
142    }
143
144    pub fn redirect_url(&self) -> Option<String> {
145        self.redirect_url.clone()
146    }
147
148    pub fn set_db_type(&mut self, typ: DBType) {
149        self.db_type = typ;
150    }
151
152    pub fn db_type(&self) -> DBType {
153        self.db_type.clone()
154    }
155
156    pub fn use_24h_time(&self) -> bool {
157        self.use_24h_time.unwrap_or_default()
158    }
159
160    pub fn set_use_24h_time(&mut self, use_24h_time: bool) {
161        self.use_24h_time = Some(use_24h_time)
162    }
163
164    pub fn query_window(&self) -> chrono::Duration {
165        self.query_window
166            .clone()
167            .map_or_else(|| chrono::TimeDelta::try_days(30).unwrap_or_default(), |x| x.duration())
168    }
169
170    pub fn set_query_window(&mut self, window: chrono::Duration) {
171        self.query_window = Some(FancyDuration::new(window))
172    }
173
174    pub fn set_client_info(&mut self, client_id: String, client_secret: String) {
175        self.client_info = Some((client_id, client_secret))
176    }
177
178    pub fn has_client(&self) -> bool {
179        self.client_info.is_some()
180    }
181
182    pub fn client_id(&self) -> Option<String> {
183        self.client_info.clone().map(|s| s.0)
184    }
185
186    pub fn client_secret(&self) -> Option<String> {
187        self.client_info.clone().map(|s| s.1)
188    }
189}