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

This commit is contained in:
Paul Campbell 2024-12-08 14:39:03 +00:00
parent dd886d94ed
commit 3f0ecd5fd1
5 changed files with 147 additions and 19 deletions

View file

@ -82,6 +82,15 @@ enum NextcloudCardCommand {
stack_id: i64, stack_id: i64,
card_id: i64, card_id: i64,
}, },
Create {
#[clap(long, action = clap::ArgAction::SetTrue)]
dump: bool,
stack_id: i64,
#[clap(long)]
title: String,
#[clap(long)]
description: Option<String>,
},
} }
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -188,6 +197,23 @@ pub async fn run(ctx: Ctx) -> color_eyre::Result<()> {
stack_id, stack_id,
card_id, card_id,
} => nextcloud::card::get(ctx, dump, stack_id.into(), card_id.into()).await, } => nextcloud::card::get(ctx, dump, stack_id.into(), card_id.into()).await,
NextcloudCardCommand::Create {
dump,
stack_id,
title,
description,
} => {
nextcloud::card::create(
ctx,
nextcloud::card::Create {
dump,
stack_id,
title,
description,
},
)
.await
}
}, },
}, },
} }

View file

@ -43,3 +43,21 @@ pub(crate) async fn get(
} }
Ok(()) Ok(())
} }
pub(crate) struct Create {
pub dump: bool,
pub stack_id: i64,
pub title: String,
pub description: Option<String>,
}
pub(crate) async fn create(ctx: FullCtx, create: Create) -> color_eyre::Result<()> {
let dc = ctx.deck_client();
let apiresult = dc.create_card(&create).await;
if create.dump {
p!(ctx.prt, "{}", apiresult.text);
} else {
let card = apiresult.result?;
p!(ctx.prt, "{}:{}", card.id, card.title);
}
Ok(())
}

View file

@ -2,14 +2,12 @@
use bytes::Bytes; use bytes::Bytes;
use kxio::net::{Net, ReqBuilder}; use kxio::net::{Net, ReqBuilder};
use crate::{ use crate::{api_result::APIResult, f, FullCtx};
api_result::APIResult,
f, use card::Create;
nextcloud::model::{ use model::{
Board, Card, NextcloudBoardId, NextcloudHostname, NextcloudPassword, NextcloudStackId, Board, Card, NextcloudBoardId, NextcloudHostname, NextcloudPassword, NextcloudStackId,
NextcloudUsername, Stack, NextcloudUsername, Stack,
},
FullCtx,
}; };
pub mod board; pub mod board;
@ -26,6 +24,8 @@ pub(crate) struct DeckClient<'ctx> {
username: &'ctx NextcloudUsername, username: &'ctx NextcloudUsername,
password: &'ctx NextcloudPassword, password: &'ctx NextcloudPassword,
} }
// Uses the API described here: https://deck.readthedocs.io/en/stable/API/#cards
impl<'ctx> DeckClient<'ctx> { impl<'ctx> DeckClient<'ctx> {
pub fn new(ctx: &'ctx FullCtx) -> Self { pub fn new(ctx: &'ctx FullCtx) -> Self {
Self { Self {
@ -118,23 +118,20 @@ impl<'ctx> DeckClient<'ctx> {
.await .await
} }
pub async fn create_card( pub(crate) async fn create_card(&self, create: &Create) -> APIResult<Card> {
&self,
board_id: i64,
stack_id: i64,
title: &str,
description: Option<&str>,
) -> APIResult<Card> {
let mut body = serde_json::json!({ let mut body = serde_json::json!({
"title": title, "title": create.title,
}); });
if let Some(desc) = description { if let Some(desc) = &create.description {
body["description"] = serde_json::Value::String(desc.to_string()); body["description"] = serde_json::Value::String(desc.to_string());
} }
self.request_with_body( self.request_with_body(
format!("boards/{}/stacks/{}/cards", board_id, stack_id), format!(
"boards/{}/stacks/{}/cards",
self.ctx.cfg.nextcloud.board_id, create.stack_id
),
body.to_string(), body.to_string(),
|net, url| net.post(url), |net, url| net.post(url),
) )

View file

@ -284,8 +284,13 @@ mod commands {
} }
mod card { mod card {
use serde_json::json;
use super::*; use super::*;
use crate::nextcloud::model::{Label, NextcloudLabelId}; use crate::nextcloud::{
card::Create,
model::{Label, NextcloudLabelId},
};
#[tokio::test] #[tokio::test]
async fn list() { async fn list() {
@ -375,6 +380,61 @@ mod commands {
} }
); );
} }
#[tokio::test]
async fn create() {
//given
let mock_net = kxio::net::mock();
mock_net
.on()
.post("https://host-name/index.php/apps/deck/api/v1.0/boards/2/stacks/1/cards")
.basic_auth("username", Some("password"))
.header("accept", "application/json")
.header("content-type", "application/json")
.body(
json!({
"title":"my new card",
"description":"my new description"
})
.to_string(),
)
.respond(StatusCode::OK)
.body(include_str!(
"../tests/responses/nextcloud-card-create.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
.create_card(&Create {
dump: false,
stack_id: 1,
title: s!("my new card"),
description: Some(s!("my new description")),
})
.await
.result
.expect("get stacks");
assert_eq!(
result,
Card {
id: result.id,
title: NextcloudCardTitle::new("my new card"),
description: Some(s!("my new description")),
stack_id: NextcloudStackId::new(1),
order: NextcloudOrder::new(999),
archived: false,
due_date: None,
labels: None
}
);
}
} }
} }

View file

@ -0,0 +1,27 @@
{
"id": 331,
"title": "my new card",
"description": "my new description",
"descriptionPrev": null,
"stackId": 1,
"type": "plain",
"lastModified": 1733669509,
"lastEditor": null,
"createdAt": 1733669509,
"labels": null,
"assignedUsers": null,
"attachments": null,
"attachmentCount": null,
"owner": "pcampbell",
"order": 999,
"archived": false,
"done": null,
"duedate": null,
"notified": false,
"deletedAt": 0,
"commentsUnread": 0,
"commentsCount": 0,
"relatedStack": null,
"relatedBoard": null,
"ETag": "a3aee71091453c0e2055e4f2c31b611f"
}