Skip to main content

babelforce_manager_sdk/resources/
users.rs

1use crate::error::{map_manager_err, ManagerError};
2use crate::gen::manager::apis::configuration::Configuration;
3use crate::gen::manager::apis::manager_api;
4use crate::gen::manager::apis::user_management_api as api;
5use crate::gen::manager::models;
6use crate::resources::raw::get_json;
7use crate::retry::{with_retry, RetryPolicy};
8use crate::token::SharedCfg;
9
10/// Optional server-side filters for [`UsersResource::list`].
11#[derive(Debug, Clone, Default)]
12pub struct ListUsersQuery {
13    /// Only return the user(s) with this email address (the endpoint's `?email=` filter).
14    pub email: Option<String>,
15}
16
17/// User management — `/api/v2/users`.
18pub struct UsersResource {
19    pub(crate) cfg: SharedCfg<Configuration>,
20    pub(crate) retry: RetryPolicy,
21}
22
23impl UsersResource {
24    /// Get the currently authenticated user.
25    ///
26    /// The underlying generated operation is marked deprecated upstream, but it remains part of the
27    /// spec and is wrapped here for parity with the TypeScript/Go SDKs.
28    #[allow(deprecated)]
29    pub async fn me(&self) -> Result<models::GenericItemResponse, ManagerError> {
30        let cfg = self.cfg.get().await?;
31        let cfg = cfg.as_ref();
32        with_retry(&self.retry, true, || manager_api::get_me(cfg))
33            .await
34            .map_err(map_manager_err)
35    }
36
37    /// Get a user by email.
38    pub async fn get_by_email(
39        &self,
40        email: &str,
41    ) -> Result<models::ManagedUserItemResponse, ManagerError> {
42        let cfg = self.cfg.get().await?;
43        let cfg = cfg.as_ref();
44        with_retry(&self.retry, true, || {
45            manager_api::get_user_by_email(cfg, email)
46        })
47        .await
48        .map_err(map_manager_err)
49    }
50
51    /// List users, optionally filtered server-side.
52    ///
53    /// The endpoint exposes no pagination parameters — a single fetch returns all matches.
54    ///
55    /// Stands in for the generated `list_users`, whose `email` parameter (an anyOf
56    /// string-or-array type) is JSON-serialized into the query — it would send
57    /// `?email="a@example.com"` with literal quotes, which the server does not match. The facade
58    /// builds the query itself and decodes into the same generated response model.
59    pub async fn list(
60        &self,
61        query: ListUsersQuery,
62    ) -> Result<Vec<models::ManagedUser>, ManagerError> {
63        let cfg = self.cfg.get().await?;
64        let cfg = cfg.as_ref();
65        let mut path = "/api/v2/users".to_string();
66        if let Some(email) = &query.email {
67            path.push_str(&format!(
68                "?email={}",
69                crate::gen::manager::apis::urlencode(email)
70            ));
71        }
72        let resp: models::PaginatedManagedUserResponse = with_retry(&self.retry, true, || async {
73            let v = get_json(cfg, &path).await?;
74            serde_json::from_value(v).map_err(|e| ManagerError::Decode(e.to_string()))
75        })
76        .await?;
77        Ok(resp.items)
78    }
79
80    /// List all users (unfiltered — the endpoint exposes no pagination parameters).
81    pub async fn list_all(&self) -> Result<Vec<models::ManagedUser>, ManagerError> {
82        self.list(ListUsersQuery::default()).await
83    }
84
85    /// Create a user.
86    pub async fn create(
87        &self,
88        user: models::CreateManagedUserRequest,
89    ) -> Result<models::ManagedUserItemResponse, ManagerError> {
90        let cfg = self.cfg.get().await?;
91        let cfg = cfg.as_ref();
92        with_retry(&self.retry, false, || {
93            api::create_user(cfg, Some(user.clone()))
94        })
95        .await
96        .map_err(map_manager_err)
97    }
98
99    /// Enable the given users (by email).
100    pub async fn enable(&self, emails: Vec<String>) -> Result<(), ManagerError> {
101        let cfg = self.cfg.get().await?;
102        let cfg = cfg.as_ref();
103        with_retry(&self.retry, false, || {
104            api::enable_users(cfg, Some(email_list(&emails)))
105        })
106        .await
107        .map_err(map_manager_err)?;
108        Ok(())
109    }
110
111    /// Disable the given users (by email).
112    pub async fn disable(&self, emails: Vec<String>) -> Result<(), ManagerError> {
113        let cfg = self.cfg.get().await?;
114        let cfg = cfg.as_ref();
115        with_retry(&self.retry, false, || {
116            api::disable_users(cfg, Some(email_list(&emails)))
117        })
118        .await
119        .map_err(map_manager_err)?;
120        Ok(())
121    }
122
123    /// Delete the given users (by email).
124    pub async fn delete(&self, emails: Vec<String>) -> Result<(), ManagerError> {
125        let cfg = self.cfg.get().await?;
126        let cfg = cfg.as_ref();
127        with_retry(&self.retry, false, || {
128            api::delete_users(cfg, Some(email_list(&emails)))
129        })
130        .await
131        .map_err(map_manager_err)?;
132        Ok(())
133    }
134
135    /// Trigger a password-reset email for the given users (by email).
136    pub async fn reset_passwords(&self, emails: Vec<String>) -> Result<(), ManagerError> {
137        let cfg = self.cfg.get().await?;
138        let cfg = cfg.as_ref();
139        with_retry(&self.retry, false, || {
140            api::reset_passwords(cfg, Some(email_list(&emails)))
141        })
142        .await
143        .map_err(map_manager_err)?;
144        Ok(())
145    }
146
147    /// List the role names that can be assigned to users.
148    pub async fn list_roles(&self) -> Result<Vec<models::AccountRole>, ManagerError> {
149        let cfg = self.cfg.get().await?;
150        let cfg = cfg.as_ref();
151        let resp = with_retry(&self.retry, true, || api::list_available_roles(cfg))
152            .await
153            .map_err(map_manager_err)?;
154        Ok(resp.items)
155    }
156
157    /// Grant the given roles to the given users (by email).
158    pub async fn add_roles(
159        &self,
160        emails: Vec<String>,
161        roles: Vec<models::AccountRole>,
162    ) -> Result<(), ManagerError> {
163        let cfg = self.cfg.get().await?;
164        let cfg = cfg.as_ref();
165        with_retry(&self.retry, false, || {
166            api::add_roles(cfg, Some(role_binding(&emails, &roles)))
167        })
168        .await
169        .map_err(map_manager_err)?;
170        Ok(())
171    }
172
173    /// Revoke the given roles from the given users (by email).
174    pub async fn remove_roles(
175        &self,
176        emails: Vec<String>,
177        roles: Vec<models::AccountRole>,
178    ) -> Result<(), ManagerError> {
179        let cfg = self.cfg.get().await?;
180        let cfg = cfg.as_ref();
181        with_retry(&self.retry, false, || {
182            api::remove_roles(cfg, Some(role_binding(&emails, &roles)))
183        })
184        .await
185        .map_err(map_manager_err)?;
186        Ok(())
187    }
188}
189
190fn email_list(emails: &[String]) -> models::EmailListRequest {
191    models::EmailListRequest {
192        emails: emails.to_vec(),
193    }
194}
195
196fn role_binding(emails: &[String], roles: &[models::AccountRole]) -> models::EmailRoleBinding {
197    models::EmailRoleBinding {
198        emails: Some(emails.to_vec()),
199        roles: Some(roles.to_vec()),
200    }
201}