redis_cloud/
account.rs

1//! Account management operations and models
2//!
3//! This module provides comprehensive account management functionality for Redis Cloud,
4//! including account information retrieval, settings management, API keys, owners,
5//! payment methods, SSO/SAML configuration, and billing address management.
6//!
7//! # Overview
8//!
9//! The account module is the central point for managing organization-wide settings and
10//! configurations in Redis Cloud. It handles everything from basic account information
11//! to advanced features like SSO integration and API key management.
12//!
13//! # Key Features
14//!
15//! - **Account Information**: Get current account details and metadata
16//! - **API Key Management**: Create, list, and manage API keys for programmatic access
17//! - **Owner Management**: Manage account owners and their permissions
18//! - **Payment Methods**: Handle payment methods and billing configuration
19//! - **SSO/SAML**: Configure single sign-on and SAML integration
20//! - **Billing Address**: Manage billing address information
21//!
22//! # Example Usage
23//!
24//! ```no_run
25//! use redis_cloud::{CloudClient, AccountHandler};
26//!
27//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
28//! let client = CloudClient::builder()
29//!     .api_key("your-api-key")
30//!     .api_secret("your-api-secret")
31//!     .build()?;
32//!
33//! let handler = AccountHandler::new(client);
34//!
35//! // Get current account information
36//! let account = handler.get_current_account().await?;
37//! println!("Account info: {:?}", account);
38//!
39//! // Get payment methods
40//! let payment_methods = handler.get_account_payment_methods().await?;
41//! println!("Payment methods: {:?}", payment_methods);
42//! # Ok(())
43//! # }
44//! ```
45
46use crate::{CloudClient, Result};
47use serde::{Deserialize, Serialize};
48use serde_json::Value;
49use std::collections::HashMap;
50
51// ============================================================================
52// Models
53// ============================================================================
54
55/// ModulesData
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct ModulesData {
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub modules: Option<Vec<Module>>,
60
61    /// HATEOAS links
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub links: Option<Vec<HashMap<String, Value>>>,
64
65    /// Additional fields from the API
66    #[serde(flatten)]
67    pub extra: Value,
68}
69
70/// RootAccount
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct RootAccount {
73    /// HATEOAS links
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub links: Option<Vec<HashMap<String, Value>>>,
76
77    /// Additional fields from the API
78    #[serde(flatten)]
79    pub extra: Value,
80}
81
82/// Account system log entry
83#[derive(Debug, Clone, Serialize, Deserialize)]
84#[serde(rename_all = "camelCase")]
85pub struct AccountSystemLogEntry {
86    #[serde(skip_serializing_if = "Option::is_none")]
87    pub id: Option<i32>,
88
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub time: Option<String>,
91
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub originator: Option<String>,
94
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub api_key_name: Option<String>,
97
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub resource: Option<String>,
100
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub r#type: Option<String>,
103
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub description: Option<String>,
106
107    /// Additional fields from the API
108    #[serde(flatten)]
109    pub extra: Value,
110}
111
112/// Regions
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct Regions {
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub regions: Option<Vec<Region>>,
117
118    /// HATEOAS links
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub links: Option<Vec<HashMap<String, Value>>>,
121
122    /// Additional fields from the API
123    #[serde(flatten)]
124    pub extra: Value,
125}
126
127/// RedisLabs region information
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub struct Region {
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub name: Option<String>,
132
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub provider: Option<String>,
135
136    /// Additional fields from the API
137    #[serde(flatten)]
138    pub extra: Value,
139}
140
141/// RedisLabs Account payment methods
142#[derive(Debug, Clone, Serialize, Deserialize)]
143#[serde(rename_all = "camelCase")]
144pub struct PaymentMethods {
145    #[serde(skip_serializing_if = "Option::is_none")]
146    pub account_id: Option<i32>,
147
148    /// HATEOAS links
149    #[serde(skip_serializing_if = "Option::is_none")]
150    pub links: Option<Vec<HashMap<String, Value>>>,
151
152    /// Additional fields from the API
153    #[serde(flatten)]
154    pub extra: Value,
155}
156
157/// RedisLabs database module information
158#[derive(Debug, Clone, Serialize, Deserialize)]
159#[serde(rename_all = "camelCase")]
160pub struct Module {
161    #[serde(skip_serializing_if = "Option::is_none")]
162    pub name: Option<String>,
163
164    #[serde(skip_serializing_if = "Option::is_none")]
165    pub capability_name: Option<String>,
166
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub description: Option<String>,
169
170    /// Additional fields from the API
171    #[serde(flatten)]
172    pub extra: Value,
173}
174
175/// AccountSystemLogEntries
176#[derive(Debug, Clone, Serialize, Deserialize)]
177pub struct AccountSystemLogEntries {
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub entries: Option<Vec<AccountSystemLogEntry>>,
180
181    /// HATEOAS links
182    #[serde(skip_serializing_if = "Option::is_none")]
183    pub links: Option<Vec<HashMap<String, Value>>>,
184
185    /// Additional fields from the API
186    #[serde(flatten)]
187    pub extra: Value,
188}
189
190/// SearchScalingFactorsData
191#[derive(Debug, Clone, Serialize, Deserialize)]
192#[serde(rename_all = "camelCase")]
193pub struct SearchScalingFactorsData {
194    #[serde(skip_serializing_if = "Option::is_none")]
195    pub query_performance_factors: Option<Vec<String>>,
196
197    /// HATEOAS links
198    #[serde(skip_serializing_if = "Option::is_none")]
199    pub links: Option<Vec<HashMap<String, Value>>>,
200
201    /// Additional fields from the API
202    #[serde(flatten)]
203    pub extra: Value,
204}
205
206/// Account session log entry
207#[derive(Debug, Clone, Serialize, Deserialize)]
208#[serde(rename_all = "camelCase")]
209pub struct AccountSessionLogEntry {
210    #[serde(skip_serializing_if = "Option::is_none")]
211    pub id: Option<String>,
212
213    #[serde(skip_serializing_if = "Option::is_none")]
214    pub time: Option<String>,
215
216    #[serde(skip_serializing_if = "Option::is_none")]
217    pub user: Option<String>,
218
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub user_agent: Option<String>,
221
222    #[serde(skip_serializing_if = "Option::is_none")]
223    pub ip_address: Option<String>,
224
225    #[serde(skip_serializing_if = "Option::is_none")]
226    pub user_role: Option<String>,
227
228    #[serde(skip_serializing_if = "Option::is_none")]
229    pub r#type: Option<String>,
230
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub action: Option<String>,
233
234    /// Additional fields from the API
235    #[serde(flatten)]
236    pub extra: Value,
237}
238
239/// RedisLabs data persistence information
240#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct DataPersistenceEntry {
242    #[serde(skip_serializing_if = "Option::is_none")]
243    pub name: Option<String>,
244
245    #[serde(skip_serializing_if = "Option::is_none")]
246    pub description: Option<String>,
247
248    /// Additional fields from the API
249    #[serde(flatten)]
250    pub extra: Value,
251}
252
253/// DataPersistenceOptions
254#[derive(Debug, Clone, Serialize, Deserialize)]
255#[serde(rename_all = "camelCase")]
256pub struct DataPersistenceOptions {
257    #[serde(skip_serializing_if = "Option::is_none")]
258    pub data_persistence: Option<Vec<DataPersistenceEntry>>,
259
260    /// HATEOAS links
261    #[serde(skip_serializing_if = "Option::is_none")]
262    pub links: Option<Vec<HashMap<String, Value>>>,
263
264    /// Additional fields from the API
265    #[serde(flatten)]
266    pub extra: Value,
267}
268
269/// AccountSessionLogEntries
270#[derive(Debug, Clone, Serialize, Deserialize)]
271pub struct AccountSessionLogEntries {
272    #[serde(skip_serializing_if = "Option::is_none")]
273    pub entries: Option<Vec<AccountSessionLogEntry>>,
274
275    /// HATEOAS links
276    #[serde(skip_serializing_if = "Option::is_none")]
277    pub links: Option<Vec<HashMap<String, Value>>>,
278
279    /// Additional fields from the API
280    #[serde(flatten)]
281    pub extra: Value,
282}
283
284// ============================================================================
285// Handler
286// ============================================================================
287
288/// Account operations handler
289/// Handler for account management operations
290///
291/// Provides methods for managing account information, API keys, owners,
292/// payment methods, SSO/SAML configuration, and billing addresses.
293pub struct AccountHandler {
294    client: CloudClient,
295}
296
297impl AccountHandler {
298    /// Create a new handler
299    pub fn new(client: CloudClient) -> Self {
300        Self { client }
301    }
302
303    /// Get current account
304    /// Gets information on this account.
305    ///
306    /// GET /
307    pub async fn get_current_account(&self) -> Result<RootAccount> {
308        self.client.get("/").await
309    }
310
311    /// Get data persistence options
312    /// Gets a list of all [data persistence](https://redis.io/docs/latest/operate/rc/databases/configuration/data-persistence/) options for this account.
313    ///
314    /// GET /data-persistence
315    pub async fn get_data_persistence_options(&self) -> Result<DataPersistenceOptions> {
316        self.client.get("/data-persistence").await
317    }
318
319    /// Get advanced capabilities
320    /// Gets a list of Redis [advanced capabilities](https://redis.io/docs/latest/operate/rc/databases/configuration/advanced-capabilities/) (also known as modules) available for this account. Advanced capability support may differ based on subscription and database settings.
321    ///
322    /// GET /database-modules
323    pub async fn get_supported_database_modules(&self) -> Result<ModulesData> {
324        self.client.get("/database-modules").await
325    }
326
327    /// Get system logs
328    /// Gets [system logs](https://redis.io/docs/latest/operate/rc/api/examples/audit-system-logs/) for this account.
329    ///
330    /// GET /logs
331    pub async fn get_account_system_logs(
332        &self,
333        offset: Option<i32>,
334        limit: Option<i32>,
335    ) -> Result<AccountSystemLogEntries> {
336        let mut query = Vec::new();
337        if let Some(v) = offset {
338            query.push(format!("offset={}", v));
339        }
340        if let Some(v) = limit {
341            query.push(format!("limit={}", v));
342        }
343        let query_string = if query.is_empty() {
344            String::new()
345        } else {
346            format!("?{}", query.join("&"))
347        };
348        self.client.get(&format!("/logs{}", query_string)).await
349    }
350
351    /// Get payment methods
352    /// Gets a list of all payment methods for this account.
353    ///
354    /// GET /payment-methods
355    pub async fn get_account_payment_methods(&self) -> Result<PaymentMethods> {
356        self.client.get("/payment-methods").await
357    }
358
359    /// Get query performance factors
360    /// Gets a list of available [query performance factors](https://redis.io/docs/latest/operate/rc/databases/configuration/advanced-capabilities/#query-performance-factor).
361    ///
362    /// GET /query-performance-factors
363    pub async fn get_supported_search_scaling_factors(&self) -> Result<SearchScalingFactorsData> {
364        self.client.get("/query-performance-factors").await
365    }
366
367    /// Get available Pro plan regions
368    /// Gets a list of available regions for Pro subscriptions. For Essentials subscriptions, use 'GET /fixed/plans'.
369    ///
370    /// GET /regions
371    pub async fn get_supported_regions(&self, provider: Option<String>) -> Result<Regions> {
372        let mut query = Vec::new();
373        if let Some(v) = provider {
374            query.push(format!("provider={}", v));
375        }
376        let query_string = if query.is_empty() {
377            String::new()
378        } else {
379            format!("?{}", query.join("&"))
380        };
381        self.client.get(&format!("/regions{}", query_string)).await
382    }
383
384    /// Get session logs
385    /// Gets session logs for this account.
386    ///
387    /// GET /session-logs
388    pub async fn get_account_session_logs(
389        &self,
390        offset: Option<i32>,
391        limit: Option<i32>,
392    ) -> Result<AccountSessionLogEntries> {
393        let mut query = Vec::new();
394        if let Some(v) = offset {
395            query.push(format!("offset={}", v));
396        }
397        if let Some(v) = limit {
398            query.push(format!("limit={}", v));
399        }
400        let query_string = if query.is_empty() {
401            String::new()
402        } else {
403            format!("?{}", query.join("&"))
404        };
405        self.client
406            .get(&format!("/session-logs{}", query_string))
407            .await
408    }
409}