Skip to content

Commit

Permalink
Use structs for projects
Browse files Browse the repository at this point in the history
  • Loading branch information
alanvardy committed Jul 29, 2023
1 parent c46bfcb commit 291dd2c
Show file tree
Hide file tree
Showing 7 changed files with 361 additions and 457 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## Unreleased

- Put date picker option first when scheduling
- Use structs for projects instead storing as a `HashMap` in config. This means that projects need to imported again with `project import`, sorry for the inconvenience. The tech debt around project handling was slowing down development.
- Remove `project add` as only `project import` can be used now

## 2023-06-27 v0.4.8

Expand Down
4 changes: 0 additions & 4 deletions manual_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ commands=(
"cargo run -- task list --scheduled"
"cargo run -- project -h"
"cargo run -- project list"
"cargo run -- project add --name test --id 2"
"cargo run -- project remove --project test"
"cargo run -- project add -n test -i 2"
"cargo run -- project remove -p test"
"cargo run -- project empty --project Inbox"
"cargo run -- project empty -p Inbox"
"cargo run -- project schedule --project '🦾 Digital'"
Expand Down
161 changes: 61 additions & 100 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::cargo::Version;
use crate::{cargo, color, input, time, VERSION};
use crate::projects::Project;
use crate::{cargo, color, input, time, todoist, VERSION};
use chrono_tz::TZ_VARIANTS;
use rand::distributions::{Alphanumeric, DistString};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::collections::HashMap;
use std::fs;
use std::io::{Read, Write};

Expand All @@ -14,7 +14,8 @@ pub struct Config {
/// The Todoist Api token
pub token: String,
/// List of Todoist projects and their project numbers
pub projects: HashMap<String, u32>,
#[serde(rename = "vecprojects")]
pub projects: Option<Vec<Project>>,
/// Path to config file
pub path: String,
/// The ID of the next task
Expand All @@ -29,9 +30,21 @@ pub struct Config {
}

impl Config {
pub fn add_project(&mut self, name: String, number: u32) {
let projects = &mut self.projects;
projects.insert(name, number);
pub fn reload_projects(self: &mut Config) -> Result<String, String> {
let all_projects = todoist::projects(self)?;
let current_projects = self.projects.clone().unwrap_or_default();
let current_project_ids: Vec<String> =
current_projects.iter().map(|p| p.id.to_owned()).collect();

let updated_projects = all_projects
.iter()
.filter(|p| current_project_ids.contains(&p.id))
.map(|p| p.to_owned())
.collect::<Vec<Project>>();

self.projects = Some(updated_projects);

Ok(color::green_string("✓"))
}

pub fn check_for_latest_version(self: Config) -> Result<Config, String> {
Expand Down Expand Up @@ -115,7 +128,6 @@ impl Config {
}

pub fn new(token: &str) -> Result<Config, String> {
let projects: HashMap<String, u32> = HashMap::new();
Ok(Config {
path: generate_path()?,
token: String::from(token),
Expand All @@ -126,16 +138,35 @@ impl Config {
mock_url: None,
mock_string: None,
mock_select: None,
projects,
projects: Some(Vec::new()),
})
}

pub fn reload(&self) -> Result<Self, String> {
Config::load(&self.path)
}

pub fn remove_project(&mut self, name: &str) {
self.projects.remove(name);
pub fn add_project(&mut self, project: Project) {
let option_projects = &mut self.projects;
match option_projects {
Some(projects) => {
projects.push(project);
}
None => self.projects = Some(vec![project]),
}
}

pub fn remove_project(&mut self, project: &Project) {
let projects = self
.projects
.clone()
.unwrap_or_default()
.iter()
.filter(|p| p.id != project.id)
.map(|p| p.to_owned())
.collect::<Vec<Project>>();

self.projects = Some(projects);
}

pub fn save(&mut self) -> std::result::Result<String, String> {
Expand Down Expand Up @@ -241,13 +272,12 @@ mod tests {
fn reload_config_should_work() {
let config = test::fixtures::config();
let mut config = config.create().expect("Failed to create test config");
config.add_project("testproj".to_string(), 1);
assert!(!&config.projects.is_empty());
let project = test::fixtures::project();
config.add_project(project);
let projects = config.projects.clone().unwrap_or_default();
assert!(!&projects.is_empty());

let reloaded_config = config.reload().expect("Failed to reload config");
assert!(reloaded_config.projects.is_empty());

delete_config(&reloaded_config.path);
config.reload().expect("Failed to reload config");
}

#[test]
Expand All @@ -263,92 +293,23 @@ mod tests {
#[test]
fn add_project_should_work() {
let mut config = test::fixtures::config();
let mut projects: HashMap<String, u32> = HashMap::new();
assert_eq!(
config,
Config {
token: String::from("alreadycreated"),
path: config.path.clone(),
next_id: None,
last_version_check: None,
projects: projects.clone(),
spinners: Some(true),
timezone: Some(String::from("US/Pacific")),
mock_url: None,
mock_string: None,
mock_select: None,
}
);
config.add_project(String::from("test"), 1234);
projects.insert(String::from("test"), 1234);
assert_eq!(
config,
Config {
token: String::from("alreadycreated"),
path: config.path.clone(),
next_id: None,
last_version_check: None,
spinners: Some(true),
projects,
timezone: Some(String::from("US/Pacific")),
mock_url: None,
mock_string: None,
mock_select: None,
}
);
let projects_count = config.projects.clone().unwrap_or_default().len();
assert_eq!(projects_count, 1);
config.add_project(test::fixtures::project());
let projects_count = config.projects.clone().unwrap_or_default().len();
assert_eq!(projects_count, 2);
}

#[test]
fn remove_project_should_work() {
let mut projects: HashMap<String, u32> = HashMap::new();
projects.insert(String::from("test"), 1234);
projects.insert(String::from("test2"), 4567);
let mut config_with_two_projects = Config {
token: String::from("something"),
path: generate_path().unwrap(),
next_id: None,
spinners: Some(true),
last_version_check: None,
projects: projects.clone(),
timezone: Some(String::from("Asia/Pyongyang")),
mock_url: None,
mock_string: None,
mock_select: None,
};

assert_eq!(
config_with_two_projects,
Config {
token: String::from("something"),
path: config_with_two_projects.path.clone(),
next_id: None,
spinners: Some(true),
last_version_check: None,
projects: projects.clone(),
timezone: Some(String::from("Asia/Pyongyang")),
mock_url: None,
mock_string: None,
mock_select: None,
}
);
config_with_two_projects.remove_project("test");
let mut projects: HashMap<String, u32> = HashMap::new();
projects.insert(String::from("test2"), 4567);
assert_eq!(
config_with_two_projects,
Config {
token: String::from("something"),
path: config_with_two_projects.path.clone(),
next_id: None,
last_version_check: None,
projects,
spinners: Some(true),
timezone: Some(String::from("Asia/Pyongyang")),
mock_url: None,
mock_string: None,
mock_select: None,
}
);
let mut config = test::fixtures::config();
let projects = config.projects.clone().unwrap_or_default();
let project = projects.first().unwrap();
let projects_count = config.projects.clone().unwrap_or_default().len();
assert_eq!(projects_count, 1);
config.remove_project(project);
let projects_count = config.projects.clone().unwrap_or_default().len();
assert_eq!(projects_count, 0);
}

#[test]
Expand All @@ -370,7 +331,7 @@ mod tests {
config,
Ok(Config {
token: String::new(),
projects: HashMap::new(),
projects: Some(Vec::new()),
path: config.clone().unwrap().path,
next_id: None,
spinners: Some(true),
Expand All @@ -395,7 +356,7 @@ mod tests {
config,
Ok(Config {
token: String::new(),
projects: HashMap::new(),
projects: Some(Vec::new()),
path: config.clone().unwrap().path,
next_id: None,
spinners: Some(true),
Expand Down
Loading

0 comments on commit 291dd2c

Please sign in to comment.