Projeto bot pontos
This commit is contained in:
78
backend/internal/adapters/postgres/audit.go
Normal file
78
backend/internal/adapters/postgres/audit.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"botpontos/internal/domain"
|
||||
)
|
||||
|
||||
func (s *Store) InsertAudit(ctx context.Context, e domain.AuditEntry) error {
|
||||
details := e.Details
|
||||
if details == nil {
|
||||
details = map[string]any{}
|
||||
}
|
||||
raw, err := json.Marshal(details)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.pool.Exec(ctx, `
|
||||
INSERT INTO audit_logs (source, actor_user_id, actor_account, target_user_id, event_type, success, details)
|
||||
VALUES ($1::text::audit_source, $2, $3, $4, $5, $6, $7::text::jsonb)`,
|
||||
string(e.Source), e.ActorUserID, e.ActorAccount, e.TargetUserID, e.EventType, e.Success, string(raw))
|
||||
return err
|
||||
}
|
||||
|
||||
type AuditFilter struct {
|
||||
From *time.Time
|
||||
To *time.Time
|
||||
Source *string
|
||||
EventType *string
|
||||
Success *bool
|
||||
TargetUserID *int64
|
||||
ActorAccount *int64
|
||||
Before *int64 // cursor: id do último item da página anterior
|
||||
Limit int
|
||||
}
|
||||
|
||||
func (s *Store) ListAudit(ctx context.Context, f AuditFilter) ([]domain.AuditLog, error) {
|
||||
if f.Limit <= 0 || f.Limit > 200 {
|
||||
f.Limit = 50
|
||||
}
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT a.id, a.occurred_at, a.source, a.actor_user_id, au.display_name, a.actor_account, wa.username::text,
|
||||
a.target_user_id, tu.display_name, a.event_type, a.success, a.details::text
|
||||
FROM audit_logs a
|
||||
LEFT JOIN users au ON au.id = a.actor_user_id
|
||||
LEFT JOIN web_accounts wa ON wa.id = a.actor_account
|
||||
LEFT JOIN users tu ON tu.id = a.target_user_id
|
||||
WHERE ($1::timestamptz IS NULL OR a.occurred_at >= $1)
|
||||
AND ($2::timestamptz IS NULL OR a.occurred_at < $2)
|
||||
AND ($3::text IS NULL OR a.source::text = $3)
|
||||
AND ($4::text IS NULL OR a.event_type = $4)
|
||||
AND ($5::boolean IS NULL OR a.success = $5)
|
||||
AND ($6::bigint IS NULL OR a.target_user_id = $6)
|
||||
AND ($7::bigint IS NULL OR a.actor_account = $7)
|
||||
AND ($8::bigint IS NULL OR a.id < $8)
|
||||
ORDER BY a.id DESC
|
||||
LIMIT $9`,
|
||||
f.From, f.To, f.Source, f.EventType, f.Success, f.TargetUserID, f.ActorAccount, f.Before, f.Limit)
|
||||
return collect(rows, err, func(row scanner) (domain.AuditLog, error) {
|
||||
var l domain.AuditLog
|
||||
var source, details string
|
||||
if err := row.Scan(&l.ID, &l.OccurredAt, &source, &l.ActorUserID, &l.ActorUserName, &l.ActorAccount,
|
||||
&l.ActorUsername, &l.TargetUserID, &l.TargetUserName, &l.EventType, &l.Success, &details); err != nil {
|
||||
return l, err
|
||||
}
|
||||
l.Source = domain.AuditSource(source)
|
||||
l.Details = map[string]any{}
|
||||
_ = json.Unmarshal([]byte(details), &l.Details)
|
||||
return l, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Store) DeleteAuditBefore(ctx context.Context, before time.Time) (int64, error) {
|
||||
tag, err := s.pool.Exec(ctx, `DELETE FROM audit_logs WHERE occurred_at < $1`, before)
|
||||
return tag.RowsAffected(), err
|
||||
}
|
||||
Reference in New Issue
Block a user