trello-to-deck/src/nextcloud/mod.rs

191 lines
5.3 KiB
Rust
Raw Normal View History

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>) -> String {
f!(
"https://{}/index.php/apps/deck/api/v1.0/{}",
self.hostname,
path.into()
)
}
async fn request<T: for<'a> serde::Deserialize<'a>>(
&self,
url: impl Into<String>,
custom: fn(&Net, String) -> ReqBuilder,
) -> APIResult<T> {
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<T: for<'a> serde::Deserialize<'a>>(
&self,
url: impl Into<String>,
body: impl Into<Bytes>,
custom: fn(&Net, String) -> ReqBuilder,
) -> APIResult<T> {
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<Vec<Board>> {
self.request("boards", |net, url| net.get(url)).await
}
pub async fn get_board(&self, board_id: NextcloudBoardId) -> APIResult<Board> {
self.request(f!("boards/{board_id}"), |net, url| net.get(url))
.await
}
pub async fn create_board(&self, title: &str, color: &str) -> APIResult<Board> {
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<Vec<Stack>> {
self.request(f!("boards/{board_id}/stacks"), |net, url| net.get(url))
.await
2024-12-07 10:05:37 +00:00
}
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(crate) async fn create_card(&self, create: &Create) -> APIResult<Card> {
let mut body = serde_json::json!({
"title": create.title,
2024-12-07 10:05:37 +00:00
});
if let Some(desc) = &create.description {
body["description"] = serde_json::Value::String(desc.to_string());
2024-12-07 10:05:37 +00:00
}
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<Card> {
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,
}