Files
nmon/internal/api/audit.go

49 lines
1.7 KiB
Go

package api
import (
"context"
"net/http"
"time"
"github.com/danielgtaylor/huma/v2"
"github.com/v10networks/nmon/internal/store"
)
// AuditView is one audit-log entry. What changed (before and after) stays in the database: it can hold request
// bodies, and this list is for answering who did what and when.
type AuditView struct {
At time.Time `json:"at"`
Actor string `json:"actor" doc:"Who: an IDP subject, token:<name>, breakglass, console, dev or system."`
Action string `json:"action" example:"device.edit"`
Object string `json:"object"`
}
// AuditList is a page of AuditView, newest first.
type AuditList struct {
Items []AuditView `json:"items"`
Page int64 `json:"page"`
PerPage int64 `json:"per_page"`
Total int64 `json:"total"`
}
func (s *server) registerAudit(api huma.API) {
huma.Register(api, huma.Operation{
OperationID: "list-audit", Method: http.MethodGet, Path: "/api/v1/audit", Tags: []string{"admin"},
Summary: "Audit log",
Description: "Admin only. Who changed what, newest first: logins, token and secret changes, imports, settings, backups.",
}, s.listAudit)
}
func (s *server) listAudit(ctx context.Context, in *struct{ PageParams }) (*struct{ Body AuditList }, error) {
rows, total, err := s.Store.ListAudit(ctx, store.Page{Offset: in.offset(), Limit: in.limit()})
if err != nil {
return nil, s.storeErr(err)
}
out := AuditList{Items: make([]AuditView, 0, len(rows)), Page: in.pageNo(), PerPage: in.limit(), Total: total}
for _, r := range rows {
out.Items = append(out.Items, AuditView{At: r.At.UTC(), Actor: r.Actor, Action: r.Action, Object: r.Object})
}
return &struct{ Body AuditList }{out}, nil
}