79 lines
2.7 KiB
Go
79 lines
2.7 KiB
Go
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
|
|
}
|