use crate::error::Result;
use crate::provider::{AwsProvider, CloudProvider};
use crate::store::traits::LoginProfileStore;
use crate::wami::credentials::login_profile::{
builder as login_builder, CreateLoginProfileRequest, LoginProfile, UpdateLoginProfileRequest,
};
use std::sync::{Arc, RwLock};
pub struct LoginProfileService<S> {
store: Arc<RwLock<S>>,
provider: Arc<dyn CloudProvider>,
account_id: String,
}
impl<S: LoginProfileStore> LoginProfileService<S> {
pub fn new(store: Arc<RwLock<S>>, account_id: String) -> Self {
Self {
store,
provider: Arc::new(AwsProvider::new()),
account_id,
}
}
pub fn with_provider(&self, provider: Arc<dyn CloudProvider>) -> Self {
Self {
store: self.store.clone(),
provider,
account_id: self.account_id.clone(),
}
}
pub async fn create_login_profile(
&self,
request: CreateLoginProfileRequest,
) -> Result<LoginProfile> {
let login_profile = login_builder::build_login_profile(
request.user_name,
request.password_reset_required,
&*self.provider,
&self.account_id,
);
self.store
.write()
.unwrap()
.create_login_profile(login_profile)
.await
}
pub async fn get_login_profile(&self, user_name: &str) -> Result<Option<LoginProfile>> {
self.store
.read()
.unwrap()
.get_login_profile(user_name)
.await
}
pub async fn update_login_profile(
&self,
request: UpdateLoginProfileRequest,
) -> Result<LoginProfile> {
let profile = self
.store
.read()
.unwrap()
.get_login_profile(&request.user_name)
.await?
.ok_or_else(|| crate::error::AmiError::ResourceNotFound {
resource: format!("LoginProfile for user: {}", request.user_name),
})?;
let updated_profile =
login_builder::update_login_profile(profile, request.password_reset_required);
self.store
.write()
.unwrap()
.update_login_profile(updated_profile)
.await
}
pub async fn delete_login_profile(&self, user_name: &str) -> Result<()> {
self.store
.write()
.unwrap()
.delete_login_profile(user_name)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::store::memory::InMemoryWamiStore;
fn setup_service() -> LoginProfileService<InMemoryWamiStore> {
let store = Arc::new(RwLock::new(InMemoryWamiStore::default()));
LoginProfileService::new(store, "123456789012".to_string())
}
#[tokio::test]
async fn test_create_and_get_login_profile() {
let service = setup_service();
let request = CreateLoginProfileRequest {
user_name: "alice".to_string(),
password: "P@ssw0rd123!".to_string(), password_reset_required: true,
};
let profile = service.create_login_profile(request).await.unwrap();
assert_eq!(profile.user_name, "alice");
assert!(profile.password_reset_required);
let retrieved = service.get_login_profile("alice").await.unwrap();
assert!(retrieved.is_some());
let retrieved_profile = retrieved.unwrap();
assert_eq!(retrieved_profile.user_name, "alice");
assert!(retrieved_profile.password_reset_required);
}
#[tokio::test]
async fn test_update_login_profile() {
let service = setup_service();
let create_request = CreateLoginProfileRequest {
user_name: "bob".to_string(),
password: "InitialP@ss123".to_string(),
password_reset_required: true,
};
service.create_login_profile(create_request).await.unwrap();
let update_request = UpdateLoginProfileRequest {
user_name: "bob".to_string(),
password: Some("NewP@ssw0rd456!".to_string()), password_reset_required: Some(false),
};
let updated = service.update_login_profile(update_request).await.unwrap();
assert_eq!(updated.user_name, "bob");
assert!(!updated.password_reset_required);
}
#[tokio::test]
async fn test_delete_login_profile() {
let service = setup_service();
let request = CreateLoginProfileRequest {
user_name: "charlie".to_string(),
password: "TempP@ss789".to_string(),
password_reset_required: false,
};
service.create_login_profile(request).await.unwrap();
service.delete_login_profile("charlie").await.unwrap();
let retrieved = service.get_login_profile("charlie").await.unwrap();
assert!(retrieved.is_none());
}
}