feat(core): add audit logging to all mutation operations
Create audit_log SeaORM entity and audit_service::record() helper. Integrate audit recording into 35 mutation endpoints across all modules: - erp-auth: user/role/organization/department/position CRUD (15 actions) - erp-config: dictionary/menu/setting/numbering_rule CRUD (15 actions) - erp-workflow: definition/instance/task operations (8 actions) - erp-message: send/system/mark_read/delete (5 actions) Uses fire-and-forget pattern — audit failures logged but non-blocking.
This commit is contained in:
@@ -8,6 +8,8 @@ use crate::dto::{CreateDepartmentReq, DepartmentResp, UpdateDepartmentReq};
|
||||
use crate::entity::department;
|
||||
use crate::entity::organization;
|
||||
use crate::error::{AuthError, AuthResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
|
||||
@@ -124,6 +126,13 @@ impl DeptService {
|
||||
serde_json::json!({ "dept_id": id, "org_id": org_id, "name": req.name }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "department.create", "department")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(DepartmentResp {
|
||||
id,
|
||||
org_id,
|
||||
@@ -195,6 +204,13 @@ impl DeptService {
|
||||
.await
|
||||
.map_err(|e| AuthError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "department.update", "department")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(DepartmentResp {
|
||||
id: updated.id,
|
||||
org_id: updated.org_id,
|
||||
@@ -256,6 +272,14 @@ impl DeptService {
|
||||
tenant_id,
|
||||
serde_json::json!({ "dept_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "department.delete", "department")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ use uuid::Uuid;
|
||||
use crate::dto::{CreateOrganizationReq, OrganizationResp, UpdateOrganizationReq};
|
||||
use crate::entity::organization;
|
||||
use crate::error::{AuthError, AuthResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
|
||||
@@ -110,6 +112,13 @@ impl OrgService {
|
||||
serde_json::json!({ "org_id": id, "name": req.name }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "organization.create", "organization")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(OrganizationResp {
|
||||
id,
|
||||
name: req.name.clone(),
|
||||
@@ -177,6 +186,13 @@ impl OrgService {
|
||||
.await
|
||||
.map_err(|e| AuthError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "organization.update", "organization")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(OrganizationResp {
|
||||
id: updated.id,
|
||||
name: updated.name.clone(),
|
||||
@@ -235,6 +251,14 @@ impl OrgService {
|
||||
tenant_id,
|
||||
serde_json::json!({ "org_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "organization.delete", "organization")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ use crate::dto::{CreatePositionReq, PositionResp, UpdatePositionReq};
|
||||
use crate::entity::department;
|
||||
use crate::entity::position;
|
||||
use crate::error::{AuthError, AuthResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
|
||||
@@ -109,6 +111,13 @@ impl PositionService {
|
||||
serde_json::json!({ "position_id": id, "dept_id": dept_id, "name": req.name }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "position.create", "position")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(PositionResp {
|
||||
id,
|
||||
dept_id,
|
||||
@@ -177,6 +186,13 @@ impl PositionService {
|
||||
.await
|
||||
.map_err(|e| AuthError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "position.update", "position")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(PositionResp {
|
||||
id: updated.id,
|
||||
dept_id: updated.dept_id,
|
||||
@@ -219,6 +235,14 @@ impl PositionService {
|
||||
tenant_id,
|
||||
serde_json::json!({ "position_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "position.delete", "position")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ use crate::dto::{PermissionResp, RoleResp};
|
||||
use crate::entity::{permission, role, role_permission};
|
||||
use crate::error::AuthError;
|
||||
use crate::error::AuthResult;
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::types::Pagination;
|
||||
@@ -131,6 +133,13 @@ impl RoleService {
|
||||
serde_json::json!({ "role_id": id, "code": code }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "role.create", "role")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(RoleResp {
|
||||
id,
|
||||
name: name.to_string(),
|
||||
@@ -180,6 +189,13 @@ impl RoleService {
|
||||
.await
|
||||
.map_err(|e| AuthError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "role.update", "role")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(RoleResp {
|
||||
id: updated.id,
|
||||
name: updated.name.clone(),
|
||||
@@ -227,6 +243,14 @@ impl RoleService {
|
||||
tenant_id,
|
||||
serde_json::json!({ "role_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "role.delete", "role")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ use uuid::Uuid;
|
||||
use crate::dto::{CreateUserReq, RoleResp, UpdateUserReq, UserResp};
|
||||
use crate::entity::{role, user, user_credential, user_role};
|
||||
use crate::error::AuthError;
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::types::Pagination;
|
||||
@@ -94,6 +96,13 @@ impl UserService {
|
||||
serde_json::json!({ "user_id": user_id, "username": req.username }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "user.create", "user")
|
||||
.with_resource_id(user_id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(UserResp {
|
||||
id: user_id,
|
||||
username: req.username.clone(),
|
||||
@@ -215,6 +224,13 @@ impl UserService {
|
||||
.await
|
||||
.map_err(|e| AuthError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "user.update", "user")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
let roles = Self::fetch_user_role_resps(id, tenant_id, db).await?;
|
||||
Ok(model_to_resp(&updated, roles))
|
||||
}
|
||||
@@ -250,6 +266,14 @@ impl UserService {
|
||||
tenant_id,
|
||||
serde_json::json!({ "user_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "user.delete", "user")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ use uuid::Uuid;
|
||||
use crate::dto::{DictionaryItemResp, DictionaryResp};
|
||||
use crate::entity::{dictionary, dictionary_item};
|
||||
use crate::error::{ConfigError, ConfigResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::types::Pagination;
|
||||
@@ -137,6 +139,13 @@ impl DictionaryService {
|
||||
serde_json::json!({ "dictionary_id": id, "code": code }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "dictionary.create", "dictionary")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(DictionaryResp {
|
||||
id,
|
||||
name: name.to_string(),
|
||||
@@ -188,6 +197,13 @@ impl DictionaryService {
|
||||
|
||||
let items = Self::fetch_items(updated.id, tenant_id, db).await?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "dictionary.update", "dictionary")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(DictionaryResp {
|
||||
id: updated.id,
|
||||
name: updated.name.clone(),
|
||||
@@ -234,6 +250,13 @@ impl DictionaryService {
|
||||
serde_json::json!({ "dictionary_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "dictionary.delete", "dictionary")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -291,6 +314,13 @@ impl DictionaryService {
|
||||
.await
|
||||
.map_err(|e| ConfigError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "dictionary_item.create", "dictionary_item")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(DictionaryItemResp {
|
||||
id,
|
||||
dictionary_id,
|
||||
@@ -345,6 +375,13 @@ impl DictionaryService {
|
||||
.await
|
||||
.map_err(|e| ConfigError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "dictionary_item.update", "dictionary_item")
|
||||
.with_resource_id(item_id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(DictionaryItemResp {
|
||||
id: updated.id,
|
||||
dictionary_id: updated.dictionary_id,
|
||||
@@ -385,6 +422,13 @@ impl DictionaryService {
|
||||
.await
|
||||
.map_err(|e| ConfigError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "dictionary_item.delete", "dictionary_item")
|
||||
.with_resource_id(item_id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ use uuid::Uuid;
|
||||
use crate::dto::{CreateMenuReq, MenuResp};
|
||||
use crate::entity::{menu, menu_role};
|
||||
use crate::error::{ConfigError, ConfigResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
|
||||
@@ -156,6 +158,13 @@ impl MenuService {
|
||||
serde_json::json!({ "menu_id": id, "title": req.title }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "menu.create", "menu")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(MenuResp {
|
||||
id,
|
||||
parent_id: req.parent_id,
|
||||
@@ -225,6 +234,13 @@ impl MenuService {
|
||||
Self::assign_roles(id, role_ids, tenant_id, operator_id, db).await?;
|
||||
}
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "menu.update", "menu")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(MenuResp {
|
||||
id: updated.id,
|
||||
parent_id: updated.parent_id,
|
||||
@@ -275,6 +291,13 @@ impl MenuService {
|
||||
serde_json::json!({ "menu_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "menu.delete", "menu")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ use uuid::Uuid;
|
||||
use crate::dto::{CreateNumberingRuleReq, GenerateNumberResp, NumberingRuleResp};
|
||||
use crate::entity::numbering_rule;
|
||||
use crate::error::{ConfigError, ConfigResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::types::Pagination;
|
||||
@@ -107,6 +109,13 @@ impl NumberingService {
|
||||
serde_json::json!({ "rule_id": id, "code": req.code }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "numbering_rule.create", "numbering_rule")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(NumberingRuleResp {
|
||||
id,
|
||||
name: req.name.clone(),
|
||||
@@ -171,6 +180,13 @@ impl NumberingService {
|
||||
.await
|
||||
.map_err(|e| ConfigError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "numbering_rule.update", "numbering_rule")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Self::model_to_resp(&updated))
|
||||
}
|
||||
|
||||
@@ -209,6 +225,13 @@ impl NumberingService {
|
||||
serde_json::json!({ "rule_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "numbering_rule.delete", "numbering_rule")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ use uuid::Uuid;
|
||||
use crate::dto::SettingResp;
|
||||
use crate::entity::setting;
|
||||
use crate::error::{ConfigError, ConfigResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::types::Pagination;
|
||||
@@ -117,6 +119,13 @@ impl SettingService {
|
||||
}),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "setting.upsert", "setting")
|
||||
.with_resource_id(updated.id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Self::model_to_resp(&updated))
|
||||
} else {
|
||||
// Insert new record
|
||||
@@ -151,6 +160,13 @@ impl SettingService {
|
||||
}),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "setting.upsert", "setting")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Self::model_to_resp(&inserted))
|
||||
}
|
||||
}
|
||||
@@ -217,6 +233,7 @@ impl SettingService {
|
||||
let next_version =
|
||||
check_version(version, model.version).map_err(|_| ConfigError::VersionMismatch)?;
|
||||
|
||||
let setting_id = model.id;
|
||||
let mut active: setting::ActiveModel = model.into();
|
||||
active.deleted_at = Set(Some(Utc::now()));
|
||||
active.updated_at = Set(Utc::now());
|
||||
@@ -227,6 +244,13 @@ impl SettingService {
|
||||
.await
|
||||
.map_err(|e| ConfigError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "setting.delete", "setting")
|
||||
.with_resource_id(setting_id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
27
crates/erp-core/src/audit_service.rs
Normal file
27
crates/erp-core/src/audit_service.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use crate::audit::AuditLog;
|
||||
use crate::entity::audit_log;
|
||||
use sea_orm::{ActiveModelTrait, Set};
|
||||
use tracing;
|
||||
|
||||
/// 持久化审计日志到 audit_logs 表。
|
||||
///
|
||||
/// 使用 fire-and-forget 模式:失败仅记录 warning 日志,不影响业务操作。
|
||||
pub async fn record(log: AuditLog, db: &sea_orm::DatabaseConnection) {
|
||||
let model = audit_log::ActiveModel {
|
||||
id: Set(log.id),
|
||||
tenant_id: Set(log.tenant_id),
|
||||
user_id: Set(log.user_id),
|
||||
action: Set(log.action),
|
||||
resource_type: Set(log.resource_type),
|
||||
resource_id: Set(log.resource_id),
|
||||
old_value: Set(log.old_value),
|
||||
new_value: Set(log.new_value),
|
||||
ip_address: Set(log.ip_address),
|
||||
user_agent: Set(log.user_agent),
|
||||
created_at: Set(log.created_at),
|
||||
};
|
||||
|
||||
if let Err(e) = model.insert(db).await {
|
||||
tracing::warn!(error = %e, "审计日志写入失败");
|
||||
}
|
||||
}
|
||||
25
crates/erp-core/src/entity/audit_log.rs
Normal file
25
crates/erp-core/src/entity/audit_log.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 审计日志实体 — 映射 audit_logs 表。
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "audit_logs")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
pub tenant_id: Uuid,
|
||||
pub user_id: Option<Uuid>,
|
||||
pub action: String,
|
||||
pub resource_type: String,
|
||||
pub resource_id: Option<Uuid>,
|
||||
pub old_value: Option<serde_json::Value>,
|
||||
pub new_value: Option<serde_json::Value>,
|
||||
pub ip_address: Option<String>,
|
||||
pub user_agent: Option<String>,
|
||||
pub created_at: DateTimeUtc,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
1
crates/erp-core/src/entity/mod.rs
Normal file
1
crates/erp-core/src/entity/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod audit_log;
|
||||
@@ -1,4 +1,6 @@
|
||||
pub mod audit;
|
||||
pub mod audit_service;
|
||||
pub mod entity;
|
||||
pub mod error;
|
||||
pub mod events;
|
||||
pub mod module;
|
||||
|
||||
@@ -8,6 +8,8 @@ use uuid::Uuid;
|
||||
use crate::dto::{MessageQuery, MessageResp, SendMessageReq, UnreadCountResp};
|
||||
use crate::entity::message;
|
||||
use crate::error::{MessageError, MessageResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::events::EventBus;
|
||||
|
||||
/// 消息服务。
|
||||
@@ -130,6 +132,13 @@ impl MessageService {
|
||||
}),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(sender_id), "message.send", "message")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Self::model_to_resp(&inserted))
|
||||
}
|
||||
|
||||
@@ -191,6 +200,13 @@ impl MessageService {
|
||||
}),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(system_user), "message.send_system", "message")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Self::model_to_resp(&inserted))
|
||||
}
|
||||
|
||||
@@ -230,6 +246,13 @@ impl MessageService {
|
||||
.await
|
||||
.map_err(|e| MessageError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(user_id), "message.mark_read", "message")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -254,6 +277,12 @@ impl MessageService {
|
||||
.await
|
||||
.map_err(|e| MessageError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(user_id), "message.mark_all_read", "message"),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -288,6 +317,13 @@ impl MessageService {
|
||||
.await
|
||||
.map_err(|e| MessageError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(user_id), "message.delete", "message")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ use crate::dto::{
|
||||
use crate::engine::parser;
|
||||
use crate::entity::process_definition;
|
||||
use crate::error::{WorkflowError, WorkflowResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::types::Pagination;
|
||||
@@ -107,6 +109,13 @@ impl DefinitionService {
|
||||
serde_json::json!({ "definition_id": id, "key": req.key }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "process_definition.create", "process_definition")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(ProcessDefinitionResp {
|
||||
id,
|
||||
name: req.name.clone(),
|
||||
@@ -182,6 +191,13 @@ impl DefinitionService {
|
||||
.await
|
||||
.map_err(|e| WorkflowError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "process_definition.update", "process_definition")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Self::model_to_resp(&updated))
|
||||
}
|
||||
|
||||
@@ -231,6 +247,13 @@ impl DefinitionService {
|
||||
serde_json::json!({ "definition_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "process_definition.publish", "process_definition")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Self::model_to_resp(&updated))
|
||||
}
|
||||
|
||||
@@ -259,6 +282,13 @@ impl DefinitionService {
|
||||
.await
|
||||
.map_err(|e| WorkflowError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "process_definition.delete", "process_definition")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ use crate::engine::executor::FlowExecutor;
|
||||
use crate::engine::parser;
|
||||
use crate::entity::{process_definition, process_instance, process_variable, token};
|
||||
use crate::error::{WorkflowError, WorkflowResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::types::Pagination;
|
||||
|
||||
@@ -130,6 +132,13 @@ impl InstanceService {
|
||||
serde_json::json!({ "instance_id": instance_id, "definition_id": definition.id, "started_by": operator_id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "process_instance.start", "process_instance")
|
||||
.with_resource_id(instance_id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
// 查询创建后的实例(包含 token)
|
||||
let instance = process_instance::Entity::find_by_id(instance_id)
|
||||
.one(db)
|
||||
@@ -303,6 +312,14 @@ impl InstanceService {
|
||||
.await
|
||||
.map_err(|e| WorkflowError::Validation(e.to_string()))?;
|
||||
|
||||
let action = format!("process_instance.{}", to_status);
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), action, "process_instance")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ use crate::engine::executor::FlowExecutor;
|
||||
use crate::engine::parser;
|
||||
use crate::entity::{process_definition, process_instance, task};
|
||||
use crate::error::{WorkflowError, WorkflowResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::types::Pagination;
|
||||
|
||||
@@ -242,6 +244,13 @@ impl TaskService {
|
||||
serde_json::json!({ "task_id": id, "outcome": req.outcome }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "task.complete", "task")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
// 重新查询任务
|
||||
let updated = task::Entity::find_by_id(id)
|
||||
.one(db)
|
||||
@@ -311,6 +320,13 @@ impl TaskService {
|
||||
.await
|
||||
.map_err(|e| WorkflowError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "task.delegate", "task")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Self::model_to_resp(&updated))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user