// use std::collections::HashMap; use std::path::PathBuf; use color_eyre::eyre::Context; use kxio::net::{Net, ReqBuilder}; use crate::trello::model::{TrelloAttachment, TrelloAttachmentId}; use crate::{ api_result::APIResult, f, s, trello::model::{ board::TrelloBoard, card::{TrelloLongCard, TrelloShortCard}, TrelloBoardId, TrelloCardId, TrelloListId, }, FullCtx, }; pub(crate) struct TrelloClient<'ctx> { ctx: &'ctx FullCtx, } impl<'ctx> TrelloClient<'ctx> { fn url(&self, path: impl Into) -> String { let path = path.into(); assert!(path.starts_with("/")); f!("https://api.trello.com/1{path}") } fn auth_headers(&self) -> HashMap { let api_key = &self.ctx.cfg.trello.api_key; let api_secret = &self.ctx.cfg.trello.api_secret; HashMap::from([( s!("Authorization"), f!(r#"OAuth oauth_consumer_key="{api_key}", oauth_token="{api_secret}""#,), )]) } fn common_headers(&self) -> HashMap { let api_key = &self.ctx.cfg.trello.api_key; let api_secret = &self.ctx.cfg.trello.api_secret; HashMap::from([ (s!("accept"), s!("application/json")), (s!("content-type"), s!("application/json")), ( s!("Authorization"), f!(r#"OAuth oauth_consumer_key="{api_key}", oauth_token="{api_secret}""#,), ), ]) } 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)) .headers(self.common_headers()) .send() .await, &self.ctx.prt, ) .await } pub(crate) async fn save_attachment( &self, card_id: &TrelloCardId, attachment_id: &TrelloAttachmentId, file_name: Option, ) -> color_eyre::Result { let attachment = self.card_attachment(card_id, attachment_id).await.result?; let url = attachment.url; let file_name = file_name.unwrap_or_else(|| attachment.file_name.into()); crate::e!(self.ctx.prt, "file_name: {}", file_name.display()); crate::e!(self.ctx.prt, "base: {}", self.ctx.fs.base().display()); let file_name = self.ctx.fs.base().join(file_name); crate::e!(self.ctx.prt, "file_name: {}", file_name.display()); let resp = self .ctx .net .get(url) .headers(self.auth_headers()) .header("accept", "application/octet") .send() .await? .bytes() .await?; let file = self.ctx.fs.file(&file_name); file.write(resp).context("writing to disk")?; Ok(file_name) } } impl<'ctx> TrelloClient<'ctx> { // https://developer.atlassian.com/cloud/trello/rest/api-group-members/#api-members-id-boards-get pub(crate) async fn boards(&self) -> APIResult> { self.request("/members/me/boards?lists=open", |net, url| net.get(url)) .await } // https://developer.atlassian.com/cloud/trello/rest/api-group-boards/#api-boards-id-get pub(crate) async fn board(&self, board_id: &TrelloBoardId) -> APIResult { self.request(f!("/boards/{board_id}?lists=open"), |net, url| net.get(url)) .await } // https://developer.atlassian.com/cloud/trello/rest/api-group-lists/#api-lists-id-cards-get pub(crate) async fn list_cards( &self, list_id: &TrelloListId, ) -> APIResult> { self.request(f!("/lists/{list_id}/cards"), |net, url| net.get(url)) .await } // https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-get pub(crate) async fn card(&self, card_id: &TrelloCardId) -> APIResult { self.request(f!("/cards/{card_id}?attachments=true"), |net, url| { net.get(url) }) .await } // https://developer.atlassian.com/cloud/trello/rest/api-group-cards/#api-cards-id-attachments-idattachment-get pub(crate) async fn card_attachment( &self, card_id: &TrelloCardId, attachment_id: &TrelloAttachmentId, ) -> APIResult { self.request( f!("/cards/{card_id}/attachments/{attachment_id}"), |net, url| net.get(url), ) .await } } impl TrelloClient<'_> { pub(crate) fn new(ctx: &FullCtx) -> TrelloClient { TrelloClient { ctx } } }