diff --git a/README.md b/README.md index 9a03ccf..5babc9b 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ As part of building the import server, the following commands exercise each oper - [x] trello card get - includes list of attachments - [x] trello attachment get - includes download url - [x] trello attachment save - saves to disk -- [ ] nextcloud deck get (was board list) +- [x] nextcloud deck get - includes list of boards - [ ] nextcloud board get (was stack list) - [ ] nextcloud stack get (was card list) - [x] nextcloud card create diff --git a/src/nextcloud/board.rs b/src/nextcloud/board.rs deleted file mode 100644 index 4a234b2..0000000 --- a/src/nextcloud/board.rs +++ /dev/null @@ -1,35 +0,0 @@ -// -use clap::Parser; - -use crate::execute::Execute; -use crate::{p, FullCtx}; - -#[derive(Parser, Debug)] -pub(crate) enum NextcloudBoardCommand { - List { - #[clap(long, action = clap::ArgAction::SetTrue)] - dump: bool, - }, -} - -impl Execute for NextcloudBoardCommand { - async fn execute(self, ctx: FullCtx) -> color_eyre::Result<()> { - match self { - Self::List { dump } => list(&ctx, dump).await, - } - } -} - -pub(crate) async fn list(ctx: &FullCtx, dump: bool) -> color_eyre::Result<()> { - let api_result = ctx.deck_client().get_boards().await; - if dump { - p!(ctx.prt, "{}", api_result.text); - } else { - let mut boards = api_result.result?; - boards.sort_by_key(|stack| stack.title.clone()); - boards - .iter() - .for_each(|stack| p!(ctx.prt, "{}:{}", stack.id, stack.title)); - } - Ok(()) -} diff --git a/src/nextcloud/deck.rs b/src/nextcloud/deck.rs new file mode 100644 index 0000000..32cb3eb --- /dev/null +++ b/src/nextcloud/deck.rs @@ -0,0 +1,33 @@ +// +use clap::Parser; + +use crate::execute::Execute; +use crate::{p, FullCtx}; + +#[derive(Parser, Debug)] +pub(crate) enum NextcloudDeckCommand { + Get { + #[clap(long, action = clap::ArgAction::SetTrue)] + dump: bool, + }, +} + +impl Execute for NextcloudDeckCommand { + async fn execute(self, ctx: FullCtx) -> color_eyre::Result<()> { + match self { + Self::Get { dump } => { + let api_result = ctx.deck_client().get_boards().await; + if dump { + p!(ctx.prt, "{}", api_result.text); + } else { + let mut boards = api_result.result?; + boards.sort_by_key(|stack| stack.title.clone()); + boards + .iter() + .for_each(|stack| p!(ctx.prt, "{}:{}", stack.id, stack.title)); + } + Ok(()) + } + } + } +} diff --git a/src/nextcloud/mod.rs b/src/nextcloud/mod.rs index 7d0aa23..99414a5 100644 --- a/src/nextcloud/mod.rs +++ b/src/nextcloud/mod.rs @@ -8,9 +8,8 @@ use crate::{ execute::Execute, f, nextcloud::{ - board::NextcloudBoardCommand, - card::Create, - card::NextcloudCardCommand, + card::{Create, NextcloudCardCommand}, + deck::NextcloudDeckCommand, model::{ Board, Card, NextcloudBoardId, NextcloudHostname, NextcloudPassword, NextcloudStackId, NextcloudUsername, Stack, @@ -20,9 +19,9 @@ use crate::{ FullCtx, }; -mod board; pub(crate) mod card; pub(crate) mod client; +pub(crate) mod deck; pub(crate) mod model; mod stack; @@ -166,7 +165,7 @@ impl<'ctx> DeckClient<'ctx> { #[derive(Parser, Debug)] pub(crate) enum NextcloudCommand { #[clap(subcommand)] - Board(NextcloudBoardCommand), + Deck(NextcloudDeckCommand), #[clap(subcommand)] Stack(NextcloudStackCommand), #[clap(subcommand)] @@ -175,7 +174,7 @@ pub(crate) enum NextcloudCommand { impl Execute for NextcloudCommand { async fn execute(self, ctx: FullCtx) -> color_eyre::Result<()> { match self { - NextcloudCommand::Board(cmd) => cmd.execute(ctx).await, + NextcloudCommand::Deck(cmd) => cmd.execute(ctx).await, NextcloudCommand::Stack(cmd) => cmd.execute(ctx).await, NextcloudCommand::Card(cmd) => cmd.execute(ctx).await, } diff --git a/src/nextcloud/tests/deck/get.rs b/src/nextcloud/tests/deck/get.rs new file mode 100644 index 0000000..f9ba1ca --- /dev/null +++ b/src/nextcloud/tests/deck/get.rs @@ -0,0 +1,82 @@ +// +use super::*; + +#[rstest::fixture] +fn ctx() -> FullCtx { + let fs = given::a_filesystem(); + let nextcloud_config = given::a_nextcloud_config(); + + let mock_net = given::a_network(); + mock_net + .on() + .get(crate::f!( + "https://{}/index.php/apps/deck/api/v1.0/boards", + nextcloud_config.hostname, + )) + .respond(StatusCode::OK) + .body(include_str!( + "../../../tests/responses/nextcloud-deck-get.json" + )) + .expect("mock request"); + + FullCtx { + fs: fs.as_real(), + net: mock_net.into(), + prt: given::a_printer(), + cfg: AppConfig { + trello: given::a_trello_config(), + nextcloud: nextcloud_config, + }, + } +} + +#[rstest::rstest] +#[test_log::test(tokio::test)] +async fn dump(ctx: FullCtx) { + //given + let prt = ctx.prt.clone(); + let prt = prt.as_test().unwrap(); + + //when + Command::Nextcloud(NextcloudCommand::Deck(NextcloudDeckCommand::Get { + dump: true, + })) + .execute(ctx) + .await + .expect("execute"); + + //then + let output = prt.output(); + assert_eq!( + output.trim(), + include_str!("../../../tests/responses/nextcloud-deck-get.json").trim() + ); +} + +#[rstest::rstest] +#[test_log::test(tokio::test)] +async fn no_dump(ctx: FullCtx) { + //given + let prt = ctx.prt.clone(); + let prt = prt.as_test().unwrap(); + + //when + Command::Nextcloud(NextcloudCommand::Deck(NextcloudDeckCommand::Get { + dump: false, + })) + .execute(ctx) + .await + .expect("execute"); + + //then + let output = prt.output(); + assert_eq!( + output.trim(), + [ + "4:4 Published: Cossmass Infinities", + "5:Fulfilment: Cossmass Infinities", + "1:Personal Board" + ] + .join("\n") + ); +} diff --git a/src/nextcloud/tests/deck/mod.rs b/src/nextcloud/tests/deck/mod.rs new file mode 100644 index 0000000..2563f63 --- /dev/null +++ b/src/nextcloud/tests/deck/mod.rs @@ -0,0 +1,4 @@ +// +use super::*; + +mod get; diff --git a/src/nextcloud/tests/mod.rs b/src/nextcloud/tests/mod.rs index 8e404e8..5229654 100644 --- a/src/nextcloud/tests/mod.rs +++ b/src/nextcloud/tests/mod.rs @@ -30,4 +30,5 @@ use crate::{ }; mod card; +mod deck; mod stack; diff --git a/src/tests/responses/nextcloud-deck-get.json b/src/tests/responses/nextcloud-deck-get.json new file mode 100644 index 0000000..cf5faff --- /dev/null +++ b/src/tests/responses/nextcloud-deck-get.json @@ -0,0 +1,86 @@ +[ + { + "id": 1, + "title": "Personal Board", + "owner": { + "primaryKey": "pcampbell", + "uid": "pcampbell", + "displayname": "Paul Campbell", + "type": 0 + }, + "color": "0087C5", + "archived": false, + "labels": [], + "acl": [], + "permissions": { + "PERMISSION_READ": true, + "PERMISSION_EDIT": true, + "PERMISSION_MANAGE": true, + "PERMISSION_SHARE": true + }, + "users": [], + "shared": 0, + "stacks": [], + "activeSessions": [], + "deletedAt": 0, + "lastModified": 1733695323, + "settings": [], + "ETag": "9de45fc7d68507f1eaef462e90e6414c" + }, + { + "id": 4, + "title": "4 Published: Cossmass Infinities", + "owner": { + "primaryKey": "pcampbell", + "uid": "pcampbell", + "displayname": "Paul Campbell", + "type": 0 + }, + "color": "ff0000", + "archived": true, + "labels": [], + "acl": [], + "permissions": { + "PERMISSION_READ": true, + "PERMISSION_EDIT": true, + "PERMISSION_MANAGE": true, + "PERMISSION_SHARE": true + }, + "users": [], + "shared": 0, + "stacks": [], + "activeSessions": [], + "deletedAt": 0, + "lastModified": 1699798570, + "settings": [], + "ETag": "5e0fe035f3b95672da3cba633086be37" + }, + { + "id": 5, + "title": "Fulfilment: Cossmass Infinities", + "owner": { + "primaryKey": "pcampbell", + "uid": "pcampbell", + "displayname": "Paul Campbell", + "type": 0 + }, + "color": "ff0000", + "archived": true, + "labels": [], + "acl": [], + "permissions": { + "PERMISSION_READ": true, + "PERMISSION_EDIT": true, + "PERMISSION_MANAGE": true, + "PERMISSION_SHARE": true + }, + "users": [], + "shared": 0, + "stacks": [], + "activeSessions": [], + "deletedAt": 0, + "lastModified": 1699798567, + "settings": [], + "ETag": "90e2f9d53c5f6ec83088425d4486e54d" + } +]