P2R-02 slice 2 follow-up: refuse to delete a host's last source group
Belt-and-braces: the UI now disables the Delete button when a group is the only one on the host (with a tooltip explaining why), and the server-side handler returns 409 if a curl/form-replay tries anyway. Every host needs at least one source group to be backup-able, so the 'last group on a fresh host' case is a meaningful accident to guard against.
This commit is contained in:
@@ -310,6 +310,20 @@ func (s *Server) handleUISourceGroupDelete(w stdhttp.ResponseWriter, r *stdhttp.
|
||||
return
|
||||
}
|
||||
|
||||
// Refuse to delete the host's last source group — every host
|
||||
// needs at least one to be backup-able. UI disables the button
|
||||
// in this case; this guards against form-replay / curl.
|
||||
groups, err := s.deps.Store.ListSourceGroupsByHost(r.Context(), host.ID)
|
||||
if err != nil {
|
||||
slog.Error("ui sources: count groups", "err", err)
|
||||
stdhttp.Error(w, "internal", stdhttp.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if len(groups) <= 1 {
|
||||
stdhttp.Error(w, "this is the host's only source group — create another one first", stdhttp.StatusConflict)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.deps.Store.DeleteSourceGroup(r.Context(), host.ID, gid); err != nil {
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
stdhttp.NotFound(w, r)
|
||||
|
||||
Reference in New Issue
Block a user