Something went wrong. Try again.
A simple to-do app focused on tasks that can be completed within a specific time span. taskline.tobinio.dev
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161#![deny(clippy::unwrap_used, clippy::expect_used)]
use std::fs;
use clap::{Parser, Subcommand};use client::fetch::{add_todo, fetch_categories, fetch_tags};use color_eyre::eyre;use directories::ProjectDirs;use serde::{Deserialize, Serialize};use types::{todo::AddTodoModel, todo::CreateTodoData};
#[derive(Debug, Parser)]#[command(name = "task-line")]#[command(about = "The TaskLine CLI", long_about = None)]struct Cli { #[command(subcommand)] command: Commands,}
#[derive(Debug, Subcommand)]enum Commands { Settings { #[arg(short, long)] url: Option<String>, #[arg(short = 'k', long)] api_key: Option<String>, }, New { title: String, note: Option<String>, #[arg(short, long)] category: Option<String>, #[arg(short, long)] tags: Vec<String>, },}
#[tokio::main]async fn main() -> eyre::Result<()> { let args = Cli::parse();
match args.command { Commands::Settings { url: None, api_key: None, } => { let settings = Settings::read()?;
if let Some(settings) = settings { println!("current settings\n{settings:?}"); } else { println!("no settings set"); } } Commands::Settings { url, api_key } => { let mut settings = Settings::read()?.unwrap_or_default();
if let Some(url) = url { settings.url = Some(url); }
if let Some(api_key) = api_key { settings.api_key = Some(api_key); }
settings.save()?; } Commands::New { title, note, category, tags, } => { let settings = Settings::read()?;
let Some(settings) = settings else { return Err(eyre::eyre!("no settings set")); };
let Some(url) = settings.url.as_deref() else { return Err(eyre::eyre!("no url set")); }; let Some(token) = settings.api_key.as_deref() else { return Err(eyre::eyre!("no api key set")); };
let server_tags = fetch_tags(url, token).await?; let server_categories = fetch_categories(url, token).await?;
let tags = server_tags .iter() .filter(|tag| tags.contains(&tag.name)) .map(|tag| tag.uuid) .collect::<Vec<_>>();
let categories = server_categories .iter() .filter(|cat| category == Some(cat.name.clone())) .map(|cat| cat.uuid) .next();
add_todo( url, token, &AddTodoModel { data: CreateTodoData { uuid: uuid::Uuid::new_v4(), title, note: note.unwrap_or_default(), tags: Some(tags), category: categories, time: None, reminders: None, }, position: None, previous_id: None, }, ) .await?; } }
Ok(())}
#[derive(Debug, Default, Deserialize, Serialize)]struct Settings { url: Option<String>, api_key: Option<String>,}
impl Settings { fn read() -> eyre::Result<Option<Self>> { let project_dirs = ProjectDirs::from("dev", "tobinio", "TaskLine") .ok_or(eyre::eyre!("Failed to create Project dir"))?;
let settings_path = project_dirs.config_dir().join("settings.json");
if !settings_path.exists() { return Ok(None); }
let content = fs::read_to_string(&settings_path)?; Ok(Some(serde_json::from_str(&content)?)) }
fn save(&self) -> eyre::Result<()> { let project_dirs = ProjectDirs::from("dev", "tobinio", "TaskLine") .ok_or(eyre::eyre!("Failed to create Project dir"))?;
let settings_path = project_dirs.config_dir().join("settings.json");
if let Some(parent) = settings_path.parent() { fs::create_dir_all(parent)?; } fs::write(&settings_path, serde_json::to_string(self)?)?;
Ok(()) }}