feat(nextcloud): add command 'nextcloud card list'

This commit is contained in:
Paul Campbell 2024-11-30 18:04:48 +00:00
parent a86f3db4d9
commit 4c9a0eb2c6
8 changed files with 319 additions and 142 deletions

View file

@ -46,6 +46,8 @@ enum NextcloudCommand {
Board(NextcloudBoardCommand),
#[clap(subcommand)]
Stack(NextcloudStackCommand),
#[clap(subcommand)]
Card(NextcloudCardCommand),
}
#[derive(Parser, Debug)]
@ -64,6 +66,15 @@ enum NextcloudStackCommand {
},
}
#[derive(Parser, Debug)]
enum NextcloudCardCommand {
List {
#[clap(long, action = clap::ArgAction::SetTrue)]
dump: bool,
stack_id: i64,
},
}
#[derive(Parser, Debug)]
enum TrelloCommand {
#[clap(subcommand)]
@ -141,6 +152,10 @@ pub async fn run(ctx: Ctx) -> color_eyre::Result<()> {
Command::Nextcloud(NextcloudCommand::Stack(NextcloudStackCommand::List {
dump,
})) => nextcloud::stack::list(ctx, dump).await,
Command::Nextcloud(NextcloudCommand::Card(NextcloudCardCommand::List {
dump,
stack_id,
})) => nextcloud::card::list(ctx, dump, stack_id.into()).await,
}
}
}

24
src/nextcloud/card.rs Normal file
View file

@ -0,0 +1,24 @@
//
use crate::nextcloud::model::NextcloudStackId;
use crate::{p, FullCtx};
pub(crate) async fn list(
ctx: FullCtx,
dump: bool,
stack_id: NextcloudStackId,
) -> color_eyre::Result<()> {
let api_result = ctx
.deck_client()
.get_stack(ctx.cfg.nextcloud.board_id, stack_id)
.await;
if dump {
p!(ctx.prt, "{}", api_result.text);
} else {
let mut cards = api_result.result?.cards;
cards.sort_by_key(|card| card.title.clone());
cards
.iter()
.for_each(|card| p!(ctx.prt, "{}:{}", card.id, card.title));
}
Ok(())
}

View file

