//! Ports implemented by the infrastructure layer. use async_trait::async_trait; use uuid::Uuid; use crate::auth::{AccessClaims, AuthEvent, RefreshToken}; use crate::host::{Inventory, OsInfo, Package}; use crate::jobs::{JobKind, JobRun, JobStatus}; use crate::settings::SmtpSettings; use crate::user::{User, UserUpdate}; use crate::DomainError; #[async_trait] pub trait UserRepository: Send + Sync { async fn find_by_id(&self, id: Uuid) -> Result, DomainError>; async fn find_by_email(&self, email: &str) -> Result, DomainError>; async fn list(&self) -> Result, DomainError>; async fn count(&self) -> Result; async fn count_active_admins(&self) -> Result; async fn insert(&self, user: &User) -> Result<(), DomainError>; async fn update(&self, id: Uuid, update: &UserUpdate) -> Result; async fn set_password_hash(&self, id: Uuid, hash: &str) -> Result<(), DomainError>; } #[async_trait] pub trait RefreshTokenRepository: Send + Sync { async fn insert(&self, token: &RefreshToken) -> Result<(), DomainError>; async fn find_by_hash(&self, hash: &str) -> Result, DomainError>; async fn revoke(&self, id: Uuid) -> Result<(), DomainError>; async fn revoke_family(&self, family: Uuid) -> Result<(), DomainError>; } #[async_trait] pub trait AuditLog: Send + Sync { async fn record(&self, event: &AuthEvent) -> Result<(), DomainError>; } pub trait PasswordHasher: Send + Sync { fn hash(&self, password: &str) -> Result; fn verify(&self, password: &str, hash: &str) -> bool; } pub trait AccessTokenIssuer: Send + Sync { fn issue(&self, user: &User) -> Result; fn verify(&self, token: &str) -> Result; } #[async_trait] pub trait SettingsRepository: Send + Sync { async fn get(&self, key: &str) -> Result, DomainError>; async fn set(&self, key: &str, value: &str) -> Result<(), DomainError>; } /// Symmetric encryption for secrets at rest. pub trait Cipher: Send + Sync { fn encrypt(&self, plain: &str) -> Result; fn decrypt(&self, cipher_text: &str) -> Result; } #[async_trait] pub trait Mailer: Send + Sync { async fn send( &self, smtp: &SmtpSettings, to: &[String], subject: &str, body: &str, ) -> Result<(), DomainError>; } #[async_trait] pub trait JobRunRepository: Send + Sync { async fn insert(&self, run: &JobRun) -> Result<(), DomainError>; async fn append_log(&self, id: Uuid, line: &str) -> Result<(), DomainError>; async fn finish(&self, id: Uuid, status: JobStatus) -> Result<(), DomainError>; async fn get(&self, id: Uuid) -> Result, DomainError>; async fn list(&self, limit: u32) -> Result, DomainError>; async fn find_running(&self, kind: JobKind) -> Result, DomainError>; async fn last_finished(&self, kind: JobKind) -> Result, DomainError>; } /// Reads the state of the Debian host. #[async_trait] pub trait HostInspector: Send + Sync { async fn os_info(&self) -> Result; async fn packages(&self) -> Result, DomainError>; } #[async_trait] pub trait InventoryRepository: Send + Sync { async fn save(&self, inventory: &Inventory) -> Result<(), DomainError>; async fn load(&self) -> Result, DomainError>; }