use uuid::Uuid; use crate::error::AppError; use crate::models::common::{EventType, JsonValue, Role, TargetType}; use crate::models::workspaces::{Workspace, WorkspaceAuditLog}; use crate::service::WorkspaceService; use crate::session::Session; use super::util::clamp_limit_offset; impl WorkspaceService { pub async fn workspace_audit_logs( &self, ctx: &Session, ws: &Workspace, limit: i64, offset: i64, ) -> Result, AppError> { let user_uid = ctx.user().ok_or(AppError::Unauthorized)?; self.ensure_workspace_role_at_least(user_uid, &ws, Role::Admin) .await?; let (limit, offset) = clamp_limit_offset(limit, offset); sqlx::query_as::<_, WorkspaceAuditLog>( "SELECT id, workspace_id, actor_id, action, target_type, target_id, \ ip_address, user_agent, metadata, created_at FROM workspace_audit_log \ WHERE workspace_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3", ) .bind(ws.id) .bind(limit) .bind(offset) .fetch_all(self.ctx.db.reader()) .await .map_err(AppError::Database) } #[allow(clippy::too_many_arguments)] pub async fn workspace_log_audit( &self, workspace_id: Uuid, actor_id: Uuid, action: EventType, target_type: Option, target_id: Option, ip_address: Option, user_agent: Option, metadata: Option, ) -> Result<(), AppError> { sqlx::query( "INSERT INTO workspace_audit_log (id, workspace_id, actor_id, action, target_type, \ target_id, ip_address, user_agent, metadata, created_at) \ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", ) .bind(Uuid::now_v7()) .bind(workspace_id) .bind(actor_id) .bind(action) .bind(target_type) .bind(target_id) .bind(ip_address) .bind(user_agent) .bind(metadata) .bind(chrono::Utc::now()) .execute(self.ctx.db.writer()) .await .map_err(AppError::Database)?; Ok(()) } }