Skip to main content

bitwarden_member_administration/
organization_users_management_client.rs

1use std::sync::Arc;
2
3use bitwarden_api_api::models::OrganizationUserBulkRequestModel;
4use bitwarden_core::{
5    ApiError, Client, FromClient, MissingFieldError, OrganizationId, client::ApiConfigurations,
6};
7use bitwarden_error::bitwarden_error;
8use bitwarden_organizations::OrganizationUserId;
9use thiserror::Error;
10#[cfg(feature = "wasm")]
11use wasm_bindgen::prelude::wasm_bindgen;
12
13use crate::OrganizationUserBulkResponse;
14
15/// Errors returned from [`OrganizationUsersManagementClient`] operations.
16#[bitwarden_error(flat)]
17#[derive(Debug, Error)]
18pub enum OrganizationUsersManagementError {
19    /// The request failed as a whole.
20    #[error(transparent)]
21    Api(#[from] ApiError),
22    /// A required field was missing from the server response.
23    #[error(transparent)]
24    MissingField(#[from] MissingFieldError),
25}
26
27/// Client for administering the members of an organization.
28#[cfg_attr(feature = "wasm", wasm_bindgen)]
29#[derive(FromClient)]
30pub struct OrganizationUsersManagementClient {
31    pub(crate) api_configurations: Arc<ApiConfigurations>,
32}
33
34#[cfg_attr(feature = "wasm", wasm_bindgen)]
35impl OrganizationUsersManagementClient {
36    /// Sends invites to the given staged members, promoting them to invited and consuming a seat.
37    ///
38    /// Returns an `Err` if the entire request fails. Otherwise returns `Ok` containing success or
39    /// failure information for each member.
40    pub async fn send_staged_invites(
41        &self,
42        organization_id: OrganizationId,
43        organization_user_ids: Vec<OrganizationUserId>,
44    ) -> Result<Vec<OrganizationUserBulkResponse>, OrganizationUsersManagementError> {
45        let response = self
46            .api_configurations
47            .api_client
48            .organization_users_api()
49            .send_invite_to_staged_users(
50                organization_id.into(),
51                Some(bulk_request(organization_user_ids)),
52            )
53            .await?;
54
55        // A missing list is treated as empty, matching how the clients parse list responses.
56        response
57            .data
58            .unwrap_or_default()
59            .into_iter()
60            .map(|row| OrganizationUserBulkResponse::try_from(row).map_err(Into::into))
61            .collect()
62    }
63
64    /// Re-sends the invitation email to the given invited members.
65    ///
66    /// Returns an `Err` if the entire request fails. Otherwise returns `Ok` containing success or
67    /// failure information for each member.
68    pub async fn bulk_reinvite(
69        &self,
70        organization_id: OrganizationId,
71        organization_user_ids: Vec<OrganizationUserId>,
72    ) -> Result<Vec<OrganizationUserBulkResponse>, OrganizationUsersManagementError> {
73        let response = self
74            .api_configurations
75            .api_client
76            .organization_users_api()
77            .bulk_reinvite(
78                organization_id.into(),
79                Some(bulk_request(organization_user_ids)),
80            )
81            .await?;
82
83        // A missing list is treated as empty, matching how the clients parse list responses.
84        response
85            .data
86            .unwrap_or_default()
87            .into_iter()
88            .map(|row| OrganizationUserBulkResponse::try_from(row).map_err(Into::into))
89            .collect()
90    }
91
92    /// Re-sends the invitation email to a single invited member.
93    pub async fn reinvite(
94        &self,
95        organization_id: OrganizationId,
96        organization_user_id: OrganizationUserId,
97    ) -> Result<(), OrganizationUsersManagementError> {
98        self.api_configurations
99            .api_client
100            .organization_users_api()
101            .reinvite(organization_id.into(), organization_user_id.into())
102            .await?;
103
104        Ok(())
105    }
106}
107
108/// Builds the request body shared by the bulk member endpoints.
109fn bulk_request(
110    organization_user_ids: Vec<OrganizationUserId>,
111) -> OrganizationUserBulkRequestModel {
112    OrganizationUserBulkRequestModel::new(
113        organization_user_ids.into_iter().map(Into::into).collect(),
114    )
115}
116
117/// Extension trait exposing [`OrganizationUsersManagementClient`] on [`Client`].
118pub trait OrganizationUsersManagementClientExt {
119    /// Organization member administration operations.
120    fn organization_users_management(&self) -> OrganizationUsersManagementClient;
121}
122
123impl OrganizationUsersManagementClientExt for Client {
124    fn organization_users_management(&self) -> OrganizationUsersManagementClient {
125        OrganizationUsersManagementClient::from_client(self)
126    }
127}