From 2625ce44c02609d27c62840186dc59293e7375ec Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Thu, 19 Dec 2024 20:29:21 +0000 Subject: [PATCH] feat(nextcloud): add command 'nextcloud board labels' --- src/nextcloud/board.rs | 28 +++++ src/nextcloud/client.rs | 5 + src/nextcloud/tests/board/labels.rs | 85 ++++++++++++++ src/nextcloud/tests/board/mod.rs | 1 + src/nextcloud/tests/mod.rs | 15 ++- .../responses/nextcloud-board-labels.json | 104 ++++++++++++++++++ 6 files changed, 230 insertions(+), 8 deletions(-) create mode 100644 src/nextcloud/tests/board/labels.rs create mode 100644 src/tests/responses/nextcloud-board-labels.json diff --git a/src/nextcloud/board.rs b/src/nextcloud/board.rs index 6290be5..c874315 100644 --- a/src/nextcloud/board.rs +++ b/src/nextcloud/board.rs @@ -7,6 +7,11 @@ use crate::{p, FullCtx}; #[derive(Parser, Debug)] pub enum NextcloudBoardCommand { + Labels { + #[clap(long, action = clap::ArgAction::SetTrue)] + dump: bool, + board_id: i64, + }, Get { #[clap(long, action = clap::ArgAction::SetTrue)] dump: bool, @@ -17,6 +22,29 @@ pub enum NextcloudBoardCommand { impl Execute for NextcloudBoardCommand { async fn execute(&self, ctx: &FullCtx) -> color_eyre::Result<()> { match self { + Self::Labels { dump, board_id } => { + let api_result = ctx + .deck_client() + .get_board(NextcloudBoardId::new(*board_id)) + .await; + if *dump { + p!(ctx.prt, "{}", api_result.text); + } else { + let mut labels = api_result.result?.labels; + labels.sort_by(|a, b| a.title.cmp(&b.title)); + labels.into_iter().for_each(|label| { + p!( + ctx.prt, + "{}:{}:{}:{}", + board_id, + label.id, + label.color, + label.title + ); + }); + } + Ok(()) + } Self::Get { dump, board_id } => { let api_result = ctx .deck_client() diff --git a/src/nextcloud/client.rs b/src/nextcloud/client.rs index dd7a602..a3f97cd 100644 --- a/src/nextcloud/client.rs +++ b/src/nextcloud/client.rs @@ -119,6 +119,11 @@ impl<'ctx> DeckClient<'ctx> { self.request("boards", |net, url| net.get(url)).await } + pub(crate) async fn get_board(&self, board_id: NextcloudBoardId) -> APIResult { + self.request(f!("boards/{board_id}"), |net, url| net.get(url)) + .await + } + pub(crate) async fn get_stacks(&self, board_id: NextcloudBoardId) -> APIResult> { self.request(f!("boards/{board_id}/stacks"), |net, url| net.get(url)) .await diff --git a/src/nextcloud/tests/board/labels.rs b/src/nextcloud/tests/board/labels.rs new file mode 100644 index 0000000..d476ae8 --- /dev/null +++ b/src/nextcloud/tests/board/labels.rs @@ -0,0 +1,85 @@ +// +use super::*; + +#[rstest::fixture] +fn board_id() -> NextcloudBoardId { + NextcloudBoardId::new(1) +} + +#[rstest::fixture] +fn ctx() -> FullCtx { + let fs = given::a_filesystem(); + + let nextcloud_config = given::a_nextcloud_config(); + + let hostname = &nextcloud_config.hostname; + let board_id = board_id(); + + let mock_net = given::a_network(); + mock_net + .on() + .get(crate::f!( + "{hostname}/index.php/apps/deck/api/v1.0/boards/{board_id}", + )) + .respond(StatusCode::OK) + .body(include_str!( + "../../../tests/responses/nextcloud-board-labels.json" + )) + .expect("mock request"); + + given::a_full_context(fs, mock_net) +} + +#[rstest::rstest] +#[test_log::test(tokio::test)] +async fn dump(ctx: FullCtx, board_id: NextcloudBoardId) { + //given + let prt = ctx.prt.clone(); + let prt = prt.as_test().unwrap(); + + //when + Command::Nextcloud(NextcloudCommand::Board(NextcloudBoardCommand::Labels { + dump: true, + board_id: board_id.into(), + })) + .execute(&ctx) + .await + .expect("execute"); + + //then + let output = prt.output(); + assert_eq!( + output.trim(), + include_str!("../../../tests/responses/nextcloud-board-labels.json").trim() + ); +} + +#[rstest::rstest] +#[test_log::test(tokio::test)] +async fn no_dump(ctx: FullCtx, board_id: NextcloudBoardId) { + //given + let prt = ctx.prt.clone(); + let prt = prt.as_test().unwrap(); + + //when + Command::Nextcloud(NextcloudCommand::Board(NextcloudBoardCommand::Labels { + dump: false, + board_id: board_id.into(), + })) + .execute(&ctx) + .await + .expect("execute"); + + //then + let output = prt.output(); + assert_eq!( + output.trim(), + [ + "1:3:FF7A66:Action needed", + "1:1:31CC7C:Finished", + "1:4:F1DB50:Later", + "1:2:317CCC:To review" + ] + .join("\n") + ); +} diff --git a/src/nextcloud/tests/board/mod.rs b/src/nextcloud/tests/board/mod.rs index 2563f63..6d7165a 100644 --- a/src/nextcloud/tests/board/mod.rs +++ b/src/nextcloud/tests/board/mod.rs @@ -2,3 +2,4 @@ use super::*; mod get; +mod labels; diff --git a/src/nextcloud/tests/mod.rs b/src/nextcloud/tests/mod.rs index ef2fd03..82b3c41 100644 --- a/src/nextcloud/tests/mod.rs +++ b/src/nextcloud/tests/mod.rs @@ -8,24 +8,23 @@ use kxio::{ use pretty_assertions::assert_eq as assert_peq; use serde_json::json; -use crate::execute::Execute; -use crate::nextcloud::card::NextcloudCardCommand; -use crate::nextcloud::deck::NextcloudDeckCommand; -use crate::nextcloud::NextcloudCommand; -use crate::Command; use crate::{ + execute::Execute, nextcloud::{ + board::NextcloudBoardCommand, + card::NextcloudCardCommand, + deck::NextcloudDeckCommand, model::{ Card, Label, NextcloudBoardId, NextcloudCardId, NextcloudCardTitle, NextcloudETag, NextcloudHostname, NextcloudLabelId, NextcloudOrder, NextcloudPassword, NextcloudStackId, NextcloudStackTitle, NextcloudUsername, Stack, }, - NextcloudConfig, + stack::NextcloudStackCommand, + NextcloudCommand, NextcloudConfig, }, s, tests::given, - trello::TrelloConfig, - AppConfig, FullCtx, + AppConfig, Command, FullCtx, }; mod board; diff --git a/src/tests/responses/nextcloud-board-labels.json b/src/tests/responses/nextcloud-board-labels.json new file mode 100644 index 0000000..78d0aaf --- /dev/null +++ b/src/tests/responses/nextcloud-board-labels.json @@ -0,0 +1,104 @@ +{ + "id": 1, + "title": "Personal Board", + "owner": { + "primaryKey": "pcampbell", + "uid": "pcampbell", + "displayname": "Paul Campbell", + "type": 0 + }, + "color": "0087C5", + "archived": false, + "labels": [ + { + "id": 1, + "title": "Finished", + "color": "31CC7C", + "boardId": 1, + "cardId": null, + "lastModified": 1670965629, + "ETag": "983f87848dc9c18d0aee63e7ee0fc83f" + }, + { + "id": 2, + "title": "To review", + "color": "317CCC", + "boardId": 1, + "cardId": null, + "lastModified": 1670965629, + "ETag": "983f87848dc9c18d0aee63e7ee0fc83f" + }, + { + "id": 3, + "title": "Action needed", + "color": "FF7A66", + "boardId": 1, + "cardId": null, + "lastModified": 1670965629, + "ETag": "983f87848dc9c18d0aee63e7ee0fc83f" + }, + { + "id": 4, + "title": "Later", + "color": "F1DB50", + "boardId": 1, + "cardId": null, + "lastModified": 1670965629, + "ETag": "983f87848dc9c18d0aee63e7ee0fc83f" + } + ], + "acl": [], + "permissions": { + "PERMISSION_READ": true, + "PERMISSION_EDIT": true, + "PERMISSION_MANAGE": true, + "PERMISSION_SHARE": true + }, + "users": [ + { + "primaryKey": "pcampbell", + "uid": "pcampbell", + "displayname": "Paul Campbell", + "type": 0 + } + ], + "stacks": [ + { + "id": 3, + "title": "Done", + "boardId": 1, + "deletedAt": 0, + "lastModified": 1733515991, + "order": 2, + "ETag": "dda386b3b247d7b4bd8917e19d38c01b" + }, + { + "id": 1, + "title": "To do", + "boardId": 1, + "deletedAt": 0, + "lastModified": 1734639912, + "order": 0, + "ETag": "72a19db972245af551058eb5506adf68" + }, + { + "id": 2, + "title": "Doing", + "boardId": 1, + "deletedAt": 0, + "lastModified": 1733695323, + "order": 1, + "ETag": "9de45fc7d68507f1eaef462e90e6414c" + } + ], + "activeSessions": [ + "pcampbell" + ], + "deletedAt": 0, + "lastModified": 1734639912, + "settings": { + "notify-due": "assigned", + "calendar": true + }, + "ETag": "72a19db972245af551058eb5506adf68" +}