feat(audit): P3-08 — audit log UI with filters, sort, CSV export, payload modal #12
@@ -172,22 +172,23 @@ func (s *Server) handleUIAuditCSV(w stdhttp.ResponseWriter, r *stdhttp.Request)
|
||||
|
||||
cw := csv.NewWriter(w)
|
||||
defer cw.Flush()
|
||||
_ = cw.Write([]string{"timestamp_utc", "actor", "user", "user_id", "action", "target_kind", "target_id", "target_name", "payload"})
|
||||
// user_id and target_id are internal ULIDs that carry no meaning
|
||||
// to anyone reading the CSV — the resolved name (or — for system
|
||||
// rows / non-host targets) is what an operator wants. The HTML
|
||||
// page still shows IDs in the Target column for traceability when
|
||||
// no name is available; the CSV is for human reporting only.
|
||||
_ = cw.Write([]string{"timestamp_utc", "actor", "user", "action", "target_kind", "target_name", "payload"})
|
||||
for _, e := range entries {
|
||||
var uid, uname string
|
||||
var uname string
|
||||
if e.UserID != nil {
|
||||
uid = *e.UserID
|
||||
uname = userNames[uid]
|
||||
uname = userNames[*e.UserID]
|
||||
}
|
||||
var tk, tid, tname string
|
||||
var tk, tname string
|
||||
if e.TargetKind != nil {
|
||||
tk = *e.TargetKind
|
||||
}
|
||||
if e.TargetID != nil {
|
||||
tid = *e.TargetID
|
||||
}
|
||||
if tk == "host" {
|
||||
tname = hostNames[tid]
|
||||
if tk == "host" && e.TargetID != nil {
|
||||
tname = hostNames[*e.TargetID]
|
||||
}
|
||||
payload := ""
|
||||
if len(e.Payload) > 0 {
|
||||
@@ -195,8 +196,7 @@ func (s *Server) handleUIAuditCSV(w stdhttp.ResponseWriter, r *stdhttp.Request)
|
||||
}
|
||||
_ = cw.Write([]string{
|
||||
e.TS.UTC().Format("2006-01-02 15:04:05"),
|
||||
e.Actor, uname, uid, e.Action,
|
||||
tk, tid, tname, payload,
|
||||
e.Actor, uname, e.Action, tk, tname, payload,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user