bitwarden_vault/cipher/cipher_client/admin/
delete.rs

1use bitwarden_api_api::models::CipherBulkDeleteRequestModel;
2use bitwarden_core::{ApiError, OrganizationId};
3
4use crate::{CipherId, cipher_client::admin::CipherAdminClient};
5
6async fn delete_cipher(
7    cipher_id: CipherId,
8    api_client: &bitwarden_api_api::apis::ApiClient,
9) -> Result<(), ApiError> {
10    let api = api_client.ciphers_api();
11    api.delete_admin(cipher_id.into()).await?;
12    Ok(())
13}
14
15async fn delete_ciphers_many(
16    cipher_ids: Vec<CipherId>,
17    organization_id: OrganizationId,
18    api_client: &bitwarden_api_api::apis::ApiClient,
19) -> Result<(), ApiError> {
20    let api = api_client.ciphers_api();
21
22    api.delete_many_admin(Some(CipherBulkDeleteRequestModel {
23        ids: cipher_ids.iter().map(|id| id.to_string()).collect(),
24        organization_id: Some(organization_id.to_string()),
25    }))
26    .await?;
27
28    Ok(())
29}
30
31async fn soft_delete(
32    cipher_id: CipherId,
33    api_client: &bitwarden_api_api::apis::ApiClient,
34) -> Result<(), ApiError> {
35    let api = api_client.ciphers_api();
36    api.put_delete_admin(cipher_id.into()).await?;
37    Ok(())
38}
39
40async fn soft_delete_many(
41    cipher_ids: Vec<CipherId>,
42    organization_id: OrganizationId,
43    api_client: &bitwarden_api_api::apis::ApiClient,
44) -> Result<(), ApiError> {
45    let api = api_client.ciphers_api();
46
47    api.put_delete_many_admin(Some(CipherBulkDeleteRequestModel {
48        ids: cipher_ids.iter().map(|id| id.to_string()).collect(),
49        organization_id: Some(organization_id.to_string()),
50    }))
51    .await?;
52    Ok(())
53}
54
55impl CipherAdminClient {
56    /// Deletes the Cipher with the matching CipherId from the server, using the admin endpoint.
57    /// Affects server data only, does not modify local state.
58    pub async fn delete(&self, cipher_id: CipherId) -> Result<(), ApiError> {
59        delete_cipher(
60            cipher_id,
61            &self
62                .client
63                .internal
64                .get_api_configurations()
65                .await
66                .api_client,
67        )
68        .await
69    }
70
71    /// Soft-deletes the Cipher with the matching CipherId from the server, using the admin
72    /// endpoint. Affects server data only, does not modify local state.
73    pub async fn soft_delete(&self, cipher_id: CipherId) -> Result<(), ApiError> {
74        soft_delete(
75            cipher_id,
76            &self
77                .client
78                .internal
79                .get_api_configurations()
80                .await
81                .api_client,
82        )
83        .await
84    }
85
86    /// Deletes all Cipher objects with a matching CipherId from the server, using the admin
87    /// endpoint. Affects server data only, does not modify local state.
88    pub async fn delete_many(
89        &self,
90        cipher_ids: Vec<CipherId>,
91        organization_id: OrganizationId,
92    ) -> Result<(), ApiError> {
93        delete_ciphers_many(
94            cipher_ids,
95            organization_id,
96            &self
97                .client
98                .internal
99                .get_api_configurations()
100                .await
101                .api_client,
102        )
103        .await
104    }
105
106    /// Soft-deletes all Cipher objects for the given CipherIds from the server, using the admin
107    /// endpoint. Affects server data only, does not modify local state.
108    pub async fn soft_delete_many(
109        &self,
110        cipher_ids: Vec<CipherId>,
111        organization_id: OrganizationId,
112    ) -> Result<(), ApiError> {
113        soft_delete_many(
114            cipher_ids,
115            organization_id,
116            &self
117                .client
118                .internal
119                .get_api_configurations()
120                .await
121                .api_client,
122        )
123        .await
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130
131    const TEST_CIPHER_ID: &str = "5faa9684-c793-4a2d-8a12-b33900187097";
132    const TEST_CIPHER_ID_2: &str = "6faa9684-c793-4a2d-8a12-b33900187098";
133    const TEST_ORG_ID: &str = "1bc9ac1e-f5aa-45f2-94bf-b181009709b8";
134
135    #[tokio::test]
136    async fn test_delete_as_admin() {
137        delete_cipher(
138            TEST_CIPHER_ID.parse().unwrap(),
139            &bitwarden_api_api::apis::ApiClient::new_mocked(|mock| {
140                mock.ciphers_api.expect_delete_admin().returning(move |id| {
141                    assert_eq!(&id.to_string(), TEST_CIPHER_ID);
142                    Ok(())
143                });
144            }),
145        )
146        .await
147        .unwrap()
148    }
149
150    #[tokio::test]
151    async fn test_soft_delete_as_admin() {
152        soft_delete(
153            TEST_CIPHER_ID.parse().unwrap(),
154            &bitwarden_api_api::apis::ApiClient::new_mocked(|mock| {
155                mock.ciphers_api
156                    .expect_put_delete_admin()
157                    .returning(move |id| {
158                        assert_eq!(&id.to_string(), TEST_CIPHER_ID);
159                        Ok(())
160                    });
161            }),
162        )
163        .await
164        .unwrap()
165    }
166
167    #[tokio::test]
168    async fn test_delete_many_as_admin() {
169        delete_ciphers_many(
170            vec![
171                TEST_CIPHER_ID.parse().unwrap(),
172                TEST_CIPHER_ID_2.parse().unwrap(),
173            ],
174            TEST_ORG_ID.parse().unwrap(),
175            &bitwarden_api_api::apis::ApiClient::new_mocked(|mock| {
176                mock.ciphers_api
177                    .expect_delete_many_admin()
178                    .returning(move |request| {
179                        let CipherBulkDeleteRequestModel {
180                            ids,
181                            organization_id,
182                        } = request.unwrap();
183
184                        assert_eq!(
185                            ids,
186                            vec![TEST_CIPHER_ID.to_string(), TEST_CIPHER_ID_2.to_string(),],
187                        );
188                        assert_eq!(organization_id, Some(TEST_ORG_ID.to_string()));
189                        Ok(())
190                    });
191            }),
192        )
193        .await
194        .unwrap()
195    }
196
197    #[tokio::test]
198    async fn test_soft_delete_many_as_admin() {
199        soft_delete_many(
200            vec![
201                TEST_CIPHER_ID.parse().unwrap(),
202                TEST_CIPHER_ID_2.parse().unwrap(),
203            ],
204            TEST_ORG_ID.parse().unwrap(),
205            &bitwarden_api_api::apis::ApiClient::new_mocked(|mock| {
206                mock.ciphers_api
207                    .expect_put_delete_many_admin()
208                    .returning(move |request| {
209                        let CipherBulkDeleteRequestModel {
210                            ids,
211                            organization_id,
212                        } = request.unwrap();
213
214                        assert_eq!(
215                            ids,
216                            vec![TEST_CIPHER_ID.to_string(), TEST_CIPHER_ID_2.to_string()],
217                        );
218                        assert_eq!(organization_id, Some(TEST_ORG_ID.to_string()));
219                        Ok(())
220                    });
221            }),
222        )
223        .await
224        .unwrap()
225    }
226}