anthropic_api/admin/members.rs
1//! # Organization Members Admin API
2//!
3//! This module provides a Rust interface to Anthropic's Admin API for managing organization members, which allows you to
4//! list, get, update, and remove users from your organization.
5//!
6//! ## Key Features
7//!
8//! - List all users with pagination and filtering support
9//! - Get detailed information about a specific user
10//! - Update user roles within the organization
11//! - Remove users from the organization
12//!
13//! ## Basic Usage
14//!
15//! ```no_run
16//! use anthropic_api::{admin::members::*, Credentials};
17//!
18//! #[tokio::main]
19//! async fn main() {
20//! let credentials = Credentials::from_env();
21//!
22//! // List users
23//! let users = UserList::builder()
24//! .credentials(credentials.clone())
25//! .create()
26//! .await
27//! .unwrap();
28//!
29//! println!("Organization members: {:?}", users.data);
30//!
31//! // Get a specific user
32//! if let Some(user) = users.data.first() {
33//! let user_details = User::builder(&user.id)
34//! .credentials(credentials.clone())
35//! .create()
36//! .await
37//! .unwrap();
38//!
39//! println!("User details: {:?}", user_details);
40//! }
41//! }
42//! ```
43
44use crate::{anthropic_request_json, ApiResponseOrError, Credentials};
45use derive_builder::Builder;
46use reqwest::Method;
47use serde::{Deserialize, Serialize};
48
49/// Organization role of a user
50#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
51#[serde(rename_all = "lowercase")]
52pub enum UserRole {
53 /// Regular user
54 User,
55 /// Developer role
56 Developer,
57 /// Billing administrator
58 Billing,
59 /// Organization administrator
60 Admin,
61}
62
63/// A user in the organization
64#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
65pub struct User {
66 /// Unique user identifier
67 pub id: String,
68 /// User's email address
69 pub email: String,
70 /// User's name
71 pub name: String,
72 /// RFC 3339 datetime string indicating when the user joined the organization
73 pub added_at: String,
74 /// User's role in the organization
75 pub role: UserRole,
76 /// Object type (always "user" for Users)
77 #[serde(rename = "type")]
78 pub user_type: String,
79}
80
81/// Response from the List Users API
82#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
83pub struct UserList {
84 /// List of users in the organization
85 pub data: Vec<User>,
86 /// First ID in the data list (for pagination)
87 pub first_id: Option<String>,
88 /// Last ID in the data list (for pagination)
89 pub last_id: Option<String>,
90 /// Indicates if there are more results in the requested page direction
91 pub has_more: bool,
92}
93
94/// Response from the Remove User API
95#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
96pub struct UserDeleted {
97 /// ID of the deleted user
98 pub id: String,
99 /// Object type (always "user_deleted" for deleted users)
100 #[serde(rename = "type")]
101 pub deleted_type: String,
102}
103
104/// Request parameters for listing users
105#[derive(Serialize, Builder, Debug, Clone)]
106#[builder(derive(Clone, Debug, PartialEq))]
107#[builder(pattern = "owned")]
108#[builder(name = "UserListBuilder")]
109#[builder(setter(strip_option, into))]
110pub struct UserListRequest {
111 /// ID of the object to use as a cursor for pagination (previous page)
112 #[builder(default)]
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub before_id: Option<String>,
115
116 /// ID of the object to use as a cursor for pagination (next page)
117 #[builder(default)]
118 #[serde(skip_serializing_if = "Option::is_none")]
119 pub after_id: Option<String>,
120
121 /// Number of items to return per page (1-1000)
122 #[builder(default)]
123 #[serde(skip_serializing_if = "Option::is_none")]
124 pub limit: Option<u32>,
125
126 /// Filter by user email
127 #[builder(default)]
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub email: Option<String>,
130
131 /// Credentials for authentication (not serialized)
132 #[serde(skip_serializing)]
133 #[builder(default)]
134 pub credentials: Option<Credentials>,
135}
136
137/// Request parameters for getting a specific user
138#[derive(Serialize, Builder, Debug, Clone)]
139#[builder(derive(Clone, Debug, PartialEq))]
140#[builder(pattern = "owned")]
141#[builder(name = "UserBuilder")]
142#[builder(setter(strip_option, into))]
143pub struct UserRequest {
144 /// User identifier
145 pub user_id: String,
146
147 /// Credentials for authentication (not serialized)
148 #[serde(skip_serializing)]
149 #[builder(default)]
150 pub credentials: Option<Credentials>,
151}
152
153/// Request parameters for updating a user
154#[derive(Serialize, Builder, Debug, Clone)]
155#[builder(derive(Clone, Debug, PartialEq))]
156#[builder(pattern = "owned")]
157#[builder(name = "UserUpdateBuilder")]
158#[builder(setter(strip_option, into))]
159pub struct UserUpdateRequest {
160 /// User identifier (not serialized)
161 #[serde(skip_serializing)]
162 pub user_id: String,
163
164 /// New role for the user (cannot be "admin")
165 pub role: UserRole,
166
167 /// Credentials for authentication (not serialized)
168 #[serde(skip_serializing)]
169 #[builder(default)]
170 pub credentials: Option<Credentials>,
171}
172
173/// Request parameters for removing a user
174#[derive(Serialize, Builder, Debug, Clone)]
175#[builder(derive(Clone, Debug, PartialEq))]
176#[builder(pattern = "owned")]
177#[builder(name = "UserRemoveBuilder")]
178#[builder(setter(strip_option, into))]
179pub struct UserRemoveRequest {
180 /// User identifier
181 pub user_id: String,
182
183 /// Credentials for authentication (not serialized)
184 #[serde(skip_serializing)]
185 #[builder(default)]
186 pub credentials: Option<Credentials>,
187}
188
189impl UserList {
190 /// Creates a builder for listing users.
191 ///
192 /// # Example
193 ///
194 /// ```no_run
195 /// # use anthropic_api::{admin::members::*, Credentials};
196 /// # #[tokio::main]
197 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
198 /// let credentials = Credentials::from_env();
199 ///
200 /// let users = UserList::builder()
201 /// .credentials(credentials)
202 /// .limit(10u32)
203 /// .create()
204 /// .await?;
205 /// # Ok(())
206 /// # }
207 /// ```
208 pub fn builder() -> UserListBuilder {
209 UserListBuilder::create_empty()
210 }
211
212 /// Lists users in the organization with the given request parameters.
213 ///
214 /// # Example
215 ///
216 /// ```no_run
217 /// # use anthropic_api::{admin::members::*, Credentials};
218 /// # #[tokio::main]
219 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
220 /// let credentials = Credentials::from_env();
221 /// let request = UserListRequest {
222 /// before_id: None,
223 /// after_id: None,
224 /// limit: Some(20),
225 /// email: None,
226 /// credentials: Some(credentials),
227 /// };
228 ///
229 /// let users = UserList::create(request).await?;
230 /// # Ok(())
231 /// # }
232 /// ```
233 pub async fn create(request: UserListRequest) -> ApiResponseOrError<Self> {
234 let credentials_opt = request.credentials.clone();
235
236 // Build query parameters
237 let mut query_params = Vec::new();
238 if let Some(before_id) = &request.before_id {
239 query_params.push(("before_id", before_id.clone()));
240 }
241 if let Some(after_id) = &request.after_id {
242 query_params.push(("after_id", after_id.clone()));
243 }
244 if let Some(limit) = request.limit {
245 query_params.push(("limit", limit.to_string()));
246 }
247 if let Some(email) = &request.email {
248 query_params.push(("email", email.clone()));
249 }
250
251 anthropic_request_json(
252 Method::GET,
253 "organizations/users",
254 |r| r.query(&query_params),
255 credentials_opt,
256 )
257 .await
258 }
259}
260
261impl User {
262 /// Creates a builder for getting a specific user.
263 ///
264 /// # Example
265 ///
266 /// ```no_run
267 /// # use anthropic_api::{admin::members::*, Credentials};
268 /// # #[tokio::main]
269 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
270 /// let credentials = Credentials::from_env();
271 ///
272 /// let user = User::builder("user_123456789")
273 /// .credentials(credentials)
274 /// .create()
275 /// .await?;
276 /// # Ok(())
277 /// # }
278 /// ```
279 pub fn builder(user_id: impl Into<String>) -> UserBuilder {
280 UserBuilder::create_empty().user_id(user_id)
281 }
282
283 /// Gets information about a specific user.
284 ///
285 /// # Example
286 ///
287 /// ```no_run
288 /// # use anthropic_api::{admin::members::*, Credentials};
289 /// # #[tokio::main]
290 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
291 /// let credentials = Credentials::from_env();
292 /// let request = UserRequest {
293 /// user_id: "user_123456789".to_string(),
294 /// credentials: Some(credentials),
295 /// };
296 ///
297 /// let user = User::create(request).await?;
298 /// # Ok(())
299 /// # }
300 /// ```
301 pub async fn create(request: UserRequest) -> ApiResponseOrError<Self> {
302 let credentials_opt = request.credentials.clone();
303 let route = format!("organizations/users/{}", request.user_id);
304
305 anthropic_request_json(Method::GET, &route, |r| r, credentials_opt).await
306 }
307
308 /// Creates a builder for updating a user.
309 ///
310 /// # Example
311 ///
312 /// ```no_run
313 /// # use anthropic_api::{admin::members::*, Credentials};
314 /// # #[tokio::main]
315 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
316 /// let credentials = Credentials::from_env();
317 ///
318 /// let updated_user = User::update_builder("user_123456789")
319 /// .credentials(credentials)
320 /// .role(UserRole::Developer)
321 /// .create()
322 /// .await?;
323 /// # Ok(())
324 /// # }
325 /// ```
326 pub fn update_builder(user_id: impl Into<String>) -> UserUpdateBuilder {
327 UserUpdateBuilder::create_empty().user_id(user_id)
328 }
329
330 /// Updates a user with the given request parameters.
331 ///
332 /// # Example
333 ///
334 /// ```no_run
335 /// # use anthropic_api::{admin::members::*, Credentials};
336 /// # #[tokio::main]
337 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
338 /// let credentials = Credentials::from_env();
339 /// let request = UserUpdateRequest {
340 /// user_id: "user_123456789".to_string(),
341 /// role: UserRole::Developer,
342 /// credentials: Some(credentials),
343 /// };
344 ///
345 /// let updated_user = User::update(request).await?;
346 /// # Ok(())
347 /// # }
348 /// ```
349 pub async fn update(request: UserUpdateRequest) -> ApiResponseOrError<Self> {
350 let credentials_opt = request.credentials.clone();
351 let route = format!("organizations/users/{}", request.user_id);
352
353 anthropic_request_json(Method::POST, &route, |r| r.json(&request), credentials_opt).await
354 }
355
356 /// Creates a builder for removing a user.
357 ///
358 /// # Example
359 ///
360 /// ```no_run
361 /// # use anthropic_api::{admin::members::*, Credentials};
362 /// # #[tokio::main]
363 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
364 /// let credentials = Credentials::from_env();
365 ///
366 /// let removed_user = User::remove_builder("user_123456789")
367 /// .credentials(credentials)
368 /// .create()
369 /// .await?;
370 /// # Ok(())
371 /// # }
372 /// ```
373 pub fn remove_builder(user_id: impl Into<String>) -> UserRemoveBuilder {
374 UserRemoveBuilder::create_empty().user_id(user_id)
375 }
376
377 /// Removes a user from the organization.
378 ///
379 /// # Example
380 ///
381 /// ```no_run
382 /// # use anthropic_api::{admin::members::*, Credentials};
383 /// # #[tokio::main]
384 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
385 /// let credentials = Credentials::from_env();
386 /// let request = UserRemoveRequest {
387 /// user_id: "user_123456789".to_string(),
388 /// credentials: Some(credentials),
389 /// };
390 ///
391 /// let removed_user = User::remove(request).await?;
392 /// # Ok(())
393 /// # }
394 /// ```
395 pub async fn remove(request: UserRemoveRequest) -> ApiResponseOrError<UserDeleted> {
396 let credentials_opt = request.credentials.clone();
397 let route = format!("organizations/users/{}", request.user_id);
398
399 anthropic_request_json(Method::DELETE, &route, |r| r, credentials_opt).await
400 }
401}
402
403// Builder convenience methods
404impl UserListBuilder {
405 /// Creates a new user list request and returns the response.
406 ///
407 /// This is a convenience method that builds the request from the builder
408 /// and sends it to the Users API.
409 ///
410 /// # Example
411 ///
412 /// ```no_run
413 /// # use anthropic_api::{admin::members::*, Credentials};
414 /// # #[tokio::main]
415 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
416 /// let credentials = Credentials::from_env();
417 ///
418 /// let users = UserList::builder()
419 /// .credentials(credentials)
420 /// .limit(10u32)
421 /// .create()
422 /// .await?;
423 /// # Ok(())
424 /// # }
425 /// ```
426 pub async fn create(self) -> ApiResponseOrError<UserList> {
427 let request = self.build().unwrap();
428 UserList::create(request).await
429 }
430}
431
432impl UserBuilder {
433 /// Creates a new user request and returns the response.
434 ///
435 /// This is a convenience method that builds the request from the builder
436 /// and sends it to the Users API.
437 ///
438 /// # Example
439 ///
440 /// ```no_run
441 /// # use anthropic_api::{admin::members::*, Credentials};
442 /// # #[tokio::main]
443 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
444 /// let credentials = Credentials::from_env();
445 ///
446 /// let user = User::builder("user_123456789")
447 /// .credentials(credentials)
448 /// .create()
449 /// .await?;
450 /// # Ok(())
451 /// # }
452 /// ```
453 pub async fn create(self) -> ApiResponseOrError<User> {
454 let request = self.build().unwrap();
455 User::create(request).await
456 }
457}
458
459impl UserUpdateBuilder {
460 /// Creates a new user update request and returns the response.
461 ///
462 /// This is a convenience method that builds the request from the builder
463 /// and sends it to the Users API.
464 ///
465 /// # Example
466 ///
467 /// ```no_run
468 /// # use anthropic_api::{admin::members::*, Credentials};
469 /// # #[tokio::main]
470 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
471 /// let credentials = Credentials::from_env();
472 ///
473 /// let updated_user = User::update_builder("user_123456789")
474 /// .credentials(credentials)
475 /// .role(UserRole::Developer)
476 /// .create()
477 /// .await?;
478 /// # Ok(())
479 /// # }
480 /// ```
481 pub async fn create(self) -> ApiResponseOrError<User> {
482 let request = self.build().unwrap();
483 User::update(request).await
484 }
485}
486
487impl UserRemoveBuilder {
488 /// Creates a new user remove request and returns the response.
489 ///
490 /// This is a convenience method that builds the request from the builder
491 /// and sends it to the Users API.
492 ///
493 /// # Example
494 ///
495 /// ```no_run
496 /// # use anthropic_api::{admin::members::*, Credentials};
497 /// # #[tokio::main]
498 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
499 /// let credentials = Credentials::from_env();
500 ///
501 /// let removed_user = User::remove_builder("user_123456789")
502 /// .credentials(credentials)
503 /// .create()
504 /// .await?;
505 /// # Ok(())
506 /// # }
507 /// ```
508 pub async fn create(self) -> ApiResponseOrError<UserDeleted> {
509 let request = self.build().unwrap();
510 User::remove(request).await
511 }
512}
513
514#[cfg(test)]
515mod tests {
516 use super::*;
517 use crate::Credentials;
518
519 #[tokio::test]
520 #[ignore] // Requires admin API key
521 async fn test_list_users() {
522 let credentials = Credentials::from_env();
523
524 let users = UserList::builder()
525 .credentials(credentials)
526 .create()
527 .await
528 .unwrap();
529
530 assert!(users.data.len() > 0);
531 }
532
533 #[tokio::test]
534 #[ignore] // Requires admin API key
535 async fn test_get_user() {
536 let credentials = Credentials::from_env();
537
538 // First get a user ID from the list
539 let users = UserList::builder()
540 .credentials(credentials.clone())
541 .create()
542 .await
543 .unwrap();
544
545 if let Some(user) = users.data.first() {
546 let user_id = &user.id;
547
548 // Then get that specific user
549 let user_details = User::builder(user_id)
550 .credentials(credentials)
551 .create()
552 .await
553 .unwrap();
554
555 assert_eq!(user_details.id, *user_id);
556 }
557 }
558}