feat: add command 'nextcloud board get'
This commit is contained in:
parent
3552faf7a9
commit
aac5ff3f5f
8 changed files with 419 additions and 1 deletions
|
@ -75,7 +75,7 @@ As part of building the import server, the following commands exercise each oper
|
|||
- [x] trello attachment get - includes download url
|
||||
- [x] trello attachment save - saves to disk
|
||||
- [x] nextcloud deck get - includes list of boards
|
||||
- [ ] nextcloud board get (was stack list)
|
||||
- [x] nextcloud board get - includes list of stacks
|
||||
- [ ] nextcloud stack get (was card list)
|
||||
- [x] nextcloud card create
|
||||
- [x] nextcloud card add-label
|
||||
|
|
38
src/nextcloud/board.rs
Normal file
38
src/nextcloud/board.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
use clap::Parser;
|
||||
|
||||
use crate::execute::Execute;
|
||||
use crate::nextcloud::model::NextcloudBoardId;
|
||||
use crate::{p, FullCtx};
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub enum NextcloudBoardCommand {
|
||||
Get {
|
||||
#[clap(long, action = clap::ArgAction::SetTrue)]
|
||||
dump: bool,
|
||||
board_id: i64,
|
||||
},
|
||||
}
|
||||
|
||||
impl Execute for NextcloudBoardCommand {
|
||||
async fn execute(&self, ctx: &FullCtx) -> color_eyre::Result<()> {
|
||||
match self {
|
||||
Self::Get { dump, board_id } => {
|
||||
let api_result = ctx
|
||||
.deck_client()
|
||||
.get_stacks(NextcloudBoardId::new(*board_id))
|
||||
.await;
|
||||
if *dump {
|
||||
p!(ctx.prt, "{}", api_result.text);
|
||||
} else {
|
||||
let mut stacks = api_result.result?;
|
||||
stacks.sort_by(|a, b| a.title.cmp(&b.title));
|
||||
stacks.into_iter().for_each(|stack| {
|
||||
p!(ctx.prt, "{}:{}", stack.id, stack.title);
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,8 @@ pub(crate) struct DeckClient<'ctx> {
|
|||
password: &'ctx NextcloudPassword,
|
||||
}
|
||||
|
||||
impl DeckClient<'_> {}
|
||||
|
||||
// Uses the API described here: https://deck.readthedocs.io/en/stable/API/#cards
|
||||
impl<'ctx> DeckClient<'ctx> {
|
||||
pub fn new(ctx: &'ctx FullCtx) -> Self {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//
|
||||
use clap::Parser;
|
||||
|
||||
use crate::nextcloud::board::NextcloudBoardCommand;
|
||||
use crate::{
|
||||
execute::Execute,
|
||||
nextcloud::{
|
||||
|
@ -12,6 +13,7 @@ use crate::{
|
|||
FullCtx,
|
||||
};
|
||||
|
||||
pub(crate) mod board;
|
||||
pub(crate) mod card;
|
||||
pub(crate) mod client;
|
||||
pub(crate) mod deck;
|
||||
|
@ -33,6 +35,8 @@ pub enum NextcloudCommand {
|
|||
#[clap(subcommand)]
|
||||
Deck(NextcloudDeckCommand),
|
||||
#[clap(subcommand)]
|
||||
Board(NextcloudBoardCommand),
|
||||
#[clap(subcommand)]
|
||||
Stack(NextcloudStackCommand),
|
||||
#[clap(subcommand)]
|
||||
Card(NextcloudCardCommand),
|
||||
|
@ -41,6 +45,7 @@ impl Execute for NextcloudCommand {
|
|||
async fn execute(&self, ctx: &FullCtx) -> color_eyre::Result<()> {
|
||||
match self {
|
||||
NextcloudCommand::Deck(cmd) => cmd.execute(ctx).await,
|
||||
NextcloudCommand::Board(cmd) => cmd.execute(ctx).await,
|
||||
NextcloudCommand::Stack(cmd) => cmd.execute(ctx).await,
|
||||
NextcloudCommand::Card(cmd) => cmd.execute(ctx).await,
|
||||
}
|
||||
|
|
78
src/nextcloud/tests/board/get.rs
Normal file
78
src/nextcloud/tests/board/get.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
use crate::execute::Execute;
|
||||
use crate::nextcloud::board::NextcloudBoardCommand;
|
||||
use crate::nextcloud::card::NextcloudCardCommand;
|
||||
use crate::nextcloud::stack::NextcloudStackCommand;
|
||||
use crate::nextcloud::NextcloudCommand;
|
||||
use crate::Command;
|
||||
//
|
||||
use super::*;
|
||||
|
||||
#[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 = nextcloud_config.board_id;
|
||||
|
||||
let mock_net = given::a_network();
|
||||
mock_net
|
||||
.on()
|
||||
.get(crate::f!(
|
||||
"https://{hostname}/index.php/apps/deck/api/v1.0/boards/{board_id}/stacks",
|
||||
))
|
||||
.respond(StatusCode::OK)
|
||||
.body(include_str!(
|
||||
"../../../tests/responses/nextcloud-board-get.json"
|
||||
))
|
||||
.expect("mock request");
|
||||
|
||||
given::a_full_context(fs, mock_net)
|
||||
}
|
||||
|
||||
#[rstest::rstest]
|
||||
#[test_log::test(tokio::test)]
|
||||
async fn dump(ctx: FullCtx) {
|
||||
//given
|
||||
let prt = ctx.prt.clone();
|
||||
let prt = prt.as_test().unwrap();
|
||||
let board_id = ctx.cfg.nextcloud.board_id;
|
||||
|
||||
//when
|
||||
Command::Nextcloud(NextcloudCommand::Board(NextcloudBoardCommand::Get {
|
||||
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-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::Board(NextcloudBoardCommand::Get {
|
||||
dump: false,
|
||||
board_id: ctx.cfg.nextcloud.board_id.into(),
|
||||
}))
|
||||
.execute(&ctx)
|
||||
.await
|
||||
.expect("execute");
|
||||
|
||||
//then
|
||||
let output = prt.output();
|
||||
assert_eq!(output.trim(), ["2:Doing\n3:Done\n1:To do"].join("\n"));
|
||||
}
|
4
src/nextcloud/tests/board/mod.rs
Normal file
4
src/nextcloud/tests/board/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
//
|
||||
use super::*;
|
||||
|
||||
mod get;
|
|
@ -29,6 +29,7 @@ use crate::{
|
|||
AppConfig, FullCtx,
|
||||
};
|
||||
|
||||
mod board;
|
||||
mod card;
|
||||
mod deck;
|
||||
mod stack;
|
||||
|
|
290
src/tests/responses/nextcloud-board-get.json
Normal file
290
src/tests/responses/nextcloud-board-get.json
Normal file
|
@ -0,0 +1,290 @@
|
|||
[
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Done",
|
||||
"boardId": 1,
|
||||
"deletedAt": 0,
|
||||
"lastModified": 1733515991,
|
||||
"cards": [
|
||||
{
|
||||
"id": 322,
|
||||
"title": "Lunch: Soup & Toast",
|
||||
"description": "",
|
||||
"stackId": 3,
|
||||
"type": "plain",
|
||||
"lastModified": 1733515991,
|
||||
"lastEditor": null,
|
||||
"createdAt": 1733043472,
|
||||
"labels": [
|
||||
{
|
||||
"id": 4,
|
||||
"title": "Later",
|
||||
"color": "F1DB50",
|
||||
"boardId": 1,
|
||||
"cardId": 322,
|
||||
"lastModified": 1670965629,
|
||||
"ETag": "983f87848dc9c18d0aee63e7ee0fc83f"
|
||||
}
|
||||
],
|
||||
"assignedUsers": [
|
||||
{
|
||||
"id": 25,
|
||||
"participant": {
|
||||
"primaryKey": "pcampbell",
|
||||
"uid": "pcampbell",
|
||||
"displayname": "Paul Campbell",
|
||||
"type": 0
|
||||
},
|
||||
"cardId": 322,
|
||||
"type": 0
|
||||
}
|
||||
],
|
||||
"attachments": null,
|
||||
"attachmentCount": 0,
|
||||
"owner": {
|
||||
"primaryKey": "pcampbell",
|
||||
"uid": "pcampbell",
|
||||
"displayname": "Paul Campbell",
|
||||
"type": 0
|
||||
},
|
||||
"order": 0,
|
||||
"archived": false,
|
||||
"done": null,
|
||||
"duedate": null,
|
||||
"deletedAt": 0,
|
||||
"commentsUnread": 0,
|
||||
"commentsCount": 0,
|
||||
"ETag": "dda386b3b247d7b4bd8917e19d38c01b",
|
||||
"overdue": 0
|
||||
}
|
||||
],
|
||||
"order": 2,
|
||||
"ETag": "dda386b3b247d7b4bd8917e19d38c01b"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Doing",
|
||||
"boardId": 1,
|
||||
"deletedAt": 0,
|
||||
"lastModified": 1733695323,
|
||||
"cards": [
|
||||
{
|
||||
"id": 319,
|
||||
"title": "That",
|
||||
"description": "",
|
||||
"stackId": 2,
|
||||
"type": "plain",
|
||||
"lastModified": 1733335979,
|
||||
"lastEditor": null,
|
||||
"createdAt": 1732610551,
|
||||
"labels": [],
|
||||
"assignedUsers": [],
|
||||
"attachments": null,
|
||||
"attachmentCount": 1,
|
||||
"owner": {
|
||||
"primaryKey": "pcampbell",
|
||||
"uid": "pcampbell",
|
||||
"displayname": "Paul Campbell",
|
||||
"type": 0
|
||||
},
|
||||
"order": 0,
|
||||
"archived": false,
|
||||
"done": null,
|
||||
"duedate": null,
|
||||
"deletedAt": 0,
|
||||
"commentsUnread": 0,
|
||||
"commentsCount": 0,
|
||||
"ETag": "79aeb703494e67736cc66b35053d258d",
|
||||
"overdue": 0
|
||||
},
|
||||
{
|
||||
"id": 323,
|
||||
"title": "Second lunch: Poached Egg & Toasted Muffin",
|
||||
"description": "",
|
||||
"stackId": 2,
|
||||
"type": "plain",
|
||||
"lastModified": 1733695323,
|
||||
"lastEditor": null,
|
||||
"createdAt": 1733043481,
|
||||
"labels": [],
|
||||
"assignedUsers": [
|
||||
{
|
||||
"id": 26,
|
||||
"participant": {
|
||||
"primaryKey": "pcampbell",
|
||||
"uid": "pcampbell",
|
||||
"displayname": "Paul Campbell",
|
||||
"type": 0
|
||||
},
|
||||
"cardId": 323,
|
||||
"type": 0
|
||||
}
|
||||
],
|
||||
"attachments": null,
|
||||
"attachmentCount": 0,
|
||||
"owner": {
|
||||
"primaryKey": "pcampbell",
|
||||
"uid": "pcampbell",
|
||||
"displayname": "Paul Campbell",
|
||||
"type": 0
|
||||
},
|
||||
"order": 1,
|
||||
"archived": false,
|
||||
"done": null,
|
||||
"duedate": null,
|
||||
"deletedAt": 0,
|
||||
"commentsUnread": 0,
|
||||
"commentsCount": 0,
|
||||
"ETag": "9de45fc7d68507f1eaef462e90e6414c",
|
||||
"overdue": 0
|
||||
}
|
||||
],
|
||||
"order": 1,
|
||||
"ETag": "9de45fc7d68507f1eaef462e90e6414c"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"title": "To do",
|
||||
"boardId": 1,
|
||||
"deletedAt": 0,
|
||||
"lastModified": 1734115321,
|
||||
"cards": [
|
||||
{
|
||||
"id": 318,
|
||||
"title": "This",
|
||||
"description": "",
|
||||
"stackId": 1,
|
||||
"type": "plain",
|
||||
"lastModified": 1733049748,
|
||||
"lastEditor": null,
|
||||
"createdAt": 1732610548,
|
||||
"labels": [],
|
||||
"assignedUsers": [],
|
||||
"attachments": null,
|
||||
"attachmentCount": 1,
|
||||
"owner": {
|
||||
"primaryKey": "pcampbell",
|
||||
"uid": "pcampbell",
|
||||
"displayname": "Paul Campbell",
|
||||
"type": 0
|
||||
},
|
||||
"order": 0,
|
||||
"archived": false,
|
||||
"done": null,
|
||||
"duedate": null,
|
||||
"deletedAt": 0,
|
||||
"commentsUnread": 0,
|
||||
"commentsCount": 0,
|
||||
"ETag": "e5007451d88799e3e3d3581cbcb30210",
|
||||
"overdue": 0
|
||||
},
|
||||
{
|
||||
"id": 321,
|
||||
"title": "Breakfast: Cereal",
|
||||
"description": "",
|
||||
"stackId": 1,
|
||||
"type": "plain",
|
||||
"lastModified": 1734115321,
|
||||
"lastEditor": null,
|
||||
"createdAt": 1733043461,
|
||||
"labels": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Finished",
|
||||
"color": "31CC7C",
|
||||
"boardId": 1,
|
||||
"cardId": 321,
|
||||
"lastModified": 1670965629,
|
||||
"ETag": "983f87848dc9c18d0aee63e7ee0fc83f"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Finished",
|
||||
"color": "31CC7C",
|
||||
"boardId": 1,
|
||||
"cardId": 321,
|
||||
"lastModified": 1670965629,
|
||||
"ETag": "983f87848dc9c18d0aee63e7ee0fc83f"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Finished",
|
||||
"color": "31CC7C",
|
||||
"boardId": 1,
|
||||
"cardId": 321,
|
||||
"lastModified": 1670965629,
|
||||
"ETag": "983f87848dc9c18d0aee63e7ee0fc83f"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "To review",
|
||||
"color": "317CCC",
|
||||
"boardId": 1,
|
||||
"cardId": 321,
|
||||
"lastModified": 1670965629,
|
||||
"ETag": "983f87848dc9c18d0aee63e7ee0fc83f"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "To review",
|
||||
"color": "317CCC",
|
||||
"boardId": 1,
|
||||
"cardId": 321,
|
||||
"lastModified": 1670965629,
|
||||
"ETag": "983f87848dc9c18d0aee63e7ee0fc83f"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Action needed",
|
||||
"color": "FF7A66",
|
||||
"boardId": 1,
|
||||
"cardId": 321,
|
||||
"lastModified": 1670965629,
|
||||
"ETag": "983f87848dc9c18d0aee63e7ee0fc83f"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "Later",
|
||||
"color": "F1DB50",
|
||||
"boardId": 1,
|
||||
"cardId": 321,
|
||||
"lastModified": 1670965629,
|
||||
"ETag": "983f87848dc9c18d0aee63e7ee0fc83f"
|
||||
}
|
||||
],
|
||||
"assignedUsers": [
|
||||
{
|
||||
"id": 24,
|
||||
"participant": {
|
||||
"primaryKey": "pcampbell",
|
||||
"uid": "pcampbell",
|
||||
"displayname": "Paul Campbell",
|
||||
"type": 0
|
||||
},
|
||||
"cardId": 321,
|
||||
"type": 0
|
||||
}
|
||||
],
|
||||
"attachments": null,
|
||||
"attachmentCount": 0,
|
||||
"owner": {
|
||||
"primaryKey": "pcampbell",
|
||||
"uid": "pcampbell",
|
||||
"displayname": "Paul Campbell",
|
||||
"type": 0
|
||||
},
|
||||
"order": 1,
|
||||
"archived": false,
|
||||
"done": null,
|
||||
"duedate": null,
|
||||
"deletedAt": 0,
|
||||
"commentsUnread": 0,
|
||||
"commentsCount": 0,
|
||||
"ETag": "9acdd42135c0347968891d2a073b87be",
|
||||
"overdue": 0
|
||||
}
|
||||
],
|
||||
"order": 0,
|
||||
"ETag": "9acdd42135c0347968891d2a073b87be"
|
||||
}
|
||||
]
|
Loading…
Reference in a new issue