aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/api_rooms_bulk_delete.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-09-15 20:44:31 -0400
committerhistoria <[not public]>2026-09-15 20:44:31 -0400
commit61881fd0c1a7066293f552be1a747143f70d03ff (patch)
tree74256e16848fd3dbf66ebd8596395be5fa0f8136 /internal/admin/api_rooms_bulk_delete.go
parentfcb806c3445ce56f2e57e208de773b4dac957c8d (diff)
downloadthehouseoficarus-61881fd0c1a7066293f552be1a747143f70d03ff.tar.gz
fix: registration overwrite, recovery chip/payout edge cases, bulk-delete rollback
Diffstat (limited to 'internal/admin/api_rooms_bulk_delete.go')
-rw-r--r--internal/admin/api_rooms_bulk_delete.go22
1 files changed, 22 insertions, 0 deletions
diff --git a/internal/admin/api_rooms_bulk_delete.go b/internal/admin/api_rooms_bulk_delete.go
index 18b10a5..70c2eb6 100644
--- a/internal/admin/api_rooms_bulk_delete.go
+++ b/internal/admin/api_rooms_bulk_delete.go
@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "log"
"net/http"
"os"
@@ -38,6 +39,18 @@ func (s *AdminServer) handleBulkDelete(w http.ResponseWriter, r *http.Request) {
return
}
+ // Duplicate IDs in one request would delete the same file twice: the
+ // second os.Remove fails after the room is already gone, and the
+ // handler aborts without pushing an undo record. Reject up front.
+ seenIDs := make(map[int]bool, len(req.IDs))
+ for _, id := range req.IDs {
+ if seenIDs[id] {
+ writeJSON(w, map[string]any{"error": fmt.Sprintf("duplicate room id %d in request", id)})
+ return
+ }
+ seenIDs[id] = true
+ }
+
type roomSnapshot struct {
id int
path string
@@ -63,6 +76,15 @@ func (s *AdminServer) handleBulkDelete(w http.ResponseWriter, r *http.Request) {
for _, snap := range snapshots {
s.detachRoomFromCourse(snap.id)
if err := os.Remove(snap.path); err != nil {
+ // All-or-nothing: restore every room deleted so far so a failed
+ // bulk delete never strands rooms without an undo record.
+ for _, done := range snapshots {
+ if deletedSet[done.id] {
+ if werr := os.WriteFile(done.path, done.oldContent, 0644); werr != nil {
+ log.Printf("bulk-delete rollback of room %d: %v", done.id, werr)
+ }
+ }
+ }
writeJSON(w, map[string]any{"error": fmt.Sprintf("delete room %d: %v", snap.id, err)})
return
}