bitwarden_vault/folder/
get_list.rs1use bitwarden_crypto::CryptoError;
2use bitwarden_error::bitwarden_error;
3use bitwarden_state::repository::{RepositoryError, RepositoryOption};
4use thiserror::Error;
5#[cfg(feature = "wasm")]
6use wasm_bindgen::prelude::*;
7
8use crate::{FolderId, FolderView, FoldersClient, ItemNotFoundError};
9
10#[allow(missing_docs)]
11#[bitwarden_error(flat)]
12#[derive(Debug, Error)]
13pub enum GetFolderError {
14 #[error(transparent)]
15 ItemNotFound(#[from] ItemNotFoundError),
16 #[error(transparent)]
17 Crypto(#[from] CryptoError),
18 #[error(transparent)]
19 Repository(#[from] RepositoryError),
20}
21
22#[cfg_attr(feature = "wasm", wasm_bindgen)]
23impl FoldersClient {
24 pub async fn get(&self, folder_id: FolderId) -> Result<FolderView, GetFolderError> {
26 let folder = self
27 .repository
28 .require()?
29 .get(folder_id)
30 .await?
31 .ok_or(ItemNotFoundError)?;
32
33 Ok(self.key_store.decrypt(&folder)?)
34 }
35
36 pub async fn list(&self) -> Result<Vec<FolderView>, GetFolderError> {
38 let folders = self.repository.require()?.list().await?;
39 let views = self.key_store.decrypt_list(&folders)?;
40 Ok(views)
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use std::sync::Arc;
47
48 use bitwarden_api_api::apis::ApiClient;
49 use bitwarden_core::{
50 client::ApiConfigurations, key_management::create_test_crypto_with_user_key,
51 };
52 use bitwarden_crypto::SymmetricCryptoKey;
53 use bitwarden_test::MemoryRepository;
54 use uuid::uuid;
55
56 use super::*;
57 use crate::Folder;
58
59 fn create_client() -> FoldersClient {
60 let store =
61 create_test_crypto_with_user_key(SymmetricCryptoKey::make_aes256_cbc_hmac_key());
62 let repository = Arc::new(MemoryRepository::<Folder>::default());
63
64 FoldersClient {
65 key_store: store,
66 api_configurations: Arc::new(ApiConfigurations::from_api_client(
67 ApiClient::new_mocked(|_| {}),
68 )),
69 repository: Some(repository),
70 }
71 }
72
73 fn make_folder(client: &FoldersClient, id: FolderId, name: &str) -> Folder {
74 client
75 .key_store
76 .encrypt(FolderView {
77 id: Some(id),
78 name: name.to_string(),
79 revision_date: "2025-01-01T00:00:00Z".parse().unwrap(),
80 })
81 .unwrap()
82 }
83
84 #[tokio::test]
85 async fn test_get_folder() {
86 let client = create_client();
87 let folder_id = FolderId::new(uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1"));
88 let folder = make_folder(&client, folder_id, "Test Folder");
89
90 client
91 .repository
92 .as_ref()
93 .unwrap()
94 .set(folder_id, folder)
95 .await
96 .unwrap();
97
98 let result = client.get(folder_id).await.unwrap();
99
100 assert_eq!(
101 result,
102 FolderView {
103 id: Some(folder_id),
104 name: "Test Folder".to_string(),
105 revision_date: "2025-01-01T00:00:00Z".parse().unwrap(),
106 }
107 );
108 }
109
110 #[tokio::test]
111 async fn test_get_folder_not_found() {
112 let client = create_client();
113 let folder_id = FolderId::new(uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1"));
114
115 let result = client.get(folder_id).await;
116
117 assert!(result.is_err());
118 assert!(matches!(
119 result.unwrap_err(),
120 GetFolderError::ItemNotFound(_)
121 ));
122 }
123
124 #[tokio::test]
125 async fn test_list_folders() {
126 let client = create_client();
127 let id_a = FolderId::new(uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1"));
128 let id_b = FolderId::new(uuid!("35afb11c-9c95-4db5-8bac-c21cb204a3f2"));
129
130 let repository = client.repository.as_ref().unwrap();
131 repository
132 .set(id_a, make_folder(&client, id_a, "Folder A"))
133 .await
134 .unwrap();
135 repository
136 .set(id_b, make_folder(&client, id_b, "Folder B"))
137 .await
138 .unwrap();
139
140 let mut result = client.list().await.unwrap();
141 result.sort_by(|a, b| a.name.cmp(&b.name));
142
143 assert_eq!(result.len(), 2);
144 assert_eq!(result[0].name, "Folder A");
145 assert_eq!(result[1].name, "Folder B");
146 }
147
148 #[tokio::test]
149 async fn test_list_folders_empty() {
150 let client = create_client();
151
152 let result = client.list().await.unwrap();
153
154 assert!(result.is_empty());
155 }
156}