Refactor error handling in IAM and CMS crates

- Introduced `RepositoryError` and `ServiceError` enums in both IAM and CMS domains for better error management.
- Updated domain traits and services to return specific error types instead of `anyhow::Result`.
- Enhanced session and OAuth repository implementations to handle errors more explicitly.
- Refactored session service methods to return `Result<T, ServiceError>` for improved error handling.
- Updated HTTP handlers to utilize the new error types.
- Modified password hashing functions to run in a blocking context using `tokio::task::spawn_blocking`.
- Added tests for new error handling mechanisms and async password functions.
This commit is contained in:
asepharyana
2026-07-20 06:14:23 +07:00
parent 5aaedbf787
commit ab1a54b72e
47 changed files with 630 additions and 347 deletions
@@ -15,11 +15,12 @@
//!
//! - `SessionServiceImpl<R, L>` — service over two generic repositories
//! - `new` / `create_session` / `list_all` / `archive_session` — lifecycle ops
use std::convert::TryInto;
use std::path::PathBuf;
use tracing;
use uuid::Uuid;
use crate::domain::error::ServiceError;
use crate::domain::repository::{SessionLockRepository, SessionRepository};
use crate::domain::service::SessionService;
use crate::domain::session::Session;
@@ -47,7 +48,7 @@ impl<R: SessionRepository, L: SessionLockRepository> SessionServiceImpl<R, L> {
}
impl<R: SessionRepository, L: SessionLockRepository> SessionService for SessionServiceImpl<R, L> {
fn create_session(&self, title: &str) -> anyhow::Result<Session> {
fn create_session(&self, title: &str) -> Result<Session, ServiceError> {
let id = Uuid::new_v4().to_string();
let title_owned = if title.is_empty() {
"New Session".to_string()
@@ -56,24 +57,30 @@ impl<R: SessionRepository, L: SessionLockRepository> SessionService for SessionS
};
let session = Session::new(id, title_owned);
tracing::debug!(session_id = %session.id, title = %session.title, "creating new session");
self.session_repo.save_session(&self.base_dir, &session)?;
self.session_repo
.save_session(&self.base_dir, &session)?; // RepositoryError → ServiceError via From
Ok(session)
}
fn list_all(&self) -> anyhow::Result<Vec<Session>> {
fn list_all(&self) -> Result<Vec<Session>, ServiceError> {
tracing::debug!("listing all sessions");
self.session_repo.list_sessions(&self.base_dir)
self.session_repo
.list_sessions(&self.base_dir)
.map_err(ServiceError::Repository)
}
fn archive_session(&self, id: &str) -> anyhow::Result<()> {
fn archive_session(&self, id: &str) -> Result<(), ServiceError> {
tracing::debug!(session_id = %id, "archiving session");
let mut session = self.session_repo.load_session(&self.base_dir, id)?;
let mut session = self.session_repo
.load_session(&self.base_dir, id)?; // RepositoryError → ServiceError
session.archived = true;
session.updated_at = std::time::SystemTime::now()
let millis = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as i64;
self.session_repo.save_session(&self.base_dir, &session)?;
.as_millis();
session.updated_at = millis.try_into().unwrap_or(i64::MAX);
self.session_repo
.save_session(&self.base_dir, &session)?; // RepositoryError → ServiceError
Ok(())
}
}