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