1use crate::card::Card;
2use crate::client::Client;
3use crate::formatting::header;
4use crate::trello_error::TrelloError;
5use crate::trello_object::{Renderable, TrelloObject};
6
7use colored::*;
8use regex::RegexBuilder;
9use serde::Deserialize;
10
11type Result<T> = std::result::Result<T, TrelloError>;
12
13#[derive(Deserialize, Debug, Eq, PartialEq, Clone)]
15#[serde(rename_all = "camelCase")]
16pub struct List {
17 pub id: String,
18 pub name: String,
19 pub closed: bool,
20 pub cards: Option<Vec<Card>>,
21}
22
23impl TrelloObject for List {
24 fn get_type() -> String {
25 String::from("List")
26 }
27
28 fn get_name(&self) -> &str {
29 &self.name
30 }
31
32 fn get_fields() -> &'static [&'static str] {
33 &["id", "name", "closed"]
34 }
35}
36
37impl Renderable for List {
38 fn render(&self) -> String {
39 let title = header(&self.name, "-").bold().to_string();
40 let mut result: Vec<String> = vec![title];
41 if let Some(cards) = &self.cards {
42 for c in cards {
43 trace!("{:?}", c);
44 let mut lformat: Vec<String> = vec![];
45
46 if c.desc != "" {
47 lformat.push("[...]".dimmed().to_string());
48 }
49
50 if let Some(labels) = &c.labels {
51 for l in labels {
52 lformat.push(l.render());
53 }
54 }
55
56 let s = format!("* {} {}", &c.name, lformat.join(" "));
57
58 result.push(s.trim_end().to_string());
60 }
61 }
62 result.join("\n")
63 }
64}
65
66impl List {
67 pub fn new(id: &str, name: &str, cards: Option<Vec<Card>>) -> List {
68 List {
69 id: String::from(id),
70 name: String::from(name),
71 cards,
72 closed: false,
73 }
74 }
75
76 pub fn filter(&self, label_filter: &str) -> List {
112 let re = RegexBuilder::new(label_filter)
113 .case_insensitive(true)
114 .build()
115 .expect("Invalid regex for label filter");
116
117 let closure = |c: &Card| -> bool {
118 if let Some(labels) = &c.labels {
119 for label in labels {
120 if re.is_match(&label.name) {
121 return true;
122 }
123 }
124 }
125 false
126 };
127
128 let mut result = self.clone();
129 result.cards = if let Some(cards) = result.cards {
130 Some(cards.into_iter().filter(closure).collect())
131 } else {
132 None
133 };
134 result
135 }
136
137 pub fn create(client: &Client, board_id: &str, name: &str) -> Result<List> {
138 let url = client.get_trello_url("/1/lists/", &[])?;
139
140 let params = [("name", name), ("idBoard", board_id)];
141
142 Ok(reqwest::Client::new()
143 .post(url)
144 .form(¶ms)
145 .send()?
146 .error_for_status()?
147 .json()?)
148 }
149
150 pub fn open(client: &Client, list_id: &str) -> Result<List> {
151 let url = client.get_trello_url(&format!("/1/lists/{}", &list_id), &[])?;
152
153 let params = [("closed", "false")];
154
155 Ok(reqwest::Client::new()
156 .put(url)
157 .form(¶ms)
158 .send()?
159 .error_for_status()?
160 .json()?)
161 }
162
163 pub fn update(client: &Client, list: &List) -> Result<List> {
164 let url = client.get_trello_url(&format!("/1/lists/{}/", &list.id), &[])?;
165
166 let params = [("name", &list.name), ("closed", &list.closed.to_string())];
167
168 Ok(reqwest::Client::new()
169 .put(url)
170 .form(¶ms)
171 .send()?
172 .error_for_status()?
173 .json()?)
174 }
175
176 pub fn get_all(client: &Client, board_id: &str, cards: bool) -> Result<Vec<List>> {
177 let fields = List::get_fields().join(",");
178 let mut params = vec![("fields", fields.as_str())];
179
180 if cards {
181 params.push(("cards", "open"));
182 }
183
184 let url = client.get_trello_url(&format!("/1/boards/{}/lists", board_id), ¶ms)?;
185
186 Ok(reqwest::get(url)?.error_for_status()?.json()?)
187 }
188}