1use crate::{PaginatedResponse, Result, RideWithGpsClient};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Deserialize, Serialize)]
10pub struct Member {
11 pub id: u64,
13
14 pub user_id: Option<u64>,
16
17 pub organization_id: Option<u64>,
19
20 pub url: Option<String>,
22
23 pub active: Option<bool>,
25
26 pub admin: Option<bool>,
28
29 pub manages_routes: Option<bool>,
31
32 pub manages_members: Option<bool>,
34
35 pub manages_billing: Option<bool>,
37
38 pub approved_at: Option<String>,
40
41 pub role: Option<String>,
43
44 pub status: Option<String>,
46
47 pub name: Option<String>,
49
50 pub email: Option<String>,
52
53 pub joined_at: Option<String>,
55
56 pub created_at: Option<String>,
58
59 pub updated_at: Option<String>,
61
62 pub permissions: Option<MemberPermissions>,
64
65 pub user: Option<crate::User>,
67}
68
69#[derive(Debug, Clone, Deserialize, Serialize)]
71pub struct MemberPermissions {
72 pub manage_routes: Option<bool>,
74
75 pub manage_events: Option<bool>,
77
78 pub manage_members: Option<bool>,
80
81 pub view_analytics: Option<bool>,
83}
84
85#[derive(Debug, Clone, Default, Serialize)]
87pub struct ListMembersParams {
88 #[serde(skip_serializing_if = "Option::is_none")]
90 pub name: Option<String>,
91
92 #[serde(skip_serializing_if = "Option::is_none")]
94 pub role: Option<String>,
95
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub status: Option<String>,
99
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub page: Option<u32>,
103
104 #[serde(skip_serializing_if = "Option::is_none")]
106 pub page_size: Option<u32>,
107}
108
109#[derive(Debug, Clone, Serialize)]
111pub struct UpdateMemberRequest {
112 #[serde(skip_serializing_if = "Option::is_none")]
114 pub role: Option<String>,
115
116 #[serde(skip_serializing_if = "Option::is_none")]
118 pub status: Option<String>,
119
120 #[serde(skip_serializing_if = "Option::is_none")]
122 pub permissions: Option<MemberPermissions>,
123}
124
125impl RideWithGpsClient {
126 pub fn list_members(
149 &self,
150 params: Option<&ListMembersParams>,
151 ) -> Result<PaginatedResponse<Member>> {
152 let mut url = "/api/v1/members.json".to_string();
153
154 if let Some(params) = params {
155 let query = serde_json::to_value(params)?;
156 if let Some(obj) = query.as_object() {
157 if !obj.is_empty() {
158 let query_str = serde_urlencoded::to_string(obj).map_err(|e| {
159 crate::Error::ApiError(format!("Failed to encode query: {}", e))
160 })?;
161 url.push('?');
162 url.push_str(&query_str);
163 }
164 }
165 }
166
167 self.get(&url)
168 }
169
170 pub fn get_member(&self, id: u64) -> Result<Member> {
193 #[derive(Deserialize)]
194 struct MemberWrapper {
195 member: Member,
196 }
197
198 let wrapper: MemberWrapper = self.get(&format!("/api/v1/members/{}.json", id))?;
199 Ok(wrapper.member)
200 }
201
202 pub fn update_member(&self, id: u64, member: &UpdateMemberRequest) -> Result<Member> {
237 #[derive(Deserialize)]
238 struct MemberWrapper {
239 member: Member,
240 }
241
242 let wrapper: MemberWrapper = self.put(&format!("/api/v1/members/{}.json", id), member)?;
243 Ok(wrapper.member)
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 fn test_member_deserialization() {
253 let json = r#"{
254 "id": 123,
255 "user_id": 456,
256 "name": "John Doe",
257 "email": "john@example.com",
258 "role": "admin",
259 "status": "active",
260 "permissions": {
261 "manage_routes": true,
262 "manage_events": true,
263 "manage_members": false,
264 "view_analytics": true
265 }
266 }"#;
267
268 let member: Member = serde_json::from_str(json).unwrap();
269 assert_eq!(member.id, 123);
270 assert_eq!(member.name.as_deref(), Some("John Doe"));
271 assert_eq!(member.role.as_deref(), Some("admin"));
272 assert!(member.permissions.is_some());
273 let perms = member.permissions.unwrap();
274 assert_eq!(perms.manage_routes, Some(true));
275 assert_eq!(perms.manage_members, Some(false));
276 }
277
278 #[test]
279 fn test_update_member_request_serialization() {
280 let req = UpdateMemberRequest {
281 role: Some("moderator".to_string()),
282 status: Some("active".to_string()),
283 permissions: Some(MemberPermissions {
284 manage_routes: Some(true),
285 manage_events: Some(false),
286 manage_members: Some(false),
287 view_analytics: Some(true),
288 }),
289 };
290
291 let json = serde_json::to_value(&req).unwrap();
292 assert_eq!(json.get("role").unwrap(), "moderator");
293 assert_eq!(json.get("status").unwrap(), "active");
294 assert!(json.get("permissions").is_some());
295 }
296
297 #[test]
298 fn test_member_wrapper_deserialization() {
299 let json = r#"{
300 "member": {
301 "id": 888,
302 "user_id": 777,
303 "name": "Wrapped Member",
304 "role": "admin",
305 "status": "active"
306 }
307 }"#;
308
309 #[derive(Deserialize)]
310 struct MemberWrapper {
311 member: Member,
312 }
313
314 let wrapper: MemberWrapper = serde_json::from_str(json).unwrap();
315 assert_eq!(wrapper.member.id, 888);
316 assert_eq!(wrapper.member.user_id, Some(777));
317 assert_eq!(wrapper.member.name.as_deref(), Some("Wrapped Member"));
318 assert_eq!(wrapper.member.role.as_deref(), Some("admin"));
319 }
320
321 #[test]
322 fn test_member_permissions_deserialization() {
323 let json = r#"{
324 "manage_routes": true,
325 "manage_events": false,
326 "manage_members": true,
327 "view_analytics": true
328 }"#;
329
330 let perms: MemberPermissions = serde_json::from_str(json).unwrap();
331 assert_eq!(perms.manage_routes, Some(true));
332 assert_eq!(perms.manage_events, Some(false));
333 assert_eq!(perms.manage_members, Some(true));
334 assert_eq!(perms.view_analytics, Some(true));
335 }
336
337 #[test]
338 fn test_member_with_user_object() {
339 let json = r#"{
340 "id": 999,
341 "user_id": 555,
342 "name": "Full Member",
343 "admin": true,
344 "manages_routes": true,
345 "user": {
346 "id": 555,
347 "name": "User Name",
348 "email": "user@example.com"
349 }
350 }"#;
351
352 let member: Member = serde_json::from_str(json).unwrap();
353 assert_eq!(member.id, 999);
354 assert_eq!(member.admin, Some(true));
355 assert!(member.user.is_some());
356 let user = member.user.unwrap();
357 assert_eq!(user.id, 555);
358 assert_eq!(user.name.as_deref(), Some("User Name"));
359 }
360}