use bytes::Bytes; // use clap::Parser; use kxio::net::{Net, ReqBuilder}; use crate::{ api_result::APIResult, execute::Execute, f, nextcloud::{ card::{Create, NextcloudCardCommand}, deck::NextcloudDeckCommand, model::{ Board, Card, NextcloudBoardId, NextcloudHostname, NextcloudPassword, NextcloudStackId, NextcloudUsername, Stack, }, stack::NextcloudStackCommand, }, FullCtx, }; pub(crate) mod card; pub(crate) mod client; pub(crate) mod deck; pub(crate) mod model; mod stack; #[cfg(test)] mod tests; pub(crate) struct DeckClient<'ctx> { ctx: &'ctx FullCtx, hostname: &'ctx NextcloudHostname, username: &'ctx NextcloudUsername, password: &'ctx NextcloudPassword, } // Uses the API described here: https://deck.readthedocs.io/en/stable/API/#cards impl<'ctx> DeckClient<'ctx> { pub fn new(ctx: &'ctx FullCtx) -> Self { Self { ctx, hostname: &ctx.cfg.nextcloud.hostname, username: &ctx.cfg.nextcloud.username, password: &ctx.cfg.nextcloud.password, } } fn url(&self, path: impl Into) -> String { f!( "https://{}/index.php/apps/deck/api/v1.0/{}", self.hostname, path.into() ) } async fn request serde::Deserialize<'a>>( &self, url: impl Into, custom: fn(&Net, String) -> ReqBuilder, ) -> APIResult { APIResult::new( custom(&self.ctx.net, self.url(url)) .basic_auth(self.username.as_str(), Some(self.password.as_str())) .header("accept", "application/json") .header("content-type", "application/json") .send() .await, &self.ctx.prt, ) .await } async fn request_with_body serde::Deserialize<'a>>( &self, url: impl Into, body: impl Into, custom: fn(&Net, String) -> ReqBuilder, ) -> APIResult { APIResult::new( custom(&self.ctx.net, self.url(url)) .basic_auth(self.username.as_str(), Some(self.password.as_str())) .header("accept", "application/json") .header("content-type", "application/json") .body(body) .send() .await, &self.ctx.prt, ) .await } pub async fn get_boards(&self) -> APIResult> { self.request("boards", |net, url| net.get(url)).await } pub async fn get_board(&self, board_id: NextcloudBoardId) -> APIResult { self.request(f!("boards/{board_id}"), |net, url| net.get(url)) .await } pub async fn create_board(&self, title: &str, color: &str) -> APIResult { self.request_with_body( "boards", serde_json::json!({ "title": title, "color": color }) .to_string(), |net, url| net.post(url), ) .await } pub async fn get_stacks(&self, board_id: NextcloudBoardId) -> APIResult> { self.request(f!("boards/{board_id}/stacks"), |net, url| net.get(url)) .await } pub async fn get_stack( &self, board_id: NextcloudBoardId, stack_id: NextcloudStackId, ) -> APIResult { self.request(f!("boards/{board_id}/stacks/{stack_id}"), |net, url| { net.get(url) }) .await } pub(crate) async fn create_card(&self, create: &Create) -> APIResult { let mut body = serde_json::json!({ "title": create.title, }); if let Some(desc) = &create.description { body["description"] = serde_json::Value::String(desc.to_string()); } self.request_with_body( format!( "boards/{}/stacks/{}/cards", self.ctx.cfg.nextcloud.board_id, create.stack_id ), body.to_string(), |net, url| net.post(url), ) .await } async fn get_card( &self, board_id: NextcloudBoardId, stack_id: NextcloudStackId, card_id: model::NextcloudCardId, ) -> APIResult { self.request( f!("boards/{board_id}/stacks/{stack_id}/cards/{card_id}"), |net, url| net.get(url), ) .await } } #[derive(Parser, Debug)] pub(crate) enum NextcloudCommand { #[clap(subcommand)] Deck(NextcloudDeckCommand), #[clap(subcommand)] Stack(NextcloudStackCommand), #[clap(subcommand)] Card(NextcloudCardCommand), } impl Execute for NextcloudCommand { async fn execute(self, ctx: FullCtx) -> color_eyre::Result<()> { match self { NextcloudCommand::Deck(cmd) => cmd.execute(ctx).await, NextcloudCommand::Stack(cmd) => cmd.execute(ctx).await, NextcloudCommand::Card(cmd) => cmd.execute(ctx).await, } } } #[derive(Clone, Debug, derive_more::From, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize)] pub struct NextcloudConfig { pub(crate) hostname: NextcloudHostname, pub(crate) username: NextcloudUsername, pub(crate) password: NextcloudPassword, pub(crate) board_id: NextcloudBoardId, }