Skip to content

Commit 085762c

Browse files
committed
feat: moves user operations to a nested User struct
1 parent f402b26 commit 085762c

File tree

4 files changed

+201
-205
lines changed

4 files changed

+201
-205
lines changed

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,5 @@ pub mod models;
6363
pub mod openapi;
6464

6565
pub mod passage_flex;
66+
pub mod user;
6667
pub use passage_flex::PassageFlex;

src/passage_flex.rs

+11-201
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
use crate::models::{AppInfo, UserInfo};
1+
use crate::models::AppInfo;
22
use crate::openapi::apis::configuration::Configuration;
3-
use crate::openapi::apis::{
4-
apps_api, authenticate_api, transactions_api, user_devices_api, users_api,
5-
};
3+
use crate::openapi::apis::{apps_api, authenticate_api, transactions_api};
4+
use crate::user::User;
65
use crate::Error;
76

87
pub struct PassageFlex {
98
app_id: String,
109
configuration: Configuration,
10+
pub user: User,
1111
}
1212

1313
const SERVER_URL: &str = "https://api.passage.id";
@@ -31,10 +31,6 @@ impl PassageFlex {
3131
/// );
3232
/// ```
3333
pub fn new(app_id: String, api_key: String) -> Self {
34-
let mut configuration = Configuration::new();
35-
// Use the api_key as the bearer access token
36-
configuration.bearer_access_token = Some(api_key);
37-
// Set the Passage-Version header to the version of the crate
3834
let mut headers = reqwest::header::HeaderMap::with_capacity(1);
3935
headers.insert(
4036
"Passage-Version",
@@ -43,14 +39,20 @@ impl PassageFlex {
4339
env!("CARGO_PKG_VERSION")
4440
)),
4541
);
42+
43+
let mut configuration = Configuration::new();
44+
configuration.bearer_access_token = Some(api_key);
4645
configuration.client = reqwest::Client::builder()
4746
.default_headers(headers)
4847
.build()
4948
.expect("Failed to create reqwest client for Passage");
5049

50+
let user = User::new(configuration.clone());
51+
5152
let mut client = Self {
5253
app_id,
5354
configuration,
55+
user,
5456
};
5557
// Set the default server URL
5658
client.set_server_url(SERVER_URL.to_string());
@@ -59,7 +61,7 @@ impl PassageFlex {
5961
}
6062

6163
fn set_server_url(&mut self, server_url: String) {
62-
// Use the app_id and server_url to set the base_path
64+
self.user.configuration.base_path = format!("{}/v1/apps/{}", server_url, self.app_id);
6365
self.configuration.base_path = format!("{}/v1/apps/{}", server_url, self.app_id);
6466
}
6567

@@ -219,198 +221,6 @@ impl PassageFlex {
219221
.map(|response| response.external_id)
220222
.map_err(Into::into)
221223
}
222-
223-
/// Get a user's ID in Passage by their external ID
224-
async fn get_id(&self, external_id: String) -> Result<String, Error> {
225-
let users = users_api::list_paginated_users(
226-
&self.configuration,
227-
Some(1),
228-
Some(1),
229-
None,
230-
None,
231-
Some(&external_id),
232-
None,
233-
None,
234-
None,
235-
None,
236-
None,
237-
None,
238-
)
239-
.await
240-
.map(|response| response.users)
241-
.map_err(Into::into);
242-
243-
match users {
244-
Ok(mut users) => match users.len() {
245-
0 => Err(Error::UserNotFound),
246-
1 => {
247-
let user = users.remove(0);
248-
Ok(user.id)
249-
}
250-
_ => Err(Error::Other("Multiple users found".to_string())),
251-
},
252-
Err(e) => Err(e),
253-
}
254-
}
255-
256-
/// Retrieves information about a user by their external ID.
257-
///
258-
/// # Arguments
259-
///
260-
/// * `external_id` - The unique, immutable ID that represents the user.
261-
///
262-
/// # Returns
263-
///
264-
/// A `Result` containing the `UserInfo` struct or an `Error`.
265-
///
266-
/// # Examples
267-
///
268-
/// ```ignore
269-
/// use passage_flex::PassageFlex;
270-
///
271-
/// let passage_flex = PassageFlex::new(
272-
/// std::env::var("PASSAGE_APP_ID").unwrap(),
273-
/// std::env::var("PASSAGE_API_KEY").unwrap(),
274-
/// );
275-
///
276-
/// let external_id = "00000000-0000-0000-0000-000000000001";
277-
/// let user_info = passage_flex.get_user(external_id.to_string()).await.unwrap();
278-
/// println!("{:?}", user_info.id);
279-
/// ```
280-
pub async fn get_user(&self, external_id: String) -> Result<Box<UserInfo>, Error> {
281-
let user_id = self.get_id(external_id).await?;
282-
self.get_user_by_id(user_id).await
283-
}
284-
285-
/// Retrieves information about a user's passkey devices.
286-
///
287-
/// # Arguments
288-
///
289-
/// * `external_id` - The unique, immutable ID that represents the user.
290-
///
291-
/// # Returns
292-
///
293-
/// A `Result` containing a vector of `WebAuthnDevices` or an `Error`.
294-
///
295-
/// # Examples
296-
///
297-
/// ```ignore
298-
/// use passage_flex::PassageFlex;
299-
///
300-
/// let passage_flex = PassageFlex::new(
301-
/// std::env::var("PASSAGE_APP_ID").unwrap(),
302-
/// std::env::var("PASSAGE_API_KEY").unwrap(),
303-
/// );
304-
///
305-
/// let external_id = "00000000-0000-0000-0000-000000000001";
306-
/// let passkey_devices = passage_flex.get_devices(external_id.to_string()).await.unwrap();
307-
/// for device in passkey_devices {
308-
/// println!("{}", device.usage_count);
309-
/// }
310-
/// ```
311-
pub async fn get_devices(
312-
&self,
313-
external_id: String,
314-
) -> Result<Vec<crate::openapi::models::WebAuthnDevices>, Error> {
315-
let user_id = self.get_id(external_id).await?;
316-
user_devices_api::list_user_devices(&self.configuration, &user_id)
317-
.await
318-
.map(|response| response.devices)
319-
.map_err(Into::into)
320-
}
321-
322-
/// Revokes a user's passkey device.
323-
///
324-
/// # Arguments
325-
///
326-
/// * `external_id` - The unique, immutable ID that represents the user.
327-
/// * `device_id` - The ID of the device to be revoked.
328-
///
329-
/// # Returns
330-
///
331-
/// A `Result` containing `()` or an `Error`.
332-
///
333-
/// # Examples
334-
///
335-
/// ```ignore
336-
/// use passage_flex::PassageFlex;
337-
/// use chrono::{Duration, NaiveDate, Utc};
338-
///
339-
/// let passage_flex = PassageFlex::new(
340-
/// std::env::var("PASSAGE_APP_ID").unwrap(),
341-
/// std::env::var("PASSAGE_API_KEY").unwrap(),
342-
/// );
343-
///
344-
/// let external_id = "00000000-0000-0000-0000-000000000001";
345-
/// let last_year = Utc::now().naive_utc().date() - Duration::days(365);
346-
///
347-
/// let passkey_devices = passage_flex.get_devices(external_id.to_string()).await.unwrap();
348-
///
349-
/// for device in passkey_devices {
350-
/// let last_login_at_parsed =
351-
/// NaiveDate::parse_from_str(&device.last_login_at, "%Y-%m-%dT%H:%M:%S%z").unwrap();
352-
///
353-
/// if last_login_at_parsed < last_year {
354-
/// if let Err(err) = passage_flex
355-
/// .revoke_device(external_id.clone(), device.id)
356-
/// .await
357-
/// {
358-
/// // device couldn't be revoked
359-
/// }
360-
/// }
361-
/// }
362-
/// ```
363-
pub async fn revoke_device(&self, external_id: String, device_id: String) -> Result<(), Error> {
364-
let user_id = self.get_id(external_id).await?;
365-
user_devices_api::delete_user_devices(&self.configuration, &user_id, &device_id)
366-
.await
367-
.map_err(Into::into)
368-
}
369-
370-
/// Retrieves information about a user by their user ID in Passage.
371-
///
372-
/// # Arguments
373-
///
374-
/// * `user_id` - The ID of the user in Passage.
375-
///
376-
/// # Returns
377-
///
378-
/// A `Result` containing the `UserInfo` struct or an `Error`.
379-
///
380-
/// # Examples
381-
///
382-
/// ```ignore
383-
/// use passage_flex::PassageFlex;
384-
///
385-
/// let passage_flex = PassageFlex::new(
386-
/// std::env::var("PASSAGE_APP_ID").unwrap(),
387-
/// std::env::var("PASSAGE_API_KEY").unwrap(),
388-
/// );
389-
///
390-
/// let user_id = "user_id_string";
391-
/// let user_info = passage_flex.get_user_by_id(user_id.to_string()).await.unwrap();
392-
/// println!("{:?}", user_info.external_id);
393-
/// ```
394-
pub async fn get_user_by_id(&self, user_id: String) -> Result<Box<UserInfo>, Error> {
395-
users_api::get_user(&self.configuration, &user_id)
396-
.await
397-
.map(|response| {
398-
Box::new(UserInfo {
399-
created_at: response.user.created_at,
400-
external_id: response.user.external_id,
401-
id: response.user.id,
402-
last_login_at: response.user.last_login_at,
403-
login_count: response.user.login_count,
404-
status: response.user.status,
405-
updated_at: response.user.updated_at,
406-
user_metadata: response.user.user_metadata,
407-
webauthn: response.user.webauthn,
408-
webauthn_devices: response.user.webauthn_devices,
409-
webauthn_types: response.user.webauthn_types,
410-
})
411-
})
412-
.map_err(Into::into)
413-
}
414224
}
415225

