feat: sync lijiaoqiao implementation and staging validation artifacts
This commit is contained in:
95
supply-api/internal/audit/audit.go
Normal file
95
supply-api/internal/audit/audit.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package audit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 审计事件
|
||||
type Event struct {
|
||||
EventID string `json:"event_id,omitempty"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
ObjectType string `json:"object_type"`
|
||||
ObjectID int64 `json:"object_id"`
|
||||
Action string `json:"action"`
|
||||
BeforeState map[string]any `json:"before_state,omitempty"`
|
||||
AfterState map[string]any `json:"after_state,omitempty"`
|
||||
RequestID string `json:"request_id,omitempty"`
|
||||
ResultCode string `json:"result_code"`
|
||||
ClientIP string `json:"client_ip,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// 审计存储接口
|
||||
type AuditStore interface {
|
||||
Emit(ctx context.Context, event Event)
|
||||
Query(ctx context.Context, filter EventFilter) ([]Event, error)
|
||||
}
|
||||
|
||||
// 事件过滤器
|
||||
type EventFilter struct {
|
||||
TenantID int64
|
||||
ObjectType string
|
||||
ObjectID int64
|
||||
Action string
|
||||
StartDate string
|
||||
EndDate string
|
||||
Limit int
|
||||
}
|
||||
|
||||
// 内存审计存储
|
||||
type MemoryAuditStore struct {
|
||||
mu sync.RWMutex
|
||||
events []Event
|
||||
nextID int64
|
||||
}
|
||||
|
||||
func NewMemoryAuditStore() *MemoryAuditStore {
|
||||
return &MemoryAuditStore{
|
||||
events: make([]Event, 0),
|
||||
nextID: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *MemoryAuditStore) Emit(ctx context.Context, event Event) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
event.EventID = generateEventID()
|
||||
event.CreatedAt = time.Now()
|
||||
s.events = append(s.events, event)
|
||||
}
|
||||
|
||||
func (s *MemoryAuditStore) Query(ctx context.Context, filter EventFilter) ([]Event, error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
var result []Event
|
||||
for _, event := range s.events {
|
||||
if filter.TenantID > 0 && event.TenantID != filter.TenantID {
|
||||
continue
|
||||
}
|
||||
if filter.ObjectType != "" && event.ObjectType != filter.ObjectType {
|
||||
continue
|
||||
}
|
||||
if filter.ObjectID > 0 && event.ObjectID != filter.ObjectID {
|
||||
continue
|
||||
}
|
||||
if filter.Action != "" && event.Action != filter.Action {
|
||||
continue
|
||||
}
|
||||
result = append(result, event)
|
||||
}
|
||||
|
||||
// 限制返回数量
|
||||
if filter.Limit > 0 && len(result) > filter.Limit {
|
||||
result = result[:filter.Limit]
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func generateEventID() string {
|
||||
return time.Now().Format("20060102150405") + "-evt"
|
||||
}
|
||||
Reference in New Issue
Block a user