diff --git a/backend/internal/domain/models.go b/backend/internal/domain/models.go index 18244817..e21e91fe 100644 --- a/backend/internal/domain/models.go +++ b/backend/internal/domain/models.go @@ -24,6 +24,7 @@ type AuditLog struct { type AuditRepository interface { Create(log *AuditLog) error FindPage(ctx context.Context, limit int, cursor *AuditCursor) ([]AuditLog, error) + FindByUserAndEvents(ctx context.Context, userID string, eventTypes []string, limit int) ([]AuditLog, error) Ping(ctx context.Context) error } diff --git a/backend/internal/middleware/audit_middleware_test.go b/backend/internal/middleware/audit_middleware_test.go index 4042dd72..cf859370 100644 --- a/backend/internal/middleware/audit_middleware_test.go +++ b/backend/internal/middleware/audit_middleware_test.go @@ -29,6 +29,11 @@ func (m *MockAuditRepository) FindPage(ctx context.Context, limit int, cursor *d return args.Get(0).([]domain.AuditLog), args.Error(1) } +func (m *MockAuditRepository) FindByUserAndEvents(ctx context.Context, userID string, eventTypes []string, limit int) ([]domain.AuditLog, error) { + args := m.Called(ctx, userID, eventTypes, limit) + return args.Get(0).([]domain.AuditLog), args.Error(1) +} + func (m *MockAuditRepository) Ping(ctx context.Context) error { args := m.Called(ctx) return args.Error(0) diff --git a/backend/internal/repository/clickhouse_repo.go b/backend/internal/repository/clickhouse_repo.go index 141a04e0..ee1c029e 100644 --- a/backend/internal/repository/clickhouse_repo.go +++ b/backend/internal/repository/clickhouse_repo.go @@ -151,6 +151,44 @@ func (r *ClickHouseRepository) FindPage(ctx context.Context, limit int, cursor * return logs, nil } +func (r *ClickHouseRepository) FindByUserAndEvents(ctx context.Context, userID string, eventTypes []string, limit int) ([]domain.AuditLog, error) { + if limit <= 0 { + limit = 100 + } + query := ` + SELECT event_id, timestamp, user_id, event_type, status, ip_address, user_agent, device_id, details + FROM audit_logs + WHERE user_id = ? AND event_type IN (?) + ORDER BY timestamp DESC + LIMIT ? + ` + rows, err := r.conn.Query(ctx, query, userID, eventTypes, limit) + if err != nil { + return nil, fmt.Errorf("failed to query audit logs by user/events: %w", err) + } + defer rows.Close() + + var logs []domain.AuditLog + for rows.Next() { + var log domain.AuditLog + if err := rows.Scan( + &log.EventID, + &log.Timestamp, + &log.UserID, + &log.EventType, + &log.Status, + &log.IPAddress, + &log.UserAgent, + &log.DeviceID, + &log.Details, + ); err != nil { + return nil, fmt.Errorf("failed to scan audit log: %w", err) + } + logs = append(logs, log) + } + return logs, nil +} + func (r *ClickHouseRepository) Ping(ctx context.Context) error { if r.conn == nil { return fmt.Errorf("clickhouse connection is nil")