@ -2,12 +2,18 @@
use bytes::Bytes;
use kxio::net::{Net, ReqBuilder};
use crate::{api_result::APIResult, f, FullCtx};
use crate::nextcloud::model::{NextcloudHostname, NextcloudPassword, NextcloudUsername};
use model::{Board, Card, NextcloudBoardId, Stack};
use crate::{
api_result::APIResult,
f,
nextcloud::model::{
Board, Card, NextcloudBoardId, NextcloudHostname, NextcloudPassword, NextcloudStackId,
NextcloudUsername, Stack,
},
FullCtx,
};
pub mod board;
pub mod card;
pub mod model;
pub mod stack;
@ -102,6 +108,17 @@ impl<'ctx> DeckClient<'ctx> {
.await
}
pub async fn get_stack(
&self,
board_id: NextcloudBoardId,
stack_id: NextcloudStackId,
) -> APIResult<Stack> {
self.request(f!("boards/{board_id}/stacks/{stack_id}"), |net, url| {
net.get(url)
})
.await
}
pub async fn create_card(
&self,
board_id: i64,

View file

@ -141,9 +141,11 @@ pub struct Stack {
pub board_id: NextcloudBoardId,
#[serde(rename = "ETag")]
pub etag: NextcloudETag,
#[serde(default)]
pub cards: Vec<Card>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct Card {
pub id: NextcloudCardId,
pub title: NextcloudCardTitle,
@ -152,8 +154,10 @@ pub struct Card {
pub stack_id: NextcloudStackId,
pub order: NextcloudOrder,
pub archived: bool,
#[serde(default)]
pub due_date: Option<String>,
pub labels: Vec<NextcloudLabelId>,
#[serde(default)]
pub labels: Option<Vec<String>>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]

View file

@ -1,13 +1,18 @@
//
use kxio::net::StatusCode;
use kxio::{
fs::TempFileSystem,
net::{MockNet, StatusCode},
print::Printer,
};
use crate::{
config::NextcloudConfig,
config::{NextcloudConfig, TrelloConfig},
nextcloud::{
model::{
Board, NextcloudBoardColour, NextcloudBoardId, NextcloudBoardOwner,
NextcloudBoardTitle, NextcloudETag, NextcloudHostname, NextcloudOrder,
NextcloudPassword, NextcloudStackId, NextcloudStackTitle, NextcloudUsername, Stack,
Board, Card, NextcloudBoardColour, NextcloudBoardId, NextcloudBoardOwner,
NextcloudBoardTitle, NextcloudCardId, NextcloudCardTitle, NextcloudETag,
NextcloudHostname, NextcloudOrder, NextcloudPassword, NextcloudStackId,
NextcloudStackTitle, NextcloudUsername, Stack,
},
DeckClient,
},
@ -124,15 +129,7 @@ mod commands {
.expect("mock request");
let fs = given::a_filesystem();
let ctx = FullCtx {
fs: fs.as_real(),
net: mock_net.into(),
prt: given::a_printer(),
cfg: AppConfig {
trello: given::a_trello_config(),
nextcloud: given::a_nextcloud_config(),
},
};
let ctx = given::a_full_context(mock_net, fs);
let deck_client = DeckClient::new(&ctx);
//when
@ -174,15 +171,7 @@ mod commands {
.expect("mock request");
let fs = given::a_filesystem();
let ctx = FullCtx {
fs: fs.as_real(),
net: mock_net.into(),
prt: given::a_printer(),
cfg: AppConfig {
trello: given::a_trello_config(),
nextcloud: given::a_nextcloud_config(),
},
};
let ctx = given::a_full_context(mock_net, fs);
let deck_client = DeckClient::new(&ctx);
//when
@ -200,32 +189,135 @@ mod commands {
title: NextcloudStackTitle::new("Done"),
order: NextcloudOrder::new(2),
board_id: NextcloudBoardId::new(1),
etag: NextcloudETag::new("97592874d17017ef4f620c9c2a490086")
etag: NextcloudETag::new("97592874d17017ef4f620c9c2a490086"),
cards: vec![Card {
id: NextcloudCardId::new(322),
title: NextcloudCardTitle::new("Lunch: Soup & Toast"),
description: Some(s!("")),
stack_id: NextcloudStackId::new(3),
order: NextcloudOrder::new(0),
archived: false,
due_date: None,
labels: Some(vec![])
}]
},
Stack {
id: NextcloudStackId::new(2),
title: NextcloudStackTitle::new("Doing"),
order: NextcloudOrder::new(1),
board_id: NextcloudBoardId::new(1),
etag: NextcloudETag::new("3da05f904903c88450b79e4f8f6e2160")
etag: NextcloudETag::new("3da05f904903c88450b79e4f8f6e2160"),
cards: vec![
Card {
id: NextcloudCardId::new(319),
title: NextcloudCardTitle::new("That"),
description: Some(s!("")),
stack_id: NextcloudStackId::new(2),
order: NextcloudOrder::new(0),
archived: false,
due_date: None,
labels: Some(vec![])
},
Card {
id: NextcloudCardId::new(323),
title: NextcloudCardTitle::new(
"Second lunch: Poached Egg & Toasted Muffin"
),
description: Some(s!("")),
stack_id: NextcloudStackId::new(2),
order: NextcloudOrder::new(1),
archived: false,
due_date: None,
labels: Some(vec![])
}
]
},
Stack {
id: NextcloudStackId::new(1),
title: NextcloudStackTitle::new("To do"),
order: NextcloudOrder::new(0),
board_id: NextcloudBoardId::new(1),
etag: NextcloudETag::new("b567d287210fa4d9b108ac68d5b087c1")
etag: NextcloudETag::new("b567d287210fa4d9b108ac68d5b087c1"),
cards: vec![
Card {
id: NextcloudCardId::new(318),
title: NextcloudCardTitle::new("This"),
description: Some(s!("")),
stack_id: NextcloudStackId::new(1),
order: NextcloudOrder::new(0),
archived: false,
due_date: None,
labels: Some(vec![])
},
Card {
id: NextcloudCardId::new(321),
title: NextcloudCardTitle::new("Breakfast: Cereal"),
description: Some(s!("")),
stack_id: NextcloudStackId::new(1),
order: NextcloudOrder::new(1),
archived: false,
due_date: None,
labels: Some(vec![])
}
]
}
]
);
}
}
mod card {
use super::*;
#[tokio::test]
async fn list() {
//given
let mock_net = kxio::net::mock();
mock_net
.on()
.get("https://host-name/index.php/apps/deck/api/v1.0/boards/2/stacks/1")
.basic_auth("username", Some("password"))
.respond(StatusCode::OK)
.body(include_str!("../tests/responses/nextcloud-card-list.json"))
.expect("mock request");
let fs = given::a_filesystem();
let ctx = given::a_full_context(mock_net, fs);
let deck_client = DeckClient::new(&ctx);
//when
let result = deck_client
.get_stack(ctx.cfg.nextcloud.board_id, 1.into())
.await
.result
.expect("get stacks");
assert_eq!(
result,
Stack {
id: NextcloudStackId::new(3),
title: NextcloudStackTitle::new("Done"),
order: NextcloudOrder::new(2),
board_id: NextcloudBoardId::new(1),
etag: NextcloudETag::new("dda386b3b247d7b4bd8917e19d38c01b"),
cards: vec![Card {
id: NextcloudCardId::new(322),
title: NextcloudCardTitle::new("Lunch: Soup & Toast"),
description: Some(s!("")),
stack_id: NextcloudStackId::new(3),
order: NextcloudOrder::new(0),
archived: false,
due_date: None,
labels: None
}]
}
);
}
}
}
mod given {
use kxio::{fs::TempFileSystem, print::Printer};
use crate::{config::TrelloConfig, s};
use super::*;
@ -258,15 +350,15 @@ mod given {
}
}
// pub(crate) fn a_full_context(mock_net: MockNet, fs: TempFileSystem) -> FullCtx {
// FullCtx {
// fs: fs.as_real(),
// net: mock_net.into(),
// prt: given::a_printer(),
// cfg: AppConfig {
// trello: given::a_trello_config(),
// nextcloud: given::a_nextcloud_config(),
// },
// }
// }
pub(crate) fn a_full_context(mock_net: MockNet, fs: TempFileSystem) -> FullCtx {
FullCtx {
fs: fs.as_real(),
net: mock_net.into(),
prt: given::a_printer(),
cfg: AppConfig {
trello: given::a_trello_config(),
nextcloud: given::a_nextcloud_config(),
},
}
}
}

