Files
lijiaoqiao/supply-api/internal/audit/service/audit_service_db.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

122 lines
3.3 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 service
import (
"context"
"errors"
"lijiaoqiao/supply-api/internal/audit/model"
"lijiaoqiao/supply-api/internal/audit/repository"
)
// DatabaseAuditService 数据库-backed审计服务
type DatabaseAuditService struct {
repo repository.AuditRepository
}
// NewDatabaseAuditService 创建数据库-backed审计服务
func NewDatabaseAuditService(repo repository.AuditRepository) *DatabaseAuditService {
return &DatabaseAuditService{repo: repo}
}
// Ensure interface
var _ AuditStoreInterface = (*DatabaseAuditService)(nil)
// Emit 发送审计事件
func (s *DatabaseAuditService) Emit(ctx context.Context, event *model.AuditEvent) error {
// 验证事件
if event == nil {
return ErrInvalidInput
}
if event.EventName == "" {
return ErrMissingEventName
}
// 检查幂等键
if event.IdempotencyKey != "" {
existing, err := s.repo.GetByIdempotencyKey(ctx, event.IdempotencyKey)
if err != nil {
return err
}
if existing != nil {
// 幂等键已存在检查payload是否一致
if isSamePayload(existing, event) {
return repository.ErrDuplicateIdempotencyKey
}
return ErrIdempotencyConflict
}
}
// 发送事件
if err := s.repo.Emit(ctx, event); err != nil {
if errors.Is(err, repository.ErrDuplicateIdempotencyKey) {
return repository.ErrDuplicateIdempotencyKey
}
return err
}
return nil
}
// EmitBatch 批量发送审计事件
func (s *DatabaseAuditService) EmitBatch(ctx context.Context, events []*model.AuditEvent) error {
if len(events) == 0 {
return nil
}
// 验证所有事件
for _, event := range events {
if event == nil {
return ErrInvalidInput
}
if event.EventName == "" {
return ErrMissingEventName
}
}
// 调用仓储批量发送
return s.repo.EmitBatch(ctx, events)
}
// Query 查询审计事件
func (s *DatabaseAuditService) Query(ctx context.Context, filter *EventFilter) ([]*model.AuditEvent, int64, error) {
if filter == nil {
filter = &EventFilter{}
}
// 转换 filter 类型
repoFilter := &repository.EventFilter{
TenantID: filter.TenantID,
Category: filter.Category,
EventName: filter.EventName,
Limit: filter.Limit,
Offset: filter.Offset,
}
if !filter.StartTime.IsZero() {
repoFilter.StartTime = &filter.StartTime
}
if !filter.EndTime.IsZero() {
repoFilter.EndTime = &filter.EndTime
}
return s.repo.Query(ctx, repoFilter)
}
// GetByIdempotencyKey 根据幂等键获取事件
func (s *DatabaseAuditService) GetByIdempotencyKey(ctx context.Context, key string) (*model.AuditEvent, error) {
return s.repo.GetByIdempotencyKey(ctx, key)
}
// GetByEventID 根据事件ID获取事件
func (s *DatabaseAuditService) GetByEventID(ctx context.Context, eventID string) (*model.AuditEvent, error) {
return s.repo.GetByEventID(ctx, eventID)
}
// NewDatabaseAuditServiceWithPool 从数据库连接池创建审计服务
func NewDatabaseAuditServiceWithPool(pool interface {
Query(ctx context.Context, sql string, args ...interface{}) (interface{}, error)
Exec(ctx context.Context, sql string, args ...interface{}) (interface{}, error)
}) *DatabaseAuditService {
// 注意这里需要一个适配器来将通用的pool接口转换为pgxpool.Pool
// 在实际使用中,应该直接使用 NewDatabaseAuditService(repo)
// 这个函数仅用于类型兼容性
return nil
}