refactor(server): audit.WriteOrLog wrapper; migrate 13 sites (T5)
Add audit.WriteOrLog: a one-line wrapper around Write that logs at
Warn and swallows the error, matching the package contract that
audit failures must not break user-facing operations.
Migrate the 13 call sites across 7 files in internal/api/ from the
3-line "if err != nil { logger.Warn(...) }" shape to a single call.
audit.Write stays exported for tests + any future caller that
needs strict semantics.
Adds three tests: success (no log), failure-via-closed-pool (Warn
record with action+err keys), and nil-logger (no panic). Tests
skip when MINSTREL_TEST_DATABASE_URL is unset, matching the
existing harness convention.
This commit is contained in:
@@ -117,9 +117,7 @@ func (h *handlers) handleUpdateUserAdmin(w http.ResponseWriter, r *http.Request)
|
||||
if !req.IsAdmin {
|
||||
action = audit.ActionDemoteAdmin
|
||||
}
|
||||
if err := audit.Write(r.Context(), h.pool, caller.ID, targetID, action, nil); err != nil {
|
||||
h.logger.Warn("admin: promote/demote audit failed", "err", err)
|
||||
}
|
||||
audit.WriteOrLog(r.Context(), h.pool, h.logger, caller.ID, targetID, action, nil)
|
||||
|
||||
writeJSON(w, http.StatusOK, adminUserView{
|
||||
ID: uuidToString(updated.ID),
|
||||
@@ -189,10 +187,8 @@ func (h *handlers) handleAdminCreateUser(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
if err := audit.Write(r.Context(), h.pool, caller.ID, user.ID, audit.ActionCreateUserAdmin,
|
||||
map[string]any{"is_admin": req.IsAdmin}); err != nil {
|
||||
h.logger.Warn("admin create user: audit failed", "err", err)
|
||||
}
|
||||
audit.WriteOrLog(r.Context(), h.pool, h.logger, caller.ID, user.ID, audit.ActionCreateUserAdmin,
|
||||
map[string]any{"is_admin": req.IsAdmin})
|
||||
|
||||
writeJSON(w, http.StatusOK, adminUserView{
|
||||
ID: uuidToString(user.ID),
|
||||
@@ -239,10 +235,8 @@ func (h *handlers) handleAdminDeleteUser(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
if err := audit.Write(r.Context(), h.pool, caller.ID, target.ID, audit.ActionDeleteUser,
|
||||
map[string]any{"username": target.Username, "was_admin": target.IsAdmin}); err != nil {
|
||||
h.logger.Warn("admin delete user: audit failed", "err", err)
|
||||
}
|
||||
audit.WriteOrLog(r.Context(), h.pool, h.logger, caller.ID, target.ID, audit.ActionDeleteUser,
|
||||
map[string]any{"username": target.Username, "was_admin": target.IsAdmin})
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
@@ -298,9 +292,7 @@ func (h *handlers) handleAdminResetPassword(w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
if err := audit.Write(r.Context(), h.pool, caller.ID, targetID, audit.ActionPasswordResetAdmin, nil); err != nil {
|
||||
h.logger.Warn("admin reset password: audit failed", "err", err)
|
||||
}
|
||||
audit.WriteOrLog(r.Context(), h.pool, h.logger, caller.ID, targetID, audit.ActionPasswordResetAdmin, nil)
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
@@ -342,10 +334,8 @@ func (h *handlers) handleAdminAutoApproveToggle(w http.ResponseWriter, r *http.R
|
||||
return
|
||||
}
|
||||
|
||||
if err := audit.Write(r.Context(), h.pool, caller.ID, targetID, audit.ActionAutoApproveToggle,
|
||||
map[string]any{"auto_approve": req.AutoApprove}); err != nil {
|
||||
h.logger.Warn("admin auto-approve: audit failed", "err", err)
|
||||
}
|
||||
audit.WriteOrLog(r.Context(), h.pool, h.logger, caller.ID, targetID, audit.ActionAutoApproveToggle,
|
||||
map[string]any{"auto_approve": req.AutoApprove})
|
||||
|
||||
writeJSON(w, http.StatusOK, adminUserView{
|
||||
ID: uuidToString(updated.ID),
|
||||
|
||||
Reference in New Issue
Block a user