57 lines
1.8 KiB
Go
57 lines
1.8 KiB
Go
package audit
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
type Entry struct {
|
|
ID int64 `json:"id"`
|
|
OccurredAt string `json:"occurred_at"`
|
|
ActorUserID *string `json:"actor_user_id,omitempty"`
|
|
Action string `json:"action"`
|
|
TargetType string `json:"target_type"`
|
|
TargetID *string `json:"target_id,omitempty"`
|
|
Outcome string `json:"outcome"`
|
|
Details map[string]any `json:"details"`
|
|
}
|
|
|
|
type Store struct{ DB *pgxpool.Pool }
|
|
|
|
func (s Store) Record(ctx context.Context, actorUserID *string, action, targetType string, targetID *string, outcome string, details map[string]any) error {
|
|
data, err := json.Marshal(details)
|
|
if err != nil {
|
|
return fmt.Errorf("encode audit details: %w", err)
|
|
}
|
|
_, err = s.DB.Exec(ctx, `INSERT INTO bell_audit_log(actor_user_id,action,target_type,target_id,outcome,details) VALUES($1,$2,$3,$4,$5,$6)`, actorUserID, action, targetType, targetID, outcome, data)
|
|
if err != nil {
|
|
return fmt.Errorf("append audit entry: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s Store) List(ctx context.Context, limit int) ([]Entry, error) {
|
|
if limit < 1 || limit > 200 {
|
|
limit = 50
|
|
}
|
|
rows, err := s.DB.Query(ctx, `SELECT id,occurred_at::text,actor_user_id::text,action,target_type,target_id,outcome,details FROM bell_audit_log ORDER BY id DESC LIMIT $1`, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
entries := make([]Entry, 0, limit)
|
|
for rows.Next() {
|
|
var e Entry
|
|
var data []byte
|
|
if err := rows.Scan(&e.ID, &e.OccurredAt, &e.ActorUserID, &e.Action, &e.TargetType, &e.TargetID, &e.Outcome, &data); err != nil {
|
|
return nil, err
|
|
}
|
|
_ = json.Unmarshal(data, &e.Details)
|
|
entries = append(entries, e)
|
|
}
|
|
return entries, rows.Err()
|
|
}
|