bitwarden_organizations/
organizations_client.rs1use std::sync::Arc;
4
5use bitwarden_core::{Client, FromClient, OrganizationId};
6use bitwarden_state::repository::{Repository, RepositoryError, RepositoryOption};
7
8use crate::ProfileOrganization;
9
10#[derive(FromClient)]
12pub struct OrganizationsClient {
13 pub(crate) repository: Option<Arc<dyn Repository<ProfileOrganization>>>,
14}
15
16impl OrganizationsClient {
17 pub async fn get_by_id(
20 &self,
21 organization_id: OrganizationId,
22 ) -> Result<Option<ProfileOrganization>, RepositoryError> {
23 self.repository.require()?.get(organization_id).await
24 }
25
26 pub async fn get_all(&self) -> Result<Vec<ProfileOrganization>, RepositoryError> {
28 self.repository.require()?.list().await
29 }
30}
31
32pub trait OrganizationsClientExt {
34 fn organizations(&self) -> OrganizationsClient;
36}
37
38impl OrganizationsClientExt for Client {
39 fn organizations(&self) -> OrganizationsClient {
40 OrganizationsClient::from_client(self)
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use bitwarden_test::MemoryRepository;
47 use uuid::Uuid;
48
49 use super::*;
50 use crate::OrganizationDetails;
51
52 fn organization(id: OrganizationId, name: &str) -> ProfileOrganization {
53 ProfileOrganization {
54 details: OrganizationDetails {
55 id,
56 name: name.to_string(),
57 ..OrganizationDetails::default()
58 },
59 ..ProfileOrganization::default()
60 }
61 }
62
63 async fn client_with(organizations: &[ProfileOrganization]) -> OrganizationsClient {
64 let repository = Arc::new(MemoryRepository::<ProfileOrganization>::default());
65 for org in organizations {
66 repository.set(org.details.id, org.clone()).await.unwrap();
67 }
68 OrganizationsClient {
69 repository: Some(repository),
70 }
71 }
72
73 #[tokio::test]
74 async fn get_by_id_returns_matching_organization() {
75 let id = OrganizationId::new(Uuid::new_v4());
76 let other = OrganizationId::new(Uuid::new_v4());
77 let client = client_with(&[organization(id, "Org"), organization(other, "Other")]).await;
78
79 let result = client.get_by_id(id).await.unwrap();
80
81 assert_eq!(result, Some(organization(id, "Org")));
82 }
83
84 #[tokio::test]
85 async fn get_by_id_returns_none_when_missing() {
86 let client = client_with(&[]).await;
87
88 let result = client
89 .get_by_id(OrganizationId::new(Uuid::new_v4()))
90 .await
91 .unwrap();
92
93 assert_eq!(result, None);
94 }
95
96 #[tokio::test]
97 async fn get_all_returns_every_organization() {
98 let first = organization(OrganizationId::new(Uuid::new_v4()), "First");
99 let second = organization(OrganizationId::new(Uuid::new_v4()), "Second");
100 let client = client_with(&[first.clone(), second.clone()]).await;
101
102 let mut result = client.get_all().await.unwrap();
103 result.sort_by(|a, b| a.details.name.cmp(&b.details.name));
104
105 assert_eq!(result, vec![first, second]);
106 }
107
108 #[tokio::test]
109 async fn errors_without_a_repository() {
110 let client = OrganizationsClient { repository: None };
111
112 assert!(client.get_all().await.is_err());
113 assert!(
114 client
115 .get_by_id(OrganizationId::new(Uuid::new_v4()))
116 .await
117 .is_err()
118 );
119 }
120}