use super::{Account, AccountRepository};
use crate::accounts::{AccountOperation, AccountsError};
use crate::authz::AccessHierarchy;
use crate::errors::Error;
use crate::secrets::SecretRepository;
use std::sync::Arc;
#[cfg(feature = "audit-logging")]
use crate::audit;
use crate::errors::Result;
use tracing::{debug, error, info, warn};
pub struct AccountDeleteService<R, G>
where
R: AccessHierarchy + Eq,
G: Eq + Clone,
{
account: Account<R, G>,
}
impl<R, G> AccountDeleteService<R, G>
where
R: AccessHierarchy + Eq,
G: Eq + Clone,
{
pub fn delete(account: Account<R, G>) -> Self {
Self { account }
}
pub async fn from_repositories<AccRepo, SecRepo>(
self,
account_repository: Arc<AccRepo>,
secret_repository: Arc<SecRepo>,
) -> Result<()>
where
AccRepo: AccountRepository<R, G>,
SecRepo: SecretRepository,
{
let user_id = &self.account.user_id;
let account_id = &self.account.account_id;
info!(%user_id, %account_id, "Starting account deletion");
#[cfg(feature = "audit-logging")]
audit::account_delete_start(user_id, account_id);
let Some(secret) = secret_repository.delete_secret(account_id).await? else {
error!(%user_id, %account_id, "Secret missing for account deletion attempt");
#[cfg(feature = "audit-logging")]
audit::account_delete_failure(user_id, account_id, None, "secret_missing");
return Err(Error::Accounts(AccountsError::operation(
AccountOperation::Delete,
"Secret not found",
Some(account_id.to_string()),
)));
};
debug!(%user_id, %account_id, "Secret removed for account");
if account_repository.delete_account(user_id).await?.is_none() {
error!(%user_id, %account_id, "Account deletion failed; attempting secret restore");
let restore_result = secret_repository.store_secret(secret).await;
match restore_result {
Ok(true) => {
warn!(%user_id, %account_id, "Secret restored after account deletion failure");
#[cfg(feature = "audit-logging")]
audit::account_delete_failure(
user_id,
account_id,
Some(true),
"account_deletion_failed_secret_restored",
);
}
Ok(false) => {
error!(%user_id, %account_id, "Secret restore reported false after account deletion failure");
#[cfg(feature = "audit-logging")]
audit::account_delete_failure(
user_id,
account_id,
Some(false),
"account_deletion_failed_restore_reported_false",
);
}
Err(ref e) => {
error!(error = %e, %user_id, %account_id, "Secret restore failed after account deletion failure");
#[cfg(feature = "audit-logging")]
audit::account_delete_failure(
user_id,
account_id,
None,
&format!("account_deletion_failed_secret_restore_error: {}", e),
);
}
}
return Err(Error::Accounts(AccountsError::operation(
AccountOperation::Delete,
"Account deletion failed",
Some(account_id.to_string()),
)));
}
info!(%user_id, %account_id, "Account deletion succeeded");
#[cfg(feature = "audit-logging")]
audit::account_delete_success(user_id, account_id);
Ok(())
}
}