收口审计治理与套餐任务进展
Constraint: 在线热修前必须保存当前迭代分支全部有效代码进展 Confidence: medium Scope-risk: broad Directive: 后续修改需保持审计事件与业务事务边界一致 Tested: git diff --cached --check Not-tested: 未运行全量测试,提交用于切换分支前保存既有工作
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
stdErrors "errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -108,7 +109,7 @@ func (s *SceneService) ListBusinessFields(ctx context.Context, businessType stri
|
||||
|
||||
// Save 校验模板控件后创建或替换指定稳定业务场景映射。
|
||||
func (s *SceneService) Save(ctx context.Context, businessType string, request dto.SaveWeComApprovalSceneRequest) (*dto.WeComApprovalSceneResponse, error) {
|
||||
if s == nil || s.db == nil || s.provider == nil || s.repo == nil {
|
||||
if s == nil || s.db == nil || s.provider == nil || s.repo == nil || s.audit == nil {
|
||||
return nil, errors.New(errors.CodeServiceUnavailable, "企业微信审批场景服务未配置")
|
||||
}
|
||||
if middleware.GetUserTypeFromContext(ctx) != constants.UserTypeSuperAdmin {
|
||||
@@ -124,9 +125,11 @@ func (s *SceneService) Save(ctx context.Context, businessType string, request dt
|
||||
}
|
||||
definition, err := s.provider.GetTemplateDetail(ctx, request.ApplicationID, strings.TrimSpace(request.TemplateID))
|
||||
if err != nil {
|
||||
s.recordFailure(ctx, businessType, request, constants.AuditResultFailed, errors.CodeInternalError, "校验企业微信审批模板失败")
|
||||
return nil, err
|
||||
}
|
||||
if err := validateSceneMapping(businessType, request.ControlMapping, definition.Controls); err != nil {
|
||||
s.recordFailure(ctx, businessType, request, constants.AuditResultDenied, errors.CodeInvalidParam, "拒绝保存非法企业微信审批场景映射")
|
||||
return nil, err
|
||||
}
|
||||
request.ControlMapping = normalizeSceneMapping(request.ControlMapping)
|
||||
@@ -177,23 +180,27 @@ func (s *SceneService) Save(ctx context.Context, businessType string, request dt
|
||||
} else if err := s.repo.Update(ctx, tx, existing); err != nil {
|
||||
return err
|
||||
}
|
||||
if s.audit != nil {
|
||||
requestID := ""
|
||||
if value := middleware.GetRequestIDFromContext(ctx); value != nil {
|
||||
requestID = *value
|
||||
}
|
||||
if err := s.audit.WriteConfigChange(ctx, tx, systemconfigapp.ChangeAudit{
|
||||
OperatorID: operatorID, OperationType: "wecom_approval_scene_save", Description: "保存企业微信审批模板映射",
|
||||
ConfigKey: "wecom.approval_scene." + businessType, BeforeData: before,
|
||||
AfterData: sceneAuditSnapshot(existing), RequestID: requestID, CorrelationID: requestID,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
requestID := ""
|
||||
if value := middleware.GetRequestIDFromContext(ctx); value != nil {
|
||||
requestID = *value
|
||||
}
|
||||
resourceID := strings.TrimSpace(existing.BusinessType)
|
||||
if existing.ID != 0 {
|
||||
resourceID = fmt.Sprintf("%d", existing.ID)
|
||||
}
|
||||
if err := s.audit.WriteConfigChange(ctx, tx, systemconfigapp.ChangeAudit{
|
||||
OperatorID: operatorID, OperationType: constants.AuditOperationWeComApprovalSceneSave, Description: "保存企业微信审批模板映射",
|
||||
ConfigKey: "wecom.approval_scene." + businessType, BeforeData: before,
|
||||
AfterData: sceneAuditSnapshot(existing), RequestID: requestID, CorrelationID: requestID,
|
||||
ResourceID: &resourceID, DisplayName: existing.TemplateName, Identity: sceneAuditIdentity(existing),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
saved = existing
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
s.recordFailure(ctx, businessType, request, constants.AuditResultFailed, errors.CodeDatabaseError, "保存企业微信审批场景失败")
|
||||
var appErr *errors.AppError
|
||||
if stdErrors.As(err, &appErr) {
|
||||
return nil, appErr
|
||||
@@ -364,6 +371,28 @@ func sceneAuditSnapshot(scene *model.WeComApprovalScene) map[string]any {
|
||||
}
|
||||
}
|
||||
|
||||
func sceneAuditIdentity(scene *model.WeComApprovalScene) map[string]any {
|
||||
if scene == nil {
|
||||
return nil
|
||||
}
|
||||
return map[string]any{
|
||||
"id": scene.ID, "business_type": scene.BusinessType, "application_id": scene.ApplicationID,
|
||||
"template_id": scene.TemplateID, "template_name": scene.TemplateName, "status": scene.Status,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SceneService) recordFailure(ctx context.Context, businessType string, request dto.SaveWeComApprovalSceneRequest, result string, code int, description string) {
|
||||
recordConfigFailure(ctx, s.db, s.audit, systemconfigapp.ChangeAudit{
|
||||
OperatorID: middleware.GetUserIDFromContext(ctx), OperationType: constants.AuditOperationWeComApprovalSceneSave,
|
||||
Description: description, ConfigKey: "wecom.approval_scene." + businessType,
|
||||
DisplayName: businessType, Identity: map[string]any{
|
||||
"business_type": businessType, "application_id": request.ApplicationID,
|
||||
"template_id": strings.TrimSpace(request.TemplateID), "status": request.Status,
|
||||
},
|
||||
Result: result, ErrorCode: fmt.Sprintf("%d", code), ErrorSummary: description,
|
||||
})
|
||||
}
|
||||
|
||||
func sceneResponse(scene model.WeComApprovalScene) (*dto.WeComApprovalSceneResponse, error) {
|
||||
var mapping []dto.WeComControlMappingItem
|
||||
if err := sonic.Unmarshal(scene.ControlMapping, &mapping); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user