Skip to main content

redmine_api/api/
enumerations.rs

1//! Enumerations Rest API Endpoint definitions
2//!
3//! [Redmine Documentation](https://www.redmine.org/projects/redmine/wiki/Rest_Enumerations)
4//!
5//! - [x] all issue priorities endpoint
6//! - [x] all time entry activities endpoint
7//! - [x] all document categories endpoint
8
9use derive_builder::Builder;
10use reqwest::Method;
11use std::borrow::Cow;
12
13use crate::api::{Endpoint, NoPagination, ReturnsJsonResponse};
14
15/// a minimal type for Redmine issue priorities included in
16/// other Redmine objects
17#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
18pub struct IssuePriorityEssentials {
19    /// numeric id
20    pub id: u64,
21    /// display name
22    pub name: String,
23}
24
25impl From<IssuePriority> for IssuePriorityEssentials {
26    fn from(v: IssuePriority) -> Self {
27        Self {
28            id: v.id,
29            name: v.name,
30        }
31    }
32}
33
34impl From<&IssuePriority> for IssuePriorityEssentials {
35    fn from(v: &IssuePriority) -> Self {
36        Self {
37            id: v.id,
38            name: v.name.to_owned(),
39        }
40    }
41}
42
43/// a type for issue priority to use as an API return type
44///
45/// alternatively you can use your own type limited to the fields you need
46#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
47pub struct IssuePriority {
48    /// numeric id
49    pub id: u64,
50    /// display name
51    pub name: String,
52    /// whether this value is the default value
53    pub is_default: bool,
54    /// whether this value is active
55    pub active: bool,
56}
57
58/// The endpoint for all issue priorities
59#[derive(Debug, Clone, Builder)]
60#[builder(setter(strip_option))]
61#[expect(
62    clippy::empty_structs_with_brackets,
63    reason = "derive_builder requires named-field syntax"
64)]
65pub struct ListIssuePriorities {}
66
67impl ReturnsJsonResponse for ListIssuePriorities {}
68impl NoPagination for ListIssuePriorities {}
69
70impl ListIssuePriorities {
71    /// Create a builder for the endpoint.
72    #[must_use]
73    pub fn builder() -> ListIssuePrioritiesBuilder {
74        ListIssuePrioritiesBuilder::default()
75    }
76}
77
78impl Endpoint for ListIssuePriorities {
79    fn method(&self) -> Method {
80        Method::GET
81    }
82
83    fn endpoint(&self) -> Cow<'static, str> {
84        "enumerations/issue_priorities.json".into()
85    }
86}
87
88/// helper struct for outer layers with a issue_priorities field holding the inner data
89#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
90pub struct IssuePrioritiesWrapper<T> {
91    /// to parse JSON with issue_priorities key
92    pub issue_priorities: Vec<T>,
93}
94
95/// a minimal type for Redmine time entry activities included in
96/// other Redmine objects
97#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
98pub struct TimeEntryActivityEssentials {
99    /// numeric id
100    pub id: u64,
101    /// display name
102    pub name: String,
103}
104
105impl From<TimeEntryActivity> for TimeEntryActivityEssentials {
106    fn from(v: TimeEntryActivity) -> Self {
107        Self {
108            id: v.id,
109            name: v.name,
110        }
111    }
112}
113
114impl From<&TimeEntryActivity> for TimeEntryActivityEssentials {
115    fn from(v: &TimeEntryActivity) -> Self {
116        Self {
117            id: v.id,
118            name: v.name.to_owned(),
119        }
120    }
121}
122
123/// a type for time entry activity to use as an API return type
124///
125/// alternatively you can use your own type limited to the fields you need
126#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
127pub struct TimeEntryActivity {
128    /// numeric id
129    pub id: u64,
130    /// display name
131    pub name: String,
132    /// whether this value is the default value
133    pub is_default: bool,
134    /// whether this value is active
135    pub active: bool,
136}
137
138/// The endpoint for all time entry activities
139#[derive(Debug, Clone, Builder)]
140#[builder(setter(strip_option))]
141#[expect(
142    clippy::empty_structs_with_brackets,
143    reason = "derive_builder requires named-field syntax"
144)]
145pub struct ListTimeEntryActivities {}
146
147impl ReturnsJsonResponse for ListTimeEntryActivities {}
148impl NoPagination for ListTimeEntryActivities {}
149
150impl ListTimeEntryActivities {
151    /// Create a builder for the endpoint.
152    #[must_use]
153    pub fn builder() -> ListTimeEntryActivitiesBuilder {
154        ListTimeEntryActivitiesBuilder::default()
155    }
156}
157
158impl Endpoint for ListTimeEntryActivities {
159    fn method(&self) -> Method {
160        Method::GET
161    }
162
163    fn endpoint(&self) -> Cow<'static, str> {
164        "enumerations/time_entry_activities.json".into()
165    }
166}
167
168/// helper struct for outer layers with a time_entry_activities field holding the inner data
169#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
170pub struct TimeEntryActivitiesWrapper<T> {
171    /// to parse JSON with time_entry_activities key
172    pub time_entry_activities: Vec<T>,
173}
174
175/// a minimal type for Redmine document categories included in
176/// other Redmine objects
177#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
178pub struct DocumentCategoryEssentials {
179    /// numeric id
180    pub id: u64,
181    /// display name
182    pub name: String,
183}
184
185impl From<DocumentCategory> for DocumentCategoryEssentials {
186    fn from(v: DocumentCategory) -> Self {
187        Self {
188            id: v.id,
189            name: v.name,
190        }
191    }
192}
193
194impl From<&DocumentCategory> for DocumentCategoryEssentials {
195    fn from(v: &DocumentCategory) -> Self {
196        Self {
197            id: v.id,
198            name: v.name.to_owned(),
199        }
200    }
201}
202
203/// a type for document category to use as an API return type
204///
205/// alternatively you can use your own type limited to the fields you need
206#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
207pub struct DocumentCategory {
208    /// numeric id
209    pub id: u64,
210    /// display name
211    pub name: String,
212    /// whether this value is the default value
213    pub is_default: bool,
214    /// whether this value is active
215    pub active: bool,
216}
217
218/// The endpoint for all document categories
219#[derive(Debug, Clone, Builder)]
220#[builder(setter(strip_option))]
221#[expect(
222    clippy::empty_structs_with_brackets,
223    reason = "derive_builder requires named-field syntax"
224)]
225pub struct ListDocumentCategories {}
226
227impl ReturnsJsonResponse for ListDocumentCategories {}
228impl NoPagination for ListDocumentCategories {}
229
230impl ListDocumentCategories {
231    /// Create a builder for the endpoint.
232    #[must_use]
233    pub fn builder() -> ListDocumentCategoriesBuilder {
234        ListDocumentCategoriesBuilder::default()
235    }
236}
237
238impl Endpoint for ListDocumentCategories {
239    fn method(&self) -> Method {
240        Method::GET
241    }
242
243    fn endpoint(&self) -> Cow<'static, str> {
244        "enumerations/document_categories.json".into()
245    }
246}
247
248/// helper struct for outer layers with a document_categories field holding the inner data
249#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
250pub struct DocumentCategoriesWrapper<T> {
251    /// to parse JSON with document_categories key
252    pub document_categories: Vec<T>,
253}
254
255#[cfg(test)]
256mod test {
257    use super::*;
258    use std::error::Error;
259    use tracing_test::traced_test;
260
261    #[traced_test]
262    #[test]
263    fn test_list_issue_priorities_no_pagination() -> Result<(), Box<dyn Error>> {
264        dotenvy::dotenv()?;
265        let redmine = crate::api::Redmine::from_env(
266            reqwest::blocking::Client::builder()
267                .tls_backend_rustls()
268                .build()?,
269        )?;
270        let endpoint = ListIssuePriorities::builder().build()?;
271        redmine.json_response_body::<_, IssuePrioritiesWrapper<IssuePriority>>(&endpoint)?;
272        Ok(())
273    }
274
275    #[traced_test]
276    #[test]
277    fn test_list_time_entry_activities_no_pagination() -> Result<(), Box<dyn Error>> {
278        dotenvy::dotenv()?;
279        let redmine = crate::api::Redmine::from_env(
280            reqwest::blocking::Client::builder()
281                .tls_backend_rustls()
282                .build()?,
283        )?;
284        let endpoint = ListTimeEntryActivities::builder().build()?;
285        redmine
286            .json_response_body::<_, TimeEntryActivitiesWrapper<TimeEntryActivity>>(&endpoint)?;
287        Ok(())
288    }
289
290    #[traced_test]
291    #[test]
292    fn test_list_document_categories_no_pagination() -> Result<(), Box<dyn Error>> {
293        dotenvy::dotenv()?;
294        let redmine = crate::api::Redmine::from_env(
295            reqwest::blocking::Client::builder()
296                .tls_backend_rustls()
297                .build()?,
298        )?;
299        let endpoint = ListDocumentCategories::builder().build()?;
300        redmine.json_response_body::<_, DocumentCategoriesWrapper<DocumentCategory>>(&endpoint)?;
301        Ok(())
302    }
303}