fix(panel): GUI defects from the 1.2.x layout pass (P3)
- .flash.error now renders on the danger surface instead of the success
one; RateLimitErr previously showed as green with red text.
- User delete goes through a confirmation page (GET/POST
/users/{uid}/delete), matching the domain-delete pattern, instead of a
plain submit button next to Save with no confirmation.
- Extracted the repeated DNS Host/Type/Value markup on a domain's page and
the duplicated Settings credentials form into shared partials. No
behaviour change.
docs/plans/code-review.md P3 checked off; CHANGELOG updated.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -102,10 +102,6 @@ func (h *Handlers) HandleUserEdit(w http.ResponseWriter, r *http.Request) {
|
||||
h.renderUserForm(w, r, http.StatusBadRequest, u.ID, userFormView{FormErr: "Invalid form submission.", FormUsername: u.Username, FormRole: string(u.Role)})
|
||||
return
|
||||
}
|
||||
if r.PostFormValue("action") == "delete" {
|
||||
h.submitUserDelete(w, r, u)
|
||||
return
|
||||
}
|
||||
h.submitUserUpdate(w, r, u)
|
||||
default:
|
||||
w.Header().Set("Allow", "GET, POST")
|
||||
@@ -291,6 +287,58 @@ func (h *Handlers) submitUserUpdate(w http.ResponseWriter, r *http.Request, u st
|
||||
http.Redirect(w, r, "/users?done=updated", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// HandleUserDeleteConfirm shows the cascade warning before a panel user is
|
||||
// removed — the same pattern as HandleDeleteConfirm for domains, so a single
|
||||
// mis-click on Delete cannot remove a user (P3, code-review.md).
|
||||
func (h *Handlers) HandleUserDeleteConfirm(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := h.requireGlobal(w, r); !ok {
|
||||
return
|
||||
}
|
||||
uid, ok := parseUserID(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
u, err := h.store.GetUser(uid)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrUserNotFound) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
logf("panel: get user %d: %v", uid, err)
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
data := h.pageBase(r)
|
||||
data["Title"] = "SelfPost — delete " + u.Username
|
||||
data["Active"] = "users"
|
||||
data["TargetID"] = u.ID
|
||||
data["TargetUsername"] = u.Username
|
||||
h.view.Render(w, http.StatusOK, "user_delete", data)
|
||||
}
|
||||
|
||||
// HandleUserDelete performs the deletion confirmed on HandleUserDeleteConfirm
|
||||
// and returns to the user list.
|
||||
func (h *Handlers) HandleUserDelete(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := h.requireGlobal(w, r); !ok {
|
||||
return
|
||||
}
|
||||
uid, ok := parseUserID(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
u, err := h.store.GetUser(uid)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrUserNotFound) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
logf("panel: get user %d: %v", uid, err)
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
h.submitUserDelete(w, r, u)
|
||||
}
|
||||
|
||||
func (h *Handlers) submitUserDelete(w http.ResponseWriter, r *http.Request, u store.User) {
|
||||
p, ok := h.principal(r)
|
||||
if !ok {
|
||||
|
||||
Reference in New Issue
Block a user