- 新增 iam_schema_v1.sql DDL脚本 (iam_roles, iam_scopes, iam_role_scopes, iam_user_roles, iam_role_hierarchy) - 新增 PostgresIAMRepository 实现数据库-backed IAM仓储 - 新增 DatabaseIAMService 使用数据库-backed Repository - 新增 PostgresAuditRepository 实现数据库-backed Audit仓储 - 新增 DatabaseAuditService 使用数据库-backed Repository - 更新实施状态文档 v1.3 R-07~R-09 完成。
97 lines
2.7 KiB
Go
97 lines
2.7 KiB
Go
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
|
||
}
|
||
|
||
// 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)
|
||
}
|
||
|
||
// 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
|
||
}
|