- Fix MaskMap to properly handle []string sensitive fields - Add missing slice handling in sanitizer - Add comprehensive tests for GetMetrics and CreateEventsBatch - Improve audit/handler coverage from 49.8% to 68.8% - Fix test expectations to match actual sanitizer behavior - All tests pass
143 lines
3.7 KiB
Go
143 lines
3.7 KiB
Go
package audit
|
||
|
||
import (
|
||
"context"
|
||
"time"
|
||
|
||
"lijiaoqiao/supply-api/internal/audit/model"
|
||
"lijiaoqiao/supply-api/internal/audit/repository"
|
||
)
|
||
|
||
// PostgresAuditStore DB-backed审计存储
|
||
// 实现了audit.AuditStore接口,供给domain层使用
|
||
type PostgresAuditStore struct {
|
||
repo *repository.PostgresAuditRepository
|
||
}
|
||
|
||
// NewPostgresAuditStore 创建DB-backed审计存储
|
||
func NewPostgresAuditStore(repo *repository.PostgresAuditRepository) *PostgresAuditStore {
|
||
return &PostgresAuditStore{repo: repo}
|
||
}
|
||
|
||
// Ensure interface - compile time check
|
||
var _ AuditStore = (*PostgresAuditStore)(nil)
|
||
|
||
// Emit 发送审计事件
|
||
func (s *PostgresAuditStore) Emit(ctx context.Context, event Event) error {
|
||
// 转换 audit.Event -> model.AuditEvent
|
||
modelEvent := &model.AuditEvent{
|
||
EventID: event.EventID,
|
||
EventName: event.Action,
|
||
EventCategory: "",
|
||
EventSubCategory: "",
|
||
Timestamp: event.CreatedAt,
|
||
TimestampMs: event.CreatedAt.UnixMilli(),
|
||
RequestID: event.RequestID,
|
||
IdempotencyKey: "",
|
||
TenantID: event.TenantID,
|
||
ObjectType: event.ObjectType,
|
||
ObjectID: event.ObjectID,
|
||
Action: event.Action,
|
||
ResultCode: event.ResultCode,
|
||
SourceIP: event.SourceIP,
|
||
}
|
||
return s.repo.Emit(ctx, modelEvent)
|
||
}
|
||
|
||
// Query 查询审计事件
|
||
func (s *PostgresAuditStore) Query(ctx context.Context, filter EventFilter) ([]Event, error) {
|
||
// 转换 EventFilter -> repository.EventFilter
|
||
repoFilter := &repository.EventFilter{
|
||
TenantID: filter.TenantID,
|
||
EventName: filter.Action,
|
||
Limit: filter.Limit,
|
||
}
|
||
|
||
if filter.StartDate != "" {
|
||
t, err := time.Parse("2006-01-02", filter.StartDate)
|
||
if err == nil {
|
||
repoFilter.StartTime = &t
|
||
}
|
||
}
|
||
if filter.EndDate != "" {
|
||
t, err := time.Parse("2006-01-02", filter.EndDate)
|
||
if err == nil {
|
||
// 设置为当天的结束时间
|
||
t = t.Add(24*time.Hour - time.Second)
|
||
repoFilter.EndTime = &t
|
||
}
|
||
}
|
||
|
||
modelEvents, _, err := s.repo.Query(ctx, repoFilter)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 转换 []model.AuditEvent -> []Event
|
||
events := make([]Event, 0, len(modelEvents))
|
||
for _, me := range modelEvents {
|
||
events = append(events, convertEventFromModel(me))
|
||
}
|
||
return events, nil
|
||
}
|
||
|
||
// QueryWithTotal 查询事件并返回总数
|
||
func (s *PostgresAuditStore) QueryWithTotal(ctx context.Context, filter EventFilter) ([]Event, int64, error) {
|
||
repoFilter := &repository.EventFilter{
|
||
TenantID: filter.TenantID,
|
||
EventName: filter.Action,
|
||
Limit: filter.Limit,
|
||
}
|
||
|
||
if filter.StartDate != "" {
|
||
t, err := time.Parse("2006-01-02", filter.StartDate)
|
||
if err == nil {
|
||
repoFilter.StartTime = &t
|
||
}
|
||
}
|
||
if filter.EndDate != "" {
|
||
t, err := time.Parse("2006-01-02", filter.EndDate)
|
||
if err == nil {
|
||
t = t.Add(24*time.Hour - time.Second)
|
||
repoFilter.EndTime = &t
|
||
}
|
||
}
|
||
|
||
modelEvents, total, err := s.repo.Query(ctx, repoFilter)
|
||
if err != nil {
|
||
return nil, 0, err
|
||
}
|
||
|
||
events := make([]Event, 0, len(modelEvents))
|
||
for _, me := range modelEvents {
|
||
events = append(events, convertEventFromModel(me))
|
||
}
|
||
return events, total, nil
|
||
}
|
||
|
||
// GetByID 根据事件ID获取单个事件
|
||
func (s *PostgresAuditStore) GetByID(ctx context.Context, eventID string) (Event, error) {
|
||
modelEvent, err := s.repo.GetByEventID(ctx, eventID)
|
||
if err != nil {
|
||
return Event{}, err
|
||
}
|
||
return convertEventFromModel(modelEvent), nil
|
||
}
|
||
|
||
// convertEventFromModel 将 model.AuditEvent 转换为 audit.Event
|
||
func convertEventFromModel(me *model.AuditEvent) Event {
|
||
return Event{
|
||
EventID: me.EventID,
|
||
TenantID: me.TenantID,
|
||
ObjectType: me.ObjectType,
|
||
ObjectID: me.ObjectID,
|
||
Action: me.Action,
|
||
BeforeState: me.BeforeState,
|
||
AfterState: me.AfterState,
|
||
RequestID: me.RequestID,
|
||
ResultCode: me.ResultCode,
|
||
SourceIP: me.SourceIP,
|
||
CreatedAt: me.CreatedAt,
|
||
}
|
||
}
|