zohohorrorshow/models/tasklist/
mod.rs1use serde::{Deserialize, Serialize};
2use tracing::warn;
3
4use crate::errors::*;
5use crate::request::{FilterOptions, ModelRequest, RequestDetails, RequestParameters};
6use std::collections::HashMap;
7
8use super::IntString;
9
10pub mod task;
11
12pub(crate) fn model_path(
13 portal: impl std::fmt::Display,
14 project: impl std::fmt::Display,
15) -> String {
16 format!("portal/{}/projects/{}/tasklists/", portal, project)
17}
18
19#[derive(Clone, Debug)]
20pub struct TasklistRequest(RequestDetails);
21
22impl TasklistRequest {
23 pub fn new(access_token: &str, model_path: &str, id: Option<i64>) -> Self {
24 TasklistRequest(RequestDetails::new(access_token, model_path, id))
25 }
26
27 pub fn iter_get(self) -> TasklistIterator {
28 TasklistIterator::new(self)
29 }
30}
31
32impl ModelRequest for TasklistRequest {
33 fn uri(&self) -> String {
34 self.0.uri()
35 }
36
37 fn params(&self) -> Option<HashMap<String, String>> {
38 self.0.params()
39 }
40
41 fn access_token(&self) -> String {
42 self.0.access_token()
43 }
44
45 fn filter(mut self, param: (impl FilterOptions + std::fmt::Display)) -> Self {
46 self.0 = self.0.filter(¶m);
47 self
48 }
49}
50
51impl RequestParameters for TasklistRequest {
52 type ModelCollection = ZohoTasklists;
53 type NewModel = NewTasklist;
54}
55
56pub enum Filter {
57 Index(usize),
58 Range(i8),
59 Flag(Flag),
60 Milestone(usize),
61}
62
63#[derive(Clone, Debug, Deserialize, Serialize)]
64pub enum Flag {
65 #[serde(rename = "internal")]
66 Internal,
67 #[serde(rename = "external")]
68 External,
69}
70
71impl std::fmt::Display for Flag {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 let str_rep = match self {
74 Flag::Internal => "internal",
75 Flag::External => "external",
76 };
77
78 write!(f, "{}", str_rep)
79 }
80}
81
82impl FilterOptions for Filter {
83 fn key(&self) -> String {
84 match self {
85 Filter::Index(_) => "index".to_owned(),
86 Filter::Range(_) => "range".to_owned(),
87 Filter::Flag(_) => "flag".to_owned(),
88 Filter::Milestone(_) => "milestone_id".to_owned(),
89 }
90 }
91}
92
93impl std::fmt::Display for Filter {
94 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95 let str_rep = match self {
96 Filter::Index(index) => index.to_string(),
97 Filter::Range(range) => range.to_string(),
98 Filter::Flag(flag) => flag.to_string(),
99 Filter::Milestone(id) => id.to_string(),
100 };
101
102 write!(f, "{}", str_rep)
103 }
104}
105
106#[derive(Clone, Debug, Serialize, Deserialize, Default)]
107pub struct ZohoTasklists {
108 #[serde(rename = "tasklists")]
109 pub tasklists: Vec<Tasklist>,
110}
111
112#[derive(Clone, Debug, Deserialize, Serialize)]
113pub struct NewTasklist {
114 name: String,
115 milestone_id: usize,
116 flag: Flag,
117}
118
119#[derive(Clone, Debug, Serialize, Deserialize, Default)]
121pub struct Tasklist {
122 #[serde(rename = "id")]
123 pub id: i64,
124 #[serde(rename = "name")]
125 pub name: String,
126 #[serde(rename = "milestone")]
127 pub milestone: Milestone,
128 #[serde(rename = "completed")]
129 pub completed: bool,
130 #[serde(rename = "created_time")]
131 pub created_time: String,
132 #[serde(rename = "created_time_long")]
133 pub created_time_long: i64,
134 #[serde(rename = "rolled")]
135 pub rolled: bool,
136 #[serde(rename = "sequence")]
137 pub sequence: i64,
138 #[serde(rename = "view_type")]
139 pub view_type: Option<String>,
140 #[serde(rename = "link")]
141 pub link: TasklistLink,
142}
143
144#[derive(Clone, Debug, Serialize, Deserialize, Default)]
145pub struct TasklistLink {
146 #[serde(rename = "self")]
147 pub link: Link,
148 #[serde(rename = "task")]
149 pub task: Link,
150}
151
152#[derive(Clone, Debug, Serialize, Deserialize, Default)]
153pub struct Link {
154 #[serde(rename = "url")]
155 pub url: String,
156}
157
158#[derive(Clone, Debug, Serialize, Deserialize, Default)]
159pub struct Milestone {
160 #[serde(rename = "id")]
161 pub id: i64,
162 #[serde(rename = "link")]
163 pub link: Option<MilestoneLink>,
164 #[serde(rename = "name")]
165 pub name: String,
166 #[serde(rename = "owner_name")]
167 pub owner_name: Option<String>,
168 #[serde(rename = "owner_id")]
169 pub owner_id: Option<IntString>,
170 #[serde(rename = "flag")]
171 pub flag: Option<String>,
172 }
183
184#[derive(Clone, Debug, Serialize, Deserialize, Default)]
185pub struct MilestoneLink {
186 #[serde(rename = "self")]
187 pub link: Link,
188 #[serde(rename = "status")]
189 pub status: Link,
190}
191
192#[derive(Clone, Debug)]
193pub struct TasklistIterator {
194 pub items: <Vec<Tasklist> as IntoIterator>::IntoIter,
195 pub last_full: bool,
196 pub request: TasklistRequest,
197 pub start_index: usize,
198}
199
200impl TasklistIterator {
201 pub fn new(request: TasklistRequest) -> TasklistIterator {
202 TasklistIterator {
203 items: Vec::new().into_iter(),
204 last_full: true,
205 request,
206 start_index: 0,
207 }
208 }
209
210 fn range(&self) -> i8 {
211 match self.request.params() {
212 Some(params) => match params.get("range") {
213 Some(range_string) => range_string.parse::<i8>().unwrap_or(100),
214 None => 100,
215 },
216 None => 100,
217 }
218 }
219
220 pub fn try_next(&mut self) -> Result<Option<Tasklist>> {
221 if let Some(tasklist) = self.items.next() {
223 return Ok(Some(tasklist));
224 }
225
226 if !self.last_full {
229 return Ok(None);
230 }
231
232 let returned_tasklists = self
233 .request
234 .clone()
235 .filter(Filter::Index(self.start_index))
236 .get();
237
238 match returned_tasklists {
239 Ok(Some(tasklist_list)) => {
240 self.last_full = tasklist_list.tasklists.len() as i8 == self.range();
241
242 self.start_index += tasklist_list.tasklists.len();
243
244 self.items = tasklist_list.tasklists.into_iter();
245
246 Ok(self.items.next())
247 }
248 Ok(None) => {
249 self.last_full = false;
250 Ok(None)
251 }
252 Err(err) => {
253 self.last_full = false;
254 Err(err)
255 }
256 }
257 }
258}
259
260impl Iterator for TasklistIterator {
261 type Item = Result<Tasklist>;
262
263 fn next(&mut self) -> Option<Self::Item> {
264 match self.try_next() {
265 Ok(Some(val)) => Some(Ok(val)),
266 Ok(None) => None,
267 Err(err) => {
268 warn!(
269 "Fetching Tasklists from Zoho experienced an error: {:?}",
270 err
271 );
272 None
273 }
274 }
275 }
276}