1use crate::client::Client;
2use crate::formatting::header;
3use crate::label::Label;
4use crate::trello_error::TrelloError;
5use crate::trello_object::{Renderable, TrelloObject};
6
7use serde::Deserialize;
8use std::str::FromStr;
9
10type Result<T> = std::result::Result<T, TrelloError>;
11
12#[derive(Deserialize, Debug, Eq, PartialEq, Clone)]
14#[serde(rename_all = "camelCase")]
15pub struct Card {
16 pub id: String,
17 pub name: String,
18 pub desc: String,
19 pub closed: bool,
20 pub url: String,
21 pub labels: Option<Vec<Label>>,
22}
23
24impl TrelloObject for Card {
25 fn get_type() -> String {
26 String::from("Card")
27 }
28
29 fn get_name(&self) -> &str {
30 &self.name
31 }
32
33 fn get_fields() -> &'static [&'static str] {
34 &["id", "name", "desc", "labels", "closed", "url"]
35 }
36}
37
38impl Renderable for Card {
39 fn render(&self) -> String {
40 [header(&self.name, "=").as_str(), &self.desc].join("\n")
41 }
42}
43
44#[derive(Debug, PartialEq, Eq)]
45pub struct CardContents {
46 pub name: String,
47 pub desc: String,
48}
49
50impl FromStr for CardContents {
51 type Err = TrelloError;
52
53 fn from_str(value: &str) -> Result<CardContents> {
74 let mut contents = value.split('\n').collect::<Vec<&str>>();
76 trace!("{:?}", contents);
77
78 let mut name = vec![contents.remove(0)];
80
81 let mut found = false;
85 while !contents.is_empty() {
86 let line = contents.remove(0);
87
88 if line.chars().take_while(|c| c == &'=').collect::<String>() != line {
89 name.push(line);
90 } else {
91 found = true;
92 break;
93 }
94 }
95
96 if !found {
97 return Err(TrelloError::CardParse(
98 "Unable to find name delimiter '===='".to_owned(),
99 ));
100 }
101
102 let name = name.join("\n");
103 let desc = contents.join("\n");
105
106 Ok(CardContents { name, desc })
107 }
108}
109
110impl Card {
111 pub fn new(id: &str, name: &str, desc: &str, labels: Option<Vec<Label>>, url: &str) -> Card {
112 Card {
113 id: String::from(id),
114 name: String::from(name),
115 desc: String::from(desc),
116 url: String::from(url),
117 labels,
118 closed: false,
119 }
120 }
121
122 pub fn get(client: &Client, card_id: &str) -> Result<Card> {
123 let url = client.get_trello_url(&format!("/1/cards/{}", card_id), &[])?;
124
125 Ok(reqwest::get(url)?.error_for_status()?.json()?)
126 }
127
128 pub fn create(client: &Client, list_id: &str, card: &Card) -> Result<Card> {
129 let url = client.get_trello_url("/1/cards/", &[])?;
130
131 let params: [(&str, &str); 3] = [
132 ("name", &card.name),
133 ("desc", &card.desc),
134 ("idList", list_id),
135 ];
136
137 Ok(reqwest::Client::new()
138 .post(url)
139 .form(¶ms)
140 .send()?
141 .error_for_status()?
142 .json()?)
143 }
144
145 pub fn open(client: &Client, card_id: &str) -> Result<Card> {
146 let url = client.get_trello_url(&format!("/1/cards/{}", &card_id), &[])?;
147
148 let params = [("closed", "false")];
149
150 Ok(reqwest::Client::new()
151 .put(url)
152 .form(¶ms)
153 .send()?
154 .error_for_status()?
155 .json()?)
156 }
157
158 pub fn update(client: &Client, card: &Card) -> Result<Card> {
159 let url = client.get_trello_url(&format!("/1/cards/{}/", &card.id), &[])?;
160
161 let params = [
162 ("name", &card.name),
163 ("desc", &card.desc),
164 ("closed", &card.closed.to_string()),
165 ];
166
167 Ok(reqwest::Client::new()
168 .put(url)
169 .form(¶ms)
170 .send()?
171 .error_for_status()?
172 .json()?)
173 }
174
175 pub fn get_all(client: &Client, list_id: &str) -> Result<Vec<Card>> {
176 let url = client.get_trello_url(
177 &format!("/1/lists/{}/cards/", list_id),
178 &[("fields", &Card::get_fields().join(","))],
179 )?;
180 Ok(reqwest::get(url)?.error_for_status()?.json()?)
181 }
182}