184 lines
5.6 KiB
Rust
184 lines
5.6 KiB
Rust
use crate::AppService;
|
|
use crate::error::AppError;
|
|
use models::DateTimeUtc;
|
|
use models::projects::{MemberRole, project_audit_log};
|
|
use sea_orm::*;
|
|
use serde::{Deserialize, Serialize};
|
|
use serde_json::Value;
|
|
use session::Session;
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
|
|
pub struct AuditLogParams {
|
|
pub action: String,
|
|
pub details: Option<Value>,
|
|
}
|
|
|
|
use utoipa::__dev::ComposeSchema;
|
|
use utoipa::ToSchema;
|
|
use utoipa::openapi::schema::{ObjectBuilder, Type};
|
|
use utoipa::openapi::{KnownFormat, SchemaFormat};
|
|
|
|
#[derive(Deserialize, Serialize, Clone, Debug)]
|
|
pub struct AuditLogResponse {
|
|
pub id: i64,
|
|
pub project_uid: Uuid,
|
|
pub actor_uid: Uuid,
|
|
pub action: String,
|
|
pub details: Option<Value>,
|
|
pub created_at: DateTimeUtc,
|
|
}
|
|
|
|
impl ComposeSchema for AuditLogResponse {
|
|
fn compose(
|
|
_: Vec<utoipa::openapi::RefOr<utoipa::openapi::Schema>>,
|
|
) -> utoipa::openapi::RefOr<utoipa::openapi::Schema> {
|
|
utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(
|
|
ObjectBuilder::new()
|
|
.property(
|
|
"id",
|
|
ObjectBuilder::new().schema_type(Type::Integer).format(Some(
|
|
utoipa::openapi::schema::SchemaFormat::KnownFormat(
|
|
utoipa::openapi::schema::KnownFormat::Int64,
|
|
),
|
|
)),
|
|
)
|
|
.property(
|
|
"project_uid",
|
|
ObjectBuilder::new()
|
|
.schema_type(Type::String)
|
|
.format(Some(SchemaFormat::KnownFormat(KnownFormat::Uuid))),
|
|
)
|
|
.property(
|
|
"actor_uid",
|
|
ObjectBuilder::new()
|
|
.schema_type(Type::String)
|
|
.format(Some(SchemaFormat::KnownFormat(KnownFormat::Uuid))),
|
|
)
|
|
.property("action", ObjectBuilder::new().schema_type(Type::String))
|
|
.property("details", ObjectBuilder::new())
|
|
.required("id")
|
|
.required("project_uid")
|
|
.required("actor_uid")
|
|
.required("action")
|
|
.into(),
|
|
))
|
|
}
|
|
}
|
|
|
|
impl ToSchema for AuditLogResponse {}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, utoipa::ToSchema)]
|
|
pub struct AuditLogListResponse {
|
|
pub logs: Vec<AuditLogResponse>,
|
|
pub total: u64,
|
|
pub page: u64,
|
|
pub per_page: u64,
|
|
}
|
|
|
|
impl From<project_audit_log::Model> for AuditLogResponse {
|
|
fn from(log: project_audit_log::Model) -> Self {
|
|
AuditLogResponse {
|
|
id: log.id,
|
|
project_uid: log.project,
|
|
actor_uid: log.actor,
|
|
action: log.action,
|
|
details: log.details,
|
|
created_at: log.created_at,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl AppService {
|
|
pub async fn project_log_audit(
|
|
&self,
|
|
project_name: String,
|
|
params: AuditLogParams,
|
|
ctx: &Session,
|
|
) -> Result<AuditLogResponse, AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
let project = self.utils_find_project_by_name(project_name).await?;
|
|
|
|
let log = project_audit_log::ActiveModel {
|
|
project: Set(project.id),
|
|
actor: Set(user_uid),
|
|
action: Set(params.action),
|
|
details: Set(params.details),
|
|
created_at: Set(chrono::Utc::now()),
|
|
..Default::default()
|
|
};
|
|
let created_log = log
|
|
.insert(&self.db)
|
|
.await
|
|
.map_err(|_| AppError::UserNotFound)?;
|
|
|
|
Ok(AuditLogResponse::from(created_log))
|
|
}
|
|
|
|
pub async fn project_get_audit_logs(
|
|
&self,
|
|
project_name: String,
|
|
page: Option<u64>,
|
|
per_page: Option<u64>,
|
|
ctx: &Session,
|
|
) -> Result<AuditLogListResponse, AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
let project = self.utils_find_project_by_name(project_name).await?;
|
|
|
|
self.utils_check_project_permission(
|
|
&project.id,
|
|
user_uid,
|
|
&[MemberRole::Owner, MemberRole::Admin],
|
|
)
|
|
.await?;
|
|
let page = page.unwrap_or(1);
|
|
let per_page = per_page.unwrap_or(20);
|
|
|
|
let logs = project_audit_log::Entity::find()
|
|
.filter(project_audit_log::Column::Project.eq(project.id))
|
|
.order_by_desc(project_audit_log::Column::CreatedAt)
|
|
.paginate(&self.db, per_page)
|
|
.fetch_page(page - 1)
|
|
.await
|
|
.map_err(|_| AppError::UserNotFound)?;
|
|
|
|
let total = project_audit_log::Entity::find()
|
|
.filter(project_audit_log::Column::Project.eq(project.id))
|
|
.count(&self.db)
|
|
.await
|
|
.map_err(|_| AppError::UserNotFound)?;
|
|
|
|
let logs = logs.into_iter().map(AuditLogResponse::from).collect();
|
|
|
|
Ok(AuditLogListResponse {
|
|
logs,
|
|
total,
|
|
page,
|
|
per_page,
|
|
})
|
|
}
|
|
|
|
pub async fn project_get_audit_log(
|
|
&self,
|
|
log_id: i64,
|
|
ctx: &Session,
|
|
) -> Result<AuditLogResponse, AppError> {
|
|
let user_uid = ctx.user().ok_or(AppError::Unauthorized)?;
|
|
|
|
let log = project_audit_log::Entity::find_by_id(log_id)
|
|
.one(&self.db)
|
|
.await
|
|
.map_err(|_| AppError::UserNotFound)?
|
|
.ok_or(AppError::UserNotFound)?;
|
|
|
|
self.utils_check_project_permission(
|
|
&log.project,
|
|
user_uid,
|
|
&[MemberRole::Owner, MemberRole::Admin],
|
|
)
|
|
.await?;
|
|
|
|
Ok(AuditLogResponse::from(log))
|
|
}
|
|
}
|