Skip to main content

redis_cloud/
users.rs

1//! User management and authentication
2//!
3//! This module provides comprehensive user management functionality for Redis Cloud,
4//! including user creation, role assignment, password management, and multi-factor
5//! authentication configuration.
6//!
7//! # Overview
8//!
9//! Users in Redis Cloud can have different roles and permissions that control their
10//! access to subscriptions, databases, and account settings. The system supports both
11//! local users and SSO/SAML integrated users.
12//!
13//! # User Roles
14//!
15//! - **Owner**: Full administrative access to all resources
16//! - **Manager**: Can manage subscriptions and databases
17//! - **Viewer**: Read-only access to resources
18//! - **Billing Admin**: Access to billing and payment information
19//! - **Custom Roles**: Organization-specific roles with custom permissions
20//!
21//! # Key Features
22//!
23//! - **User Lifecycle**: Create, update, delete, and invite users
24//! - **Role Management**: Assign and modify user roles
25//! - **Password Policies**: Enforce password complexity and rotation
26//! - **MFA Support**: Two-factor authentication configuration
27//! - **API Access**: Manage programmatic access for users
28//! - **Audit Trail**: Track user actions and changes
29//!
30//! # Example Usage
31//!
32//! ```no_run
33//! use redis_cloud::{CloudClient, UserHandler};
34//!
35//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
36//! let client = CloudClient::builder()
37//!     .api_key("your-api-key")
38//!     .api_secret("your-api-secret")
39//!     .build()?;
40//!
41//! let handler = UserHandler::new(client);
42//!
43//! // List all users
44//! let users = handler.get_all_users().await?;
45//!
46//! // Get specific user details (user ID 123)
47//! let user = handler.get_user_by_id(123).await?;
48//! # Ok(())
49//! # }
50//! ```
51
52use crate::types::{Link, ProcessorResponse};
53use crate::{CloudClient, Result};
54use serde::{Deserialize, Serialize};
55
56// ============================================================================
57// Models
58// ============================================================================
59
60/// User update request
61#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(rename_all = "camelCase")]
63pub struct AccountUserUpdateRequest {
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub user_id: Option<i32>,
66
67    /// The account user's name.
68    pub name: String,
69
70    /// Changes the account user's role.
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub role: Option<String>,
73
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub command_type: Option<String>,
76}
77
78/// Account users response
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct AccountUsers {
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub account: Option<i32>,
83
84    /// List of users
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub users: Option<Vec<AccountUser>>,
87
88    /// HATEOAS links
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub links: Option<Vec<Link>>,
91}
92
93/// User options information
94#[derive(Debug, Clone, Serialize, Deserialize)]
95#[serde(rename_all = "camelCase")]
96pub struct AccountUserOptions {
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub billing: Option<bool>,
99
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub email_alerts: Option<bool>,
102
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub operational_emails: Option<bool>,
105
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub mfa_enabled: Option<bool>,
108}
109
110/// Task state update response
111#[derive(Debug, Clone, Serialize, Deserialize)]
112#[serde(rename_all = "camelCase")]
113pub struct TaskStateUpdate {
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub task_id: Option<String>,
116
117    #[serde(skip_serializing_if = "Option::is_none")]
118    pub command_type: Option<String>,
119
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub status: Option<String>,
122
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub description: Option<String>,
125
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub timestamp: Option<String>,
128
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub response: Option<ProcessorResponse>,
131
132    /// HATEOAS links
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub links: Option<Vec<Link>>,
135}
136
137/// User information
138#[derive(Debug, Clone, Serialize, Deserialize)]
139#[serde(rename_all = "camelCase")]
140pub struct AccountUser {
141    #[serde(skip_serializing_if = "Option::is_none")]
142    pub id: Option<i32>,
143
144    #[serde(skip_serializing_if = "Option::is_none")]
145    pub name: Option<String>,
146
147    #[serde(skip_serializing_if = "Option::is_none")]
148    pub email: Option<String>,
149
150    #[serde(skip_serializing_if = "Option::is_none")]
151    pub role: Option<String>,
152
153    #[serde(skip_serializing_if = "Option::is_none")]
154    pub sign_up: Option<String>,
155
156    #[serde(skip_serializing_if = "Option::is_none")]
157    pub user_type: Option<String>,
158
159    #[serde(skip_serializing_if = "Option::is_none")]
160    pub has_api_key: Option<bool>,
161
162    #[serde(skip_serializing_if = "Option::is_none")]
163    pub options: Option<AccountUserOptions>,
164
165    /// HATEOAS links
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub links: Option<Vec<Link>>,
168}
169
170// ============================================================================
171// Handler
172// ============================================================================
173
174/// Handler for user management operations
175///
176/// Manages user accounts, roles, permissions, invitations,
177/// and authentication settings including MFA configuration.
178pub struct UsersHandler {
179    client: CloudClient,
180}
181
182impl UsersHandler {
183    /// Create a new handler
184    #[must_use]
185    pub fn new(client: CloudClient) -> Self {
186        Self { client }
187    }
188
189    /// Get users
190    /// Gets a list of all account users.
191    ///
192    /// GET /users
193    pub async fn get_all_users(&self) -> Result<AccountUsers> {
194        self.client.get("/users").await
195    }
196
197    /// Delete user
198    /// Deletes a user from this account.
199    ///
200    /// DELETE /users/{userId}
201    pub async fn delete_user_by_id(&self, user_id: i32) -> Result<TaskStateUpdate> {
202        let response = self.client.delete_raw(&format!("/users/{user_id}")).await?;
203        serde_json::from_value(response).map_err(Into::into)
204    }
205
206    /// Get a single user
207    /// Gets details about a single account user.
208    ///
209    /// GET /users/{userId}
210    pub async fn get_user_by_id(&self, user_id: i32) -> Result<AccountUser> {
211        self.client.get(&format!("/users/{user_id}")).await
212    }
213
214    /// Update a user
215    /// Updates an account user's name or role.
216    ///
217    /// PUT /users/{userId}
218    pub async fn update_user(
219        &self,
220        user_id: i32,
221        request: &AccountUserUpdateRequest,
222    ) -> Result<TaskStateUpdate> {
223        self.client.put(&format!("/users/{user_id}"), request).await
224    }
225}