Skip to main content

trello/
list.rs

1use crate::card::Card;
2use crate::client::TrelloClient;
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// https://developers.trello.com/reference/#list-object
14#[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, headers: bool) -> String {
39        let title = header(&self.name, "-").bold().to_string();
40        let mut result: Vec<String> = match headers {
41            true => vec![title],
42            false => vec![],
43        };
44        if let Some(cards) = &self.cards {
45            for c in cards {
46                result.push(format!("* {}", c.simple_render()));
47            }
48        }
49        result.join("\n")
50    }
51
52    fn simple_render(&self) -> String {
53        self.name.clone()
54    }
55}
56
57impl List {
58    pub fn new(id: &str, name: &str, cards: Option<Vec<Card>>) -> List {
59        List {
60            id: String::from(id),
61            name: String::from(name),
62            cards,
63            closed: false,
64        }
65    }
66
67    /// Filters cards that match the given label_filter (As a regular expression).
68    /// Returns a copy of the original List, with the correct filtering applied.
69    ///
70    /// ```
71    /// use trello::{Card, Label, List};
72    ///
73    /// let list = List::new(
74    ///     "123",
75    ///     "TODO",
76    ///     Some(vec![
77    ///         Card::new("1", "Orange", "", Some(vec![Label::new("", "fruit", "")]), "", None),
78    ///         Card::new("2", "Green", "", None, "", None),
79    ///     ])
80    /// );
81    ///
82    /// assert_eq!(
83    ///     list.filter("idontexist"),
84    ///     List::new(
85    ///         "123",
86    ///         "TODO",
87    ///         Some(vec![]),
88    ///     )
89    /// );
90    ///
91    /// assert_eq!(
92    ///     list.filter("fruit"),
93    ///     List::new(
94    ///         "123",
95    ///         "TODO",
96    ///         Some(vec![
97    ///             Card::new("1", "Orange", "", Some(vec![Label::new("", "fruit", "")]), "", None)
98    ///         ])
99    ///     )
100    /// );
101    /// ```
102    pub fn filter(&self, label_filter: &str) -> List {
103        let re = RegexBuilder::new(label_filter)
104            .case_insensitive(true)
105            .build()
106            .expect("Invalid regex for label filter");
107
108        let closure = |c: &Card| -> bool {
109            if let Some(labels) = &c.labels {
110                for label in labels {
111                    if re.is_match(&label.name) {
112                        return true;
113                    }
114                }
115            }
116            false
117        };
118
119        let mut result = self.clone();
120        result.cards = result
121            .cards
122            .map(|cards| cards.into_iter().filter(closure).collect());
123        result
124    }
125
126    pub fn create(client: &TrelloClient, board_id: &str, name: &str) -> Result<List> {
127        let url = client.config.get_trello_url("/1/lists/", &[])?;
128
129        let params = [("name", name), ("idBoard", board_id)];
130
131        Ok(client
132            .client
133            .post(url)
134            .form(&params)
135            .send()?
136            .error_for_status()?
137            .json()?)
138    }
139
140    pub fn open(client: &TrelloClient, list_id: &str) -> Result<List> {
141        let url = client
142            .config
143            .get_trello_url(&format!("/1/lists/{}", &list_id), &[])?;
144
145        let params = [("closed", "false")];
146
147        Ok(client
148            .client
149            .put(url)
150            .form(&params)
151            .send()?
152            .error_for_status()?
153            .json()?)
154    }
155
156    pub fn update(client: &TrelloClient, list: &List) -> Result<List> {
157        let url = client
158            .config
159            .get_trello_url(&format!("/1/lists/{}/", &list.id), &[])?;
160
161        let params = [("name", &list.name), ("closed", &list.closed.to_string())];
162
163        Ok(client
164            .client
165            .put(url)
166            .form(&params)
167            .send()?
168            .error_for_status()?
169            .json()?)
170    }
171
172    pub fn get_all(client: &TrelloClient, board_id: &str, cards: bool) -> Result<Vec<List>> {
173        let fields = List::get_fields().join(",");
174        let mut params = vec![("fields", fields.as_str())];
175
176        if cards {
177            params.push(("cards", "open"));
178        }
179
180        let url = client
181            .config
182            .get_trello_url(&format!("/1/boards/{}/lists", board_id), &params)?;
183
184        Ok(client.client.get(url).send()?.error_for_status()?.json()?)
185    }
186}