Files
junhong_cmp_fiber/internal/infrastructure/audit/polling.go
break 5e552d99bc 收口审计治理与套餐任务进展
Constraint: 在线热修前必须保存当前迭代分支全部有效代码进展
Confidence: medium
Scope-risk: broad
Directive: 后续修改需保持审计事件与业务事务边界一致
Tested: git diff --cached --check
Not-tested: 未运行全量测试,提交用于切换分支前保存既有工作
2026-08-05 14:30:54 +08:00

74 lines
2.7 KiB
Go

package audit
import (
"context"
"strconv"
"gorm.io/gorm"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/pkg/constants"
pkgerrors "github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
)
// PollingInput 描述轮询配置、规则或人工任务的审计事实。
type PollingInput struct {
EventID string
ActionCode string
Summary string
ResourceType string
ResourceID uint
ResourceKey string
DisplayName string
OperatorID uint
IdentitySnapshot map[string]any
BeforeData map[string]any
AfterData map[string]any
Metadata map[string]any
Cards []*model.IotCard
Result string
ErrorCode string
ErrorSummary string
}
// WritePolling 将轮询配置、规则或人工任务转换为统一 Audit Event。
func (w *Writer) WritePolling(ctx context.Context, tx *gorm.DB, input PollingInput) error {
if input.OperatorID == 0 || input.ResourceType == "" || input.ResourceKey == "" {
return pkgerrors.New(pkgerrors.CodeInvalidParam, "轮询审计资源或操作者不完整")
}
resourceID := optionalResourceID(input.ResourceID)
resources := []ResourceInput{{
Type: input.ResourceType, ID: resourceID, Key: input.ResourceKey, DisplayName: input.DisplayName,
Relation: constants.AuditResourceRelationPrimary, Role: constants.AuditResourceRolePollingTarget,
IdentitySnapshot: input.IdentitySnapshot, BeforeData: input.BeforeData, AfterData: input.AfterData,
SubjectVisibility: constants.AuditSubjectInternalOnly,
}}
for index, card := range input.Cards {
if card == nil || card.ID == 0 {
continue
}
resources = append(resources, ResourceInput{
Type: constants.AuditResourceIotCard, ID: optionalResourceID(card.ID),
Key: iotCardResourceKey(card), DisplayName: card.ICCID,
Relation: constants.AuditResourceRelationReference, Role: constants.AuditResourceRolePollingCard,
IdentitySnapshot: iotCardIdentity(card), SubjectVisibility: constants.AuditSubjectInternalOnly,
SortOrder: index + 1,
})
}
result := input.Result
if result == "" {
result = constants.AuditResultSuccess
}
return w.Append(ctx, tx, AppendInput{
EventID: input.EventID, ActionCode: input.ActionCode, Summary: input.Summary,
Actor: ActorInput{
Kind: constants.AuditActorAccount, ID: strconv.FormatUint(uint64(input.OperatorID), 10),
Name: middleware.GetUsernameFromContext(ctx),
},
Source: constants.AuditSourceAdminAPI, ScopeType: constants.AuditScopePlatform,
Result: result, ErrorCode: input.ErrorCode, ErrorSummary: input.ErrorSummary,
Metadata: input.Metadata, Resources: resources,
})
}