diff --git a/src/api_result.rs b/src/api_result.rs index b85043c..c9e3bdb 100644 --- a/src/api_result.rs +++ b/src/api_result.rs @@ -1,32 +1,32 @@ // -// use kxio::net::Response; -// -// use crate::{e, s}; +use kxio::net::Response; -// pub struct APIResult { -// pub text: String, -// pub result: Result, -// } +use crate::{e, s}; -// impl serde::Deserialize<'a>> APIResult { -// pub async fn new(response: kxio::net::Result) -> Self { -// match response { -// Ok(response) => { -// let text = response.text().await.unwrap_or_default(); -// let text = if text.is_empty() { s!("null") } else { text }; -// let result = serde_json::from_str::(&text) -// .map_err(|e| e.to_string()) -// .map_err(|e| { -// e!("{e}: {text}"); -// e -// }) -// .map_err(kxio::net::Error::from); -// Self { text, result } -// } -// Err(e) => Self { -// text: s!(""), -// result: Err(e), -// }, -// } -// } -// } +pub struct APIResult { + pub text: String, + pub result: Result, +} + +impl serde::Deserialize<'a>> APIResult { + pub async fn new(response: kxio::net::Result) -> Self { + match response { + Ok(response) => { + let text = response.text().await.unwrap_or_default(); + let text = if text.is_empty() { s!("null") } else { text }; + let result = serde_json::from_str::(&text) + .map_err(|e| e.to_string()) + .map_err(|e| { + e!("{e}: {text}"); + e + }) + .map_err(kxio::net::Error::from); + Self { text, result } + } + Err(e) => Self { + text: s!(""), + result: Err(e), + }, + } + } +} diff --git a/src/config.rs b/src/config.rs index 235abbd..11f874d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,6 +3,13 @@ use color_eyre::Result; use crate::{f, s, Ctx, NAME}; +#[derive(Clone, Debug, derive_more::From, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize)] +pub struct TrelloConfig { + pub api_key: String, + pub api_secret: String, + pub board_name: String, +} + #[derive( Clone, Debug, @@ -14,7 +21,9 @@ use crate::{f, s, Ctx, NAME}; derive_more::AsRef, serde::Deserialize, )] -pub struct AppConfig {} +pub struct AppConfig { + pub trello: TrelloConfig, +} impl AppConfig { pub fn load(ctx: &Ctx) -> Result { let file = ctx.fs.base().join(f!("{NAME}.toml")); diff --git a/src/lib.rs b/src/lib.rs index 1db038a..31a267a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,12 +4,12 @@ use std::path::PathBuf; use clap::Parser; use kxio::{fs::FileSystem, net::Net}; -mod api_result; +// mod api_result; mod config; mod init; mod macros; mod template; -mod trello; +// mod trello; #[cfg(test)] mod tests; diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 156165c..3e32a11 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -9,19 +9,41 @@ use crate::{config::AppConfig, f, NAME}; mod config { use super::*; + use crate::config::TrelloConfig; + use crate::s; + #[test] fn load_config() { //given let fs = given::a_filesystem(); let file = fs.base().join(f!("{}.toml", NAME)); - fs.file(&file).write("").expect("write file"); + fs.file(&file) + .write( + [ + "[trello]", + "api_key = \"trello-api-key\"", + "api_secret = \"trello-api-secret\"", + "board_name = \"trello-board-name\"", + ] + .join("\n"), + ) + .expect("write file"); let ctx = given::a_context(fs.as_real(), given::a_network().into()); //when let_assert!(Ok(config) = AppConfig::load(&ctx)); //then - assert_eq!(config, AppConfig {}); + assert_eq!( + config, + AppConfig { + trello: TrelloConfig { + api_key: s!("trello-api-key"), + api_secret: s!("trello-api-secret"), + board_name: s!("trello-board-name"), + } + } + ); } } diff --git a/src/trello/api/members.rs b/src/trello/api/members.rs index 7c8d609..5217b14 100644 --- a/src/trello/api/members.rs +++ b/src/trello/api/members.rs @@ -1,54 +1,54 @@ // -// use kxio::net::Net; +use kxio::net::Net; -// use crate::api_result::APIResult; -// use crate::{ -// f, -// trello::{ -// types::{TrelloAuth, board::TrelloBoard}, -// url, -// }, -// }; -// -// /// Get lists from named board that Member belongs to -// /// -// /// Get Boards that Member belongs to -// /// https://developer.atlassian.com/cloud/trello/rest/api-group-members/#api-members-id-boards-get -// /// /members/{id}/boards -// /// -// /// Lists the boards that the user is a member of. -// /// -// /// Request -// /// -// /// Path parameters -// /// -// /// - id TrelloID REQUIRED -// /// -// /// -// /// Query parameters -// /// -// /// - fields string -// /// Default: all -// /// Valid values: id, name, desc, descData, closed, idMemberCreator, idOrganization, pinned, url, shortUrl, prefs, labelNames, starred, limits, memberships, enterpriseOwned -// /// -// /// - lists string -// /// Which lists to include with the boards. One of: all, closed, none, open -// /// Default: none -// /// Valid values: all, closed, none, open -// /// -// /// curl --request GET \ -// /// --url "https://api.trello.com/1/members/$TRELLO_USERNAME/boards?key=$TRELLO_KEY&token=$TRELLO_SECRET&lists=open" \ -// /// --header 'Accept: application/json' -// pub async fn get_boards_that_member_belongs_to( -// auth: &TrelloAuth, -// net: &Net, -// ) -> APIResult> { -// APIResult::new( -// net.get(url(f!("/members/{}/boards?lists=open", **auth.user()))) -// .headers(auth.into()) -// .header("Accept", "application/json") -// .send() -// .await, -// ) -// .await -// } +use crate::api_result::APIResult; +use crate::{ + f, + trello::{ + types::{auth::TrelloAuth, board::TrelloBoard}, + url, + }, +}; + +/// Get lists from named board that Member belongs to +/// +/// Get Boards that Member belongs to +/// https://developer.atlassian.com/cloud/trello/rest/api-group-members/#api-members-id-boards-get +/// /members/{id}/boards +/// +/// Lists the boards that the user is a member of. +/// +/// Request +/// +/// Path parameters +/// +/// - id TrelloID REQUIRED +/// +/// +/// Query parameters +/// +/// - fields string +/// Default: all +/// Valid values: id, name, desc, descData, closed, idMemberCreator, idOrganization, pinned, url, shortUrl, prefs, labelNames, starred, limits, memberships, enterpriseOwned +/// +/// - lists string +/// Which lists to include with the boards. One of: all, closed, none, open +/// Default: none +/// Valid values: all, closed, none, open +/// +/// curl --request GET \ +/// --url "https://api.trello.com/1/members/$TRELLO_USERNAME/boards?key=$TRELLO_KEY&token=$TRELLO_SECRET&lists=open" \ +/// --header 'Accept: application/json' +pub async fn get_boards_that_member_belongs_to( + auth: &TrelloAuth, + net: &Net, +) -> APIResult> { + APIResult::new( + net.get(url(f!("/members/{}/boards?lists=open", **auth.user()))) + .headers(auth.into()) + .header("Accept", "application/json") + .send() + .await, + ) + .await +} diff --git a/src/trello/api/tests/given.rs b/src/trello/api/tests/given.rs index 7e75fc9..7701e20 100644 --- a/src/trello/api/tests/given.rs +++ b/src/trello/api/tests/given.rs @@ -1,15 +1,16 @@ -// use kxio::net::MockNet; +// +use kxio::net::MockNet; -// use crate::trello::types::auth::{TrelloApiKey, TrelloApiSecret, TrelloAuth, TrelloUser}; +use crate::trello::types::auth::{TrelloApiKey, TrelloApiSecret, TrelloAuth, TrelloUser}; -// pub(crate) fn a_network() -> MockNet { -// kxio::net::mock() -// } +pub(crate) fn a_network() -> MockNet { + kxio::net::mock() +} -// pub(crate) fn an_auth() -> TrelloAuth { -// TrelloAuth::new( -// TrelloApiKey::new("foo"), -// TrelloApiSecret::new("bar"), -// TrelloUser::new("baz"), -// ) -// } +pub(crate) fn an_auth() -> TrelloAuth { + TrelloAuth::new( + TrelloApiKey::new("foo"), + TrelloApiSecret::new("bar"), + TrelloUser::new("baz"), + ) +} diff --git a/src/trello/api/tests/mod.rs b/src/trello/api/tests/mod.rs index cf0a2c5..474d599 100644 --- a/src/trello/api/tests/mod.rs +++ b/src/trello/api/tests/mod.rs @@ -1,59 +1,62 @@ // use super::*; +use super::*; mod given; -// type TestResult = color_eyre::Result<()>; +type TestResult = color_eyre::Result<()>; mod members { - // use std::collections::HashMap; - - // use kxio::net::StatusCode; - // use serde_json::json; - - // use crate::{ - // s, - // trello::{ - // // api::members::get_boards_that_member_belongs_to, - // types::{board::TrelloBoard, TrelloBoardId, TrelloBoardName}, - // }, - // }; - - // use super::*; - // - // #[tokio::test] - // async fn get_member_boards() -> TestResult { - // //given - // let net = given::a_network(); - // let auth = given::an_auth(); - // - // net.on() - // .get("https://api.trello.com/1/members/baz/boards?lists=open") - // .headers(HashMap::from([ - // ( - // s!("authorization"), - // s!("OAuth oauth_consumer_key=\"foo\", oauth_token=\"bar\""), - // ), - // (s!("accept"), s!("application/json")), - // ])) - // .respond(StatusCode::OK) - // .body(s!(json!([ - // {"id": "1", "name": "board-1", "lists":[]} - // ])))?; - // - // //when - // let result = get_boards_that_member_belongs_to(&auth, &net.into()).await; - // - // assert_eq!( - // result.result?, - // vec![TrelloBoard::new( - // TrelloBoardId::new("1"), - // TrelloBoardName::new("board-1"), - // vec![] - // )] - // ); - // - // //then - // Ok(()) - // } + use std::collections::HashMap; + + use kxio::net::StatusCode; + use serde_json::json; + + use crate::{ + s, + trello::{ + api::members::get_boards_that_member_belongs_to, + types::{board::TrelloBoard, TrelloBoardId, TrelloBoardName}, + }, + }; + + use super::*; + + #[tokio::test] + async fn get_member_boards() -> TestResult { + //given + let net = given::a_network(); + let auth = given::an_auth(); + + net.on() + .get("https://api.trello.com/1/members/baz/boards?lists=open") + .headers(HashMap::from([ + ( + s!("authorization"), + s!("OAuth oauth_consumer_key=\"foo\", oauth_token=\"bar\""), + ), + (s!("accept"), s!("application/json")), + ])) + .respond(StatusCode::OK) + .body(s!(json!([ + {"id": "1", "name": "board-1", "lists":[]} + ])))?; + + //when + let result = get_boards_that_member_belongs_to(&auth, &net.into()) + .await + .result?; + + assert_eq!( + result, + vec![TrelloBoard::new( + TrelloBoardId::new("1"), + TrelloBoardName::new("board-1"), + vec![] + )] + ); + + //then + Ok(()) + } } diff --git a/src/trello/mod.rs b/src/trello/mod.rs index 699da72..41660e0 100644 --- a/src/trello/mod.rs +++ b/src/trello/mod.rs @@ -5,10 +5,10 @@ pub mod types; #[cfg(test)] mod tests; -// use crate::f; +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}") -// } +pub fn url(path: impl Into) -> String { + let path = path.into(); + assert!(path.starts_with("/")); + f!("https://api.trello.com/1{path}") +}