1use bitwarden_core::ApiError;
2use bitwarden_error::bitwarden_error;
3use bitwarden_state::repository::{Repository, RepositoryError};
4use thiserror::Error;
5#[cfg(feature = "wasm")]
6use wasm_bindgen::prelude::*;
7
8use crate::{Send, SendId, send_client::SendClient};
9
10#[allow(missing_docs)]
11#[bitwarden_error(flat)]
12#[derive(Debug, Error)]
13pub enum DeleteSendError {
14 #[error(transparent)]
15 Api(#[from] ApiError),
16 #[error(transparent)]
17 Repository(#[from] RepositoryError),
18}
19
20async fn delete_send<R: Repository<Send> + ?Sized>(
21 api_client: &bitwarden_api_api::apis::ApiClient,
22 repository: &R,
23 send_id: SendId,
24) -> Result<(), DeleteSendError> {
25 api_client
26 .sends_api()
27 .delete(&send_id.to_string())
28 .await
29 .map_err(ApiError::from)?;
30
31 repository.remove(send_id).await?;
32
33 Ok(())
34}
35
36#[cfg_attr(feature = "wasm", wasm_bindgen)]
37impl SendClient {
38 pub async fn delete(&self, send_id: SendId) -> Result<(), DeleteSendError> {
40 let config = self.client.internal.get_api_configurations();
41 let repository = self.get_repository()?;
42
43 delete_send(&config.api_client, repository.as_ref(), send_id).await
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use bitwarden_api_api::apis::ApiClient;
50 use bitwarden_core::key_management::{KeySlotIds, SymmetricKeySlotId};
51 use bitwarden_crypto::{KeyStore, SymmetricKeyAlgorithm};
52 use bitwarden_test::MemoryRepository;
53 use uuid::uuid;
54
55 use super::*;
56 use crate::{AuthType, Send, SendId, SendTextView, SendType, SendView};
57
58 async fn make_store_with_send(
59 send_id: uuid::Uuid,
60 ) -> (KeyStore<KeySlotIds>, MemoryRepository<Send>) {
61 let store: KeyStore<KeySlotIds> = KeyStore::default();
62 {
63 let mut ctx = store.context_mut();
64 let local_key_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
65 ctx.persist_symmetric_key(local_key_id, SymmetricKeySlotId::User)
66 .unwrap();
67 }
68
69 let repository = MemoryRepository::<Send>::default();
70 let send_view = SendView {
71 id: None,
72 access_id: None,
73 name: "Test Send".to_string(),
74 notes: None,
75 key: None,
76 new_password: None,
77 has_password: false,
78 r#type: SendType::Text,
79 file: None,
80 text: Some(SendTextView {
81 text: Some("Secret text".to_string()),
82 hidden: false,
83 }),
84 max_access_count: None,
85 access_count: 0,
86 disabled: false,
87 hide_email: false,
88 revision_date: "2025-01-01T00:00:00Z".parse().unwrap(),
89 deletion_date: "2025-01-10T00:00:00Z".parse().unwrap(),
90 expiration_date: None,
91 emails: Vec::new(),
92 auth_type: AuthType::None,
93 };
94 let mut send = store.encrypt(send_view).unwrap();
95 send.id = Some(SendId::new(send_id));
96 repository.set(SendId::new(send_id), send).await.unwrap();
97
98 (store, repository)
99 }
100
101 #[tokio::test]
102 async fn test_delete_send() {
103 let send_id = uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1");
104 let (_store, repository) = make_store_with_send(send_id).await;
105
106 let api_client = ApiClient::new_mocked(move |mock| {
107 mock.sends_api
108 .expect_delete()
109 .returning(move |_id| Ok(()))
110 .once();
111 });
112
113 let result = delete_send(&api_client, &repository, SendId::new(send_id)).await;
114
115 assert!(result.is_ok());
116 assert!(
117 repository
118 .get(SendId::new(send_id))
119 .await
120 .unwrap()
121 .is_none()
122 );
123 }
124
125 #[tokio::test]
126 async fn test_delete_send_http_error() {
127 let send_id = uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1");
128 let (_store, repository) = make_store_with_send(send_id).await;
129
130 let api_client = ApiClient::new_mocked(move |mock| {
131 mock.sends_api
132 .expect_delete()
133 .returning(move |_id| {
134 Err(bitwarden_api_api::apis::Error::Io(std::io::Error::other(
135 "Simulated error",
136 )))
137 })
138 .once();
139 });
140
141 let result = delete_send(&api_client, &repository, SendId::new(send_id)).await;
142
143 assert!(result.is_err());
144 assert!(matches!(result.unwrap_err(), DeleteSendError::Api(_)));
145 assert!(
147 repository
148 .get(SendId::new(send_id))
149 .await
150 .unwrap()
151 .is_some()
152 );
153 }
154}