aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/api_rooms_bulk_delete.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/api_rooms_bulk_delete.go')
-rw-r--r--internal/admin/api_rooms_bulk_delete.go132
1 files changed, 132 insertions, 0 deletions
diff --git a/internal/admin/api_rooms_bulk_delete.go b/internal/admin/api_rooms_bulk_delete.go
new file mode 100644
index 0000000..6aa0181
--- /dev/null
+++ b/internal/admin/api_rooms_bulk_delete.go
@@ -0,0 +1,132 @@
+package admin
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+
+ "thehouseoficarus/internal/world"
+)
+
+type bulkDeleteRequest struct {
+ IDs []int `json:"ids"`
+}
+
+func (s *AdminServer) handleBulkDelete(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ body, readErr := io.ReadAll(r.Body)
+ r.Body.Close()
+ if readErr != nil {
+ writeJSON(w, map[string]any{"error": fmt.Sprintf("read body: %v", readErr)})
+ return
+ }
+
+ var req bulkDeleteRequest
+ if err := json.Unmarshal(body, &req); err != nil {
+ writeJSON(w, map[string]any{"error": fmt.Sprintf("invalid json: %v", err)})
+ return
+ }
+
+ if len(req.IDs) == 0 {
+ writeJSON(w, map[string]any{"error": "no room ids"})
+ return
+ }
+
+ type roomSnapshot struct {
+ id int
+ path string
+ oldContent []byte
+ }
+
+ snapshots := make([]roomSnapshot, 0, len(req.IDs))
+ for _, id := range req.IDs {
+ path, ok := s.world.GetRoomPath(id)
+ if !ok {
+ writeJSON(w, map[string]any{"error": fmt.Sprintf("room %d not found", id)})
+ return
+ }
+ oldContent, snapErr := snapshotFile(path)
+ if snapErr != nil {
+ writeJSON(w, map[string]any{"error": fmt.Sprintf("snapshot room %d: %v", id, snapErr)})
+ return
+ }
+ snapshots = append(snapshots, roomSnapshot{id: id, path: path, oldContent: oldContent})
+ }
+
+ deletedSet := make(map[int]bool, len(req.IDs))
+ for _, snap := range snapshots {
+ s.detachRoomFromCourse(snap.id)
+ if err := os.Remove(snap.path); err != nil {
+ writeJSON(w, map[string]any{"error": fmt.Sprintf("delete room %d: %v", snap.id, err)})
+ return
+ }
+ deletedSet[snap.id] = true
+ }
+
+ s.world.RebuildRoomIndex(s.dataDir)
+ for _, snap := range snapshots {
+ s.world.ClearRoomState(snap.id)
+ }
+
+ allIDs, _ := listRoomIDs(s.dataDir)
+ var extraFiles []ExtraFile
+ var exitCleaned int
+ for _, otherID := range allIDs {
+ if deletedSet[otherID] {
+ continue
+ }
+ otherRoom, loadErr := s.world.LoadRoom(otherID)
+ if loadErr != nil {
+ continue
+ }
+ changed := false
+ for _, dir := range world.ExitOrder {
+ exit, exists := otherRoom.Exits[dir]
+ if !exists || !deletedSet[exit.Room] {
+ continue
+ }
+ delete(otherRoom.Exits, dir)
+ changed = true
+ }
+ if changed {
+ otherPath, pathOk := s.world.GetRoomPath(otherID)
+ if pathOk {
+ oldExtra, _ := snapshotFile(otherPath)
+ newContent, writeErr := writeYAMLFile(otherPath, otherRoom)
+ if writeErr != nil {
+ continue
+ }
+ extraFiles = append(extraFiles, ExtraFile{
+ FilePath: otherPath,
+ OldContent: oldExtra,
+ NewContent: newContent,
+ })
+ exitCleaned++
+ }
+ }
+ }
+
+ for i := 1; i < len(snapshots); i++ {
+ extraFiles = append(extraFiles, ExtraFile{
+ FilePath: snapshots[i].path,
+ OldContent: snapshots[i].oldContent,
+ IsDelete: true,
+ })
+ }
+
+ s.undoStack.Push(ChangeDesc{
+ Description: fmt.Sprintf("delete %d rooms (cleaned %d exits)", len(req.IDs), exitCleaned),
+ FilePath: snapshots[0].path,
+ OldContent: snapshots[0].oldContent,
+ IsDelete: true,
+ ExtraFiles: extraFiles,
+ })
+
+ writeJSON(w, map[string]any{"ok": true, "count": len(req.IDs)})
+}