use crate::client::TrelloClient;
use crate::formatting::header;
use crate::label::Label;
use crate::trello_error::TrelloError;
use crate::trello_object::{Renderable, TrelloObject};
use chrono::{DateTime, Utc};
use colored::Colorize;
use serde::Deserialize;
use std::str::FromStr;
type Result<T> = std::result::Result<T, TrelloError>;
#[derive(Deserialize, Debug, Eq, PartialEq, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Card {
pub id: String,
pub name: String,
pub desc: String,
pub closed: bool,
pub url: String,
pub labels: Option<Vec<Label>>,
pub due: Option<DateTime<Utc>>,
}
impl TrelloObject for Card {
fn get_type() -> String {
String::from("Card")
}
fn get_name(&self) -> &str {
&self.name
}
fn get_fields() -> &'static [&'static str] {
&["id", "name", "desc", "labels", "closed", "due", "url"]
}
}
impl Renderable for Card {
fn render(&self, headers: bool) -> String {
match headers {
true => [header(&self.name, "=").as_str(), &self.desc].join("\n"),
false => self.desc.clone(),
}
}
fn simple_render(&self) -> String {
let mut lformat: Vec<String> = vec![];
if self.closed {
lformat.push("[Closed]".red().to_string());
}
lformat.push(String::from(&self.name));
if !self.desc.is_empty() {
lformat.push("[...]".dimmed().to_string());
}
if let Some(labels) = &self.labels {
for l in labels {
lformat.push(l.simple_render());
}
}
lformat.join(" ").trim_end().to_string()
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct CardContents {
pub name: String,
pub desc: String,
}
impl FromStr for CardContents {
type Err = TrelloError;
fn from_str(value: &str) -> Result<CardContents> {
let mut contents = value.split('\n').collect::<Vec<&str>>();
trace!("{:?}", contents);
let mut name = vec![contents.remove(0)];
let mut found = false;
while !contents.is_empty() {
let line = contents.remove(0);
if line.chars().take_while(|c| c == &'=').collect::<String>() != line {
name.push(line);
} else {
found = true;
break;
}
}
if !found {
return Err(TrelloError::CardParse(
"Unable to find name delimiter '===='".to_owned(),
));
}
let name = name.join("\n");
let desc = contents.join("\n");
Ok(CardContents { name, desc })
}
}
impl Card {
pub fn new(
id: &str,
name: &str,
desc: &str,
labels: Option<Vec<Label>>,
url: &str,
due: Option<DateTime<Utc>>,
) -> Card {
Card {
id: String::from(id),
name: String::from(name),
desc: String::from(desc),
url: String::from(url),
labels,
due,
closed: false,
}
}
pub fn get(client: &TrelloClient, card_id: &str) -> Result<Card> {
let url = client
.config
.get_trello_url(&format!("/1/cards/{}", card_id), &[])?;
Ok(client.client.get(url).send()?.error_for_status()?.json()?)
}
pub fn create(client: &TrelloClient, list_id: &str, card: &Card) -> Result<Card> {
let url = client.config.get_trello_url("/1/cards/", &[])?;
let params: [(&str, &str); 3] = [
("name", &card.name),
("desc", &card.desc),
("idList", list_id),
];
Ok(client
.client
.post(url)
.form(¶ms)
.send()?
.error_for_status()?
.json()?)
}
pub fn open(client: &TrelloClient, card_id: &str) -> Result<Card> {
let url = client
.config
.get_trello_url(&format!("/1/cards/{}", &card_id), &[])?;
let params = [("closed", "false")];
Ok(client
.client
.put(url)
.form(¶ms)
.send()?
.error_for_status()?
.json()?)
}
pub fn update(client: &TrelloClient, card: &Card) -> Result<Card> {
let url = client
.config
.get_trello_url(&format!("/1/cards/{}/", &card.id), &[])?;
let params = [
("name", &card.name),
("desc", &card.desc),
("closed", &card.closed.to_string()),
];
Ok(client
.client
.put(url)
.form(¶ms)
.send()?
.error_for_status()?
.json()?)
}
pub fn change_list(client: &TrelloClient, card_id: &str, list_id: &str) -> Result<()> {
let url = client
.config
.get_trello_url(&format!("/1/cards/{}/", card_id), &[])?;
let params = [("idList", list_id)];
client
.client
.put(url)
.form(¶ms)
.send()?
.error_for_status()?;
Ok(())
}
pub fn get_all(client: &TrelloClient, list_id: &str) -> Result<Vec<Card>> {
let url = client.config.get_trello_url(
&format!("/1/lists/{}/cards/", list_id),
&[("fields", &Card::get_fields().join(","))],
)?;
Ok(client.client.get(url).send()?.error_for_status()?.json()?)
}
}