416226
#[cfg(test)]

src/passage_flex/test.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -289,15 +289,15 @@ async fn test_get_user() {
289289
let (app_id, passage_flex, mut server) = setup_passage_flex().await;
290290

291291
let m1 = setup_empty_list_paginated_users_mock(&app_id, &mut server).await;
292-
let invalid_result = passage_flex.get_user("invalid".to_string()).await;
292+
let invalid_result = passage_flex.user.get("invalid".to_string()).await;
293293
m1.assert_async().await;
294294
assert!(invalid_result.is_err());
295295
assert!(matches!(invalid_result, Err(Error::UserNotFound)));
296296

297297
let m2 = setup_valid_list_paginated_users_mock(&app_id, &mut server).await;
298298
let m3 = setup_valid_get_user_mock(&app_id, &mut server).await;
299299

300-
let user_info = passage_flex.get_user("valid".to_string()).await.unwrap();
300+
let user_info = passage_flex.user.get("valid".to_string()).await.unwrap();
301301
m2.assert_async().await;
302302
m3.assert_async().await;
303303
assert_eq!(user_info.external_id, "valid");
@@ -308,14 +308,18 @@ async fn test_get_devices() {
308308
let (app_id, passage_flex, mut server) = setup_passage_flex().await;
309309

310310
let m1 = setup_empty_list_paginated_users_mock(&app_id, &mut server).await;
311-
let invalid_result = passage_flex.get_devices("invalid".to_string()).await;
311+
let invalid_result = passage_flex.user.list_devices("invalid".to_string()).await;
312312
m1.assert_async().await;
313313
assert!(invalid_result.is_err());
314314
assert!(matches!(invalid_result, Err(Error::UserNotFound)));
315315

316316
let m2 = setup_valid_list_paginated_users_mock(&app_id, &mut server).await;
317317
let m3 = setup_valid_get_devices_mock(&app_id, &mut server).await;
318-
let devices = passage_flex.get_devices("valid".to_string()).await.unwrap();
318+
let devices = passage_flex
319+
.user
320+
.list_devices("valid".to_string())
321+
.await
322+
.unwrap();
319323
m2.assert_async().await;
320324
m3.assert_async().await;
321325
assert_eq!(devices.len(), 1);
@@ -328,6 +332,7 @@ async fn test_revoke_device() {
328332

329333
let m1 = setup_empty_list_paginated_users_mock(&app_id, &mut server).await;
330334
let invalid_result = passage_flex
335+
.user
331336
.revoke_device("invalid".to_string(), "invalid".to_string())
332337
.await;
333338
m1.assert_async().await;
@@ -337,6 +342,7 @@ async fn test_revoke_device() {
337342
let m2 = setup_valid_list_paginated_users_mock(&app_id, &mut server).await;
338343
let m3 = setup_valid_revoke_device_mock(&app_id, &mut server).await;
339344
let result = passage_flex
345+
.user
340346
.revoke_device("valid".to_string(), "test_device_id".to_string())
341347
.await;
342348
m2.assert_async().await;

0 commit comments

Comments
 (0)