From 159f03320ff211d23872864c58006d25d99ac208 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Wed, 4 Dec 2024 20:31:36 +0000 Subject: [PATCH] refactor: Add FullCtx which is Ctx with AppConfig --- src/config.rs | 103 ++++++++++--------------------------- src/lib.rs | 39 +++++++++++--- src/nextcloud/mod.rs | 33 ++++++------ src/nextcloud/tests.rs | 51 +++++++++++++----- src/tests/mod.rs | 42 +++++++++++++++ src/tests/test-config.toml | 10 ++++ src/trello/mod.rs | 20 +++---- src/trello/types/auth.rs | 14 ++--- src/trello/types/mod.rs | 25 +++++---- 9 files changed, 193 insertions(+), 144 deletions(-) create mode 100644 src/tests/test-config.toml diff --git a/src/config.rs b/src/config.rs index 0f3a9b7..9bd4e2d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,80 +1,30 @@ // -// use color_eyre::Result; +use color_eyre::Result; use crate::{ - // f, + f, nextcloud::model::{NextcloudBoardId, NextcloudHostname, NextcloudPassword, NextcloudUsername}, - // s, - // trello::types::{TrelloApiKey, TrelloApiSecret, TrelloAuth, TrelloBoardName, TrelloUser}, - // Ctx, NAME, + s, + trello::types::{ + auth::{TrelloApiKey, TrelloApiSecret}, + TrelloBoardName, + }, + Ctx, NAME, }; -#[derive( - Clone, - Debug, - derive_more::From, - PartialEq, - Eq, - PartialOrd, - Ord, - serde::Deserialize, - derive_more::Constructor, -)] +#[derive(Clone, Debug, derive_more::From, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize)] pub struct TrelloConfig { - pub user: String, - pub api_key: String, - pub api_secret: String, - pub board_name: String, + pub(crate) api_key: TrelloApiKey, + pub(crate) api_secret: TrelloApiSecret, + pub(crate) board_name: TrelloBoardName, } -// impl TrelloConfig { -// pub fn user(&self) -> TrelloUser { -// TrelloUser::from(self.user.clone()) -// } -// pub fn api_key(&self) -> TrelloApiKey { -// TrelloApiKey::from(self.api_key.clone()) -// } -// pub fn api_secret(&self) -> TrelloApiSecret { -// TrelloApiSecret::from(self.api_secret.clone()) -// } -// pub fn auth(&self) -> TrelloAuth { -// TrelloAuth::new(self.api_key(), self.api_secret(), self.user()) -// } -// -// pub fn board_name(&self) -> TrelloBoardName { -// TrelloBoardName::from(self.board_name.clone()) -// } -// } -#[derive( - Clone, - Debug, - derive_more::From, - PartialEq, - Eq, - PartialOrd, - Ord, - serde::Deserialize, - derive_more::Constructor, -)] +#[derive(Clone, Debug, derive_more::From, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize)] pub struct NextcloudConfig { - hostname: NextcloudHostname, - username: NextcloudUsername, - password: NextcloudPassword, - board_id: NextcloudBoardId, -} -impl NextcloudConfig { - pub fn hostname(&self) -> &NextcloudHostname { - &self.hostname - } - pub fn username(&self) -> &NextcloudUsername { - &self.username - } - pub fn password(&self) -> &NextcloudPassword { - &self.password - } - pub fn board_id(&self) -> NextcloudBoardId { - self.board_id - } + pub(crate) hostname: NextcloudHostname, + pub(crate) username: NextcloudUsername, + pub(crate) password: NextcloudPassword, + pub(crate) board_id: NextcloudBoardId, } #[derive( @@ -87,16 +37,15 @@ impl NextcloudConfig { Ord, derive_more::AsRef, serde::Deserialize, - derive_more::Constructor, )] pub struct AppConfig { - pub trello: TrelloConfig, - pub nextcloud: NextcloudConfig, + pub(crate) trello: TrelloConfig, + pub(crate) nextcloud: NextcloudConfig, +} +impl AppConfig { + pub fn load(ctx: &Ctx) -> Result { + let file = ctx.fs.base().join(f!("{NAME}.toml")); + let str = ctx.fs.file(&file).reader()?; + Ok(toml::from_str(s!(str).as_str())?) + } } -// impl AppConfig { -// pub fn load(ctx: &Ctx) -> Result { -// let file = ctx.fs.base().join(f!("{NAME}.toml")); -// let str = ctx.fs.file(&file).reader()?; -// Ok(toml::from_str(s!(str).as_str())?) -// } -// } diff --git a/src/lib.rs b/src/lib.rs index fe20602..cdd52ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ use std::path::PathBuf; use clap::Parser; +use color_eyre::eyre::eyre; pub use config::AppConfig; use kxio::{fs::FileSystem, net::Net}; @@ -11,7 +12,7 @@ mod init; mod macros; pub mod nextcloud; mod template; -// mod trello; +mod trello; #[cfg(test)] mod tests; @@ -45,16 +46,38 @@ impl Default for Ctx { } } +#[derive(Clone)] +pub struct FullCtx { + pub fs: FileSystem, + pub net: Net, + pub cfg: AppConfig, +} + #[cfg_attr(test, mutants::skip)] pub async fn run(ctx: Ctx) -> color_eyre::Result<()> { color_eyre::install()?; let commands = Commands::parse(); - match commands.command { - Command::Init => init::run(&ctx)?, - Command::Check => todo!("check"), - Command::Import => todo!("import"), - }; - - Ok(()) + let cfg = AppConfig::load(&ctx); + match cfg { + Err(err) => { + if matches!(commands.command, Command::Init) { + init::run(&ctx) + } else { + Err(eyre!("Missing or invalid config: {err}")) + } + } + Ok(cfg) => { + let _ctx = FullCtx { + fs: ctx.fs, + net: ctx.net, + cfg, + }; + match commands.command { + Command::Init => Err(eyre!("Config file already exists. Not overwriting it.")), + Command::Check => todo!("check"), + Command::Import => todo!("import"), + } + } + } } diff --git a/src/nextcloud/mod.rs b/src/nextcloud/mod.rs index 0a01925..4a7eadf 100644 --- a/src/nextcloud/mod.rs +++ b/src/nextcloud/mod.rs @@ -4,6 +4,7 @@ use kxio::net::Net; use crate::api_result::APIResult; use crate::{config::NextcloudConfig, f}; +use crate::nextcloud::model::{NextcloudHostname, NextcloudPassword, NextcloudUsername}; use model::{Board, Card, NextcloudBoardId, Stack}; pub mod model; @@ -11,24 +12,20 @@ pub mod model; #[cfg(test)] mod tests; -pub struct DeckClient { +pub struct DeckClient<'cfg> { net: Net, - hostname: String, - username: String, - password: String, + hostname: &'cfg NextcloudHostname, + username: &'cfg NextcloudUsername, + password: &'cfg NextcloudPassword, } -impl DeckClient { - pub fn new(cfg: &NextcloudConfig, net: Net) -> Self { - let hostname = cfg.hostname().to_string(); - let username = cfg.username().to_string(); - let password = cfg.password().to_string(); - +impl<'cfg> DeckClient<'cfg> { + pub fn new(cfg: &'cfg NextcloudConfig, net: Net) -> Self { Self { net, - hostname, - username, - password, + hostname: &cfg.hostname, + username: &cfg.username, + password: &cfg.password, } } @@ -44,7 +41,7 @@ impl DeckClient { APIResult::new( self.net .get(self.url("boards")) - .basic_auth(&self.username, Some(&self.password)) + .basic_auth(self.username.as_str(), Some(self.password.as_str())) .header("accept", "application/json") .send() .await, @@ -56,7 +53,7 @@ impl DeckClient { APIResult::new( self.net .get(self.url(f!("boards/{board_id}"))) - .basic_auth(&self.username, Some(&self.password)) + .basic_auth(self.username.as_str(), Some(self.password.as_str())) .header("accept", "application/json") .send() .await, @@ -68,7 +65,7 @@ impl DeckClient { APIResult::new( self.net .post(self.url("boards")) - .basic_auth(&self.username, Some(&self.password)) + .basic_auth(self.username.as_str(), Some(self.password.as_str())) .header("accept", "application/json") .body( serde_json::json!({ @@ -87,7 +84,7 @@ impl DeckClient { APIResult::new( self.net .get(self.url(f!("boards/{board_id}/stacks"))) - .basic_auth(&self.username, Some(&self.password)) + .basic_auth(self.username.as_str(), Some(self.password.as_str())) .header("accept", "application/json") .send() .await, @@ -118,7 +115,7 @@ impl DeckClient { APIResult::new( self.net .post(&url) - .basic_auth(&self.username, Some(&self.password)) + .basic_auth(self.username.as_str(), Some(self.password.as_str())) .header("accept", "application/json") .body(json.to_string()) .send() diff --git a/src/nextcloud/tests.rs b/src/nextcloud/tests.rs index 3518cbc..5f1682d 100644 --- a/src/nextcloud/tests.rs +++ b/src/nextcloud/tests.rs @@ -17,13 +17,18 @@ mod config { let username = NextcloudUsername::new("username"); let password = NextcloudPassword::new("password"); let board_id = NextcloudBoardId::new(2); - let cfg = NextcloudConfig::new(hostname.clone(), username, password, board_id); + let cfg = NextcloudConfig { + hostname: hostname.clone(), + username, + password, + board_id, + }; //when - let result = cfg.hostname(); + let result = cfg.hostname; //then - assert_eq!(result, &hostname); + assert_eq!(result, hostname); } #[test] @@ -33,13 +38,18 @@ mod config { let username = NextcloudUsername::new("username"); let password = NextcloudPassword::new("password"); let board_id = NextcloudBoardId::new(2); - let cfg = NextcloudConfig::new(hostname, username.clone(), password, board_id); + let cfg = NextcloudConfig { + hostname, + username: username.clone(), + password, + board_id, + }; //when - let result = cfg.username(); + let result = cfg.username; //then - assert_eq!(result, &username); + assert_eq!(result, username); } #[test] @@ -49,13 +59,18 @@ mod config { let username = NextcloudUsername::new("username"); let password = NextcloudPassword::new("password"); let board_id = NextcloudBoardId::new(2); - let cfg = NextcloudConfig::new(hostname, username, password.clone(), board_id); + let cfg = NextcloudConfig { + hostname, + username, + password: password.clone(), + board_id, + }; //when - let result = cfg.password(); + let result = cfg.password; //then - assert_eq!(result, &password); + assert_eq!(result, password); } #[test] @@ -65,10 +80,15 @@ mod config { let username = NextcloudUsername::new("username"); let password = NextcloudPassword::new("password"); let board_id = NextcloudBoardId::new(2); - let cfg = NextcloudConfig::new(hostname, username, password, board_id); + let cfg = NextcloudConfig { + hostname, + username, + password, + board_id, + }; //when - let result = cfg.board_id(); + let result = cfg.board_id; //then assert_eq!(result, board_id); @@ -174,7 +194,7 @@ mod client { //when let result = deck_client - .get_stacks(cfg.board_id()) + .get_stacks(cfg.board_id) .await .result .expect("get stacks"); @@ -216,6 +236,11 @@ mod given { let username = NextcloudUsername::new("username"); let password = NextcloudPassword::new("password"); let board_id = NextcloudBoardId::new(2); - NextcloudConfig::new(hostname, username, password, board_id) + NextcloudConfig { + hostname, + username, + password, + board_id, + } } } diff --git a/src/tests/mod.rs b/src/tests/mod.rs index f1a8183..9b0d8c7 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -48,6 +48,48 @@ mod init { } } +mod config { + use super::*; + mod load { + use super::*; + use crate::config::{NextcloudConfig, TrelloConfig}; + use crate::{s, AppConfig}; + #[test] + fn test_load() { + //given + let fs = given::a_filesystem(); + let mock_net = given::a_network(); + + let file = fs.file(&fs.base().join("trello-to-deck.toml")); + file.write(include_str!("test-config.toml")) + .expect("write test config"); + + let ctx = given::a_context(fs.as_real(), mock_net.into()); + + //when + let cfg = AppConfig::load(&ctx); + + //then + let_assert!(Ok(cfg) = cfg); + assert_eq!( + cfg, + AppConfig { + trello: TrelloConfig { + api_key: s!("trello-api-key").into(), + api_secret: s!("trello-api-secret").into(), + board_name: s!("trello-board-name").into(), + }, + nextcloud: NextcloudConfig { + hostname: s!("nextcloud-hostname").into(), + username: s!("nextcloud-username").into(), + password: s!("nextcloud-password").into(), + board_id: 321.into(), + } + } + ); + } + } +} mod template { use std::collections::HashMap; diff --git a/src/tests/test-config.toml b/src/tests/test-config.toml new file mode 100644 index 0000000..fcbe03a --- /dev/null +++ b/src/tests/test-config.toml @@ -0,0 +1,10 @@ +[trello] +api_key = "trello-api-key" +api_secret = "trello-api-secret" +board_name = "trello-board-name" + +[nextcloud] +hostname = "nextcloud-hostname" +username = "nextcloud-username" +password = "nextcloud-password" +board_id = 321 \ No newline at end of file diff --git a/src/trello/mod.rs b/src/trello/mod.rs index 41660e0..2c7b347 100644 --- a/src/trello/mod.rs +++ b/src/trello/mod.rs @@ -1,14 +1,14 @@ // -pub mod api; +// pub mod api; pub mod types; -#[cfg(test)] -mod tests; +// #[cfg(test)] +// mod tests; -use crate::f; - -pub fn url(path: impl Into) -> String { - let path = path.into(); - assert!(path.starts_with("/")); - f!("https://api.trello.com/1{path}") -} +// use crate::f; +// +// pub fn url(path: impl Into) -> String { +// let path = path.into(); +// assert!(path.starts_with("/")); +// f!("https://api.trello.com/1{path}") +// } diff --git a/src/trello/types/auth.rs b/src/trello/types/auth.rs index 76c868e..392289b 100644 --- a/src/trello/types/auth.rs +++ b/src/trello/types/auth.rs @@ -1,16 +1,17 @@ +// use std::collections::HashMap; -// use derive_more::derive::Display; use crate::newtype; -newtype!(TrelloUser, String, Display, "User"); -newtype!(TrelloApiKey, String, Display, "API Key"); +newtype!(TrelloApiKey, String, Display, PartialOrd, Ord, "API Key"); newtype!( TrelloApiSecret, String, Display, + PartialOrd, + Ord, "API Secret token for Trello" ); @@ -18,14 +19,12 @@ newtype!( pub struct TrelloAuth { api_key: TrelloApiKey, api_secret: TrelloApiSecret, - user: TrelloUser, } impl TrelloAuth { - pub const fn new(api_key: TrelloApiKey, api_secret: TrelloApiSecret, user: TrelloUser) -> Self { + pub const fn new(api_key: TrelloApiKey, api_secret: TrelloApiSecret) -> Self { Self { api_key, api_secret, - user, } } @@ -35,9 +34,6 @@ impl TrelloAuth { pub const fn api_token(&self) -> &TrelloApiSecret { &self.api_secret } - pub const fn user(&self) -> &TrelloUser { - &self.user - } } impl From<&TrelloAuth> for HashMap { fn from(value: &TrelloAuth) -> Self { diff --git a/src/trello/types/mod.rs b/src/trello/types/mod.rs index a168aa4..b3f8bf2 100644 --- a/src/trello/types/mod.rs +++ b/src/trello/types/mod.rs @@ -1,23 +1,30 @@ pub(crate) mod auth; -pub(crate) mod board; +// pub(crate) mod board; // mod card; -mod list; +// mod list; // mod new_card; use derive_more::derive::Display; use crate::newtype; -newtype!(TrelloBoardId, String, Display, "Board ID"); -newtype!(TrelloBoardName, String, Display, "Board Name"); -newtype!(TrelloListId, String, "List ID"); +// newtype!(TrelloBoardId, String, Display, "Board ID"); newtype!( - TrelloListName, + TrelloBoardName, String, Display, PartialOrd, Ord, - "List Name" + "Board Name" ); -newtype!(TrelloCardId, String, Display, "Card ID"); -newtype!(TrelloCardName, String, Display, "Card Name"); +// newtype!(TrelloListId, String, "List ID"); +// newtype!( +// TrelloListName, +// String, +// Display, +// PartialOrd, +// Ord, +// "List Name" +// ); +// newtype!(TrelloCardId, String, Display, "Card ID"); +// newtype!(TrelloCardName, String, Display, "Card Name");