1use derive_builder::Builder;
9use reqwest::Method;
10use std::borrow::Cow;
11
12use crate::api::{Endpoint, NoPagination, ReturnsJsonResponse};
13
14#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
18pub struct RoleEssentials {
19 pub id: u64,
21 pub name: String,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub inherited: Option<bool>,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
30pub enum IssuesVisibility {
31 #[serde(rename = "all")]
33 All,
34 #[serde(rename = "default")]
36 AllNonPrivate,
37 #[serde(rename = "own")]
39 Own,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
44pub enum TimeEntriesVisibility {
45 #[serde(rename = "all")]
47 All,
48 #[serde(rename = "own")]
50 Own,
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
55pub enum UsersVisibility {
56 #[serde(rename = "all")]
58 All,
59 #[serde(rename = "members_of_visible_projects")]
61 MembersOfVisibleProjects,
62}
63
64#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
68pub struct Role {
69 pub id: u64,
71 pub name: String,
73 pub assignable: bool,
75 pub issues_visibility: IssuesVisibility,
77 pub time_entries_visibility: TimeEntriesVisibility,
79 pub users_visibility: UsersVisibility,
81 pub permissions: Vec<String>,
84}
85
86#[derive(Debug, Clone, Builder)]
91#[builder(setter(strip_option))]
92pub struct ListRoles {}
93
94impl ReturnsJsonResponse for ListRoles {}
95impl NoPagination for ListRoles {}
96
97impl ListRoles {
98 #[must_use]
100 pub fn builder() -> ListRolesBuilder {
101 ListRolesBuilder::default()
102 }
103}
104
105impl Endpoint for ListRoles {
106 fn method(&self) -> Method {
107 Method::GET
108 }
109
110 fn endpoint(&self) -> Cow<'static, str> {
111 "roles.json".into()
112 }
113}
114
115#[derive(Debug, Clone, Builder)]
117#[builder(setter(strip_option))]
118pub struct GetRole {
119 id: u64,
121}
122
123impl ReturnsJsonResponse for GetRole {}
124impl NoPagination for GetRole {}
125
126impl GetRole {
127 #[must_use]
129 pub fn builder() -> GetRoleBuilder {
130 GetRoleBuilder::default()
131 }
132}
133
134impl Endpoint for GetRole {
135 fn method(&self) -> Method {
136 Method::GET
137 }
138
139 fn endpoint(&self) -> Cow<'static, str> {
140 format!("roles/{}.json", self.id).into()
141 }
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
146pub struct RolesWrapper<T> {
147 pub roles: Vec<T>,
149}
150
151#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
154pub struct RoleWrapper<T> {
155 pub role: T,
157}
158
159#[cfg(test)]
160mod test {
161 use super::*;
162 use pretty_assertions::assert_eq;
163 use std::error::Error;
164 use tracing_test::traced_test;
165
166 #[traced_test]
167 #[test]
168 fn test_list_roles_no_pagination() -> Result<(), Box<dyn Error>> {
169 dotenvy::dotenv()?;
170 let redmine = crate::api::Redmine::from_env(
171 reqwest::blocking::Client::builder()
172 .use_rustls_tls()
173 .build()?,
174 )?;
175 let endpoint = ListRoles::builder().build()?;
176 redmine.json_response_body::<_, RolesWrapper<RoleEssentials>>(&endpoint)?;
177 Ok(())
178 }
179
180 #[test]
181 fn test_get_role() -> Result<(), Box<dyn Error>> {
182 dotenvy::dotenv()?;
183 let redmine = crate::api::Redmine::from_env(
184 reqwest::blocking::Client::builder()
185 .use_rustls_tls()
186 .build()?,
187 )?;
188 let endpoint = GetRole::builder().id(8).build()?;
189 redmine.json_response_body::<_, RoleWrapper<Role>>(&endpoint)?;
190 Ok(())
191 }
192
193 #[traced_test]
198 #[test]
199 fn test_completeness_role_type() -> Result<(), Box<dyn Error>> {
200 dotenvy::dotenv()?;
201 let redmine = crate::api::Redmine::from_env(
202 reqwest::blocking::Client::builder()
203 .use_rustls_tls()
204 .build()?,
205 )?;
206 let list_endpoint = ListRoles::builder().build()?;
207 let RolesWrapper { roles } =
208 redmine.json_response_body::<_, RolesWrapper<RoleEssentials>>(&list_endpoint)?;
209 for role in roles {
210 let endpoint = GetRole::builder().id(role.id).build()?;
211 let RoleWrapper { role: value } =
212 redmine.json_response_body::<_, RoleWrapper<serde_json::Value>>(&endpoint)?;
213 let o: Role = serde_json::from_value(value.clone())?;
214 let reserialized = serde_json::to_value(o)?;
215 assert_eq!(value, reserialized);
216 }
217 Ok(())
218 }
219}