Files
lijiaoqiao/supply-api/internal/audit/postgres_audit_store.go
Your Name 8ac23bf7d4 test: improve coverage and fix sanitizer bug
- 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
2026-04-08 07:44:58 +08:00

143 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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,
}
}