View file

@ -114,6 +114,11 @@ mod template {
mod given {
use super::*;
use kxio::{
fs::{FileSystem, TempFileSystem},
net::{MockNet, Net},
print::Printer,
};
pub fn a_context(fs: FileSystem, net: Net, prt: Printer) -> Ctx {
Ctx { fs, net, prt }
@ -130,32 +135,4 @@ mod given {
pub fn a_printer() -> Printer {
kxio::print::test()
}
// pub fn a_config() -> AppConfig {
// AppConfig {
// trello: a_trello_config(),
// nextcloud: a_nextcloud_config(),
// }
// }
// pub fn a_trello_config() -> TrelloConfig {
// TrelloConfig {
// api_key: s!("trello-api-key").into(),
// api_secret: s!("trello-api-secret").into(),
// board_name: s!("Trello Platform Changes").into(),
// }
// }
// pub fn a_nextcloud_config() -> NextcloudConfig {
// let hostname = s!("nextcloud.example.org").into();
// let username = s!("username").into();
// let password = s!("password").into();
// let board_id = NextcloudBoardId::new(2);
// NextcloudConfig {
// hostname,
// username,
// password,
// board_id,
// }
// }
}

View file

@ -0,0 +1,47 @@
{
"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": "pcampbell",
"createdAt": 1733043472,
"labels": null,
"assignedUsers": [
{
"id": 25,
"participant": {
"primaryKey": "pcampbell",
"uid": "pcampbell",
"displayname": "Paul Campbell",
"type": 0
},
"cardId": 322,
"type": 0
}
],
"attachments": null,
"attachmentCount": 0,
"owner": "pcampbell",
"order": 0,
"archived": false,
"done": null,
"duedate": null,
"deletedAt": 0,
"commentsUnread": 0,
"commentsCount": 0,
"ETag": "dda386b3b247d7b4bd8917e19d38c01b",
"overdue": 0
}
],
"order": 2,
"ETag": "dda386b3b247d7b4bd8917e19d38c01b"
}

View file

@ -35,7 +35,7 @@ mod board {
// //then
// assert_eq!(result, Some(&board));
// }
mod commands {
mod commands {
mod board {
use crate::trello::{
api::boards::TrelloBoards as _,
@ -110,4 +110,5 @@ mod commands {
assert_eq!(result, Some(&board));
}
}
}
}