diff options
| author | historia <[not public]> | 2026-10-06 12:57:23 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-10-06 12:57:23 -0400 |
| commit | 9666676766bf21364f4fc4d0d1d336e72f2a91b4 (patch) | |
| tree | 0cade34091d7602790dc38cd44053f0b74bbadf2 /internal/admin | |
| parent | 4bc1daaf259e0c19c5fe4a12ec8bc7f6e5a735c1 (diff) | |
| download | thehouseoficarus-9666676766bf21364f4fc4d0d1d336e72f2a91b4.tar.gz | |
refactor: split casino.go, dedup helpers, remove audit docs
Diffstat (limited to 'internal/admin')
| -rw-r--r-- | internal/admin/api_entity.go | 9 | ||||
| -rw-r--r-- | internal/admin/api_rooms.go | 46 | ||||
| -rw-r--r-- | internal/admin/api_triggers.go | 19 | ||||
| -rw-r--r-- | internal/admin/server.go | 2 | ||||
| -rw-r--r-- | internal/admin/undo.go | 12 | ||||
| -rw-r--r-- | internal/admin/yaml_util.go | 10 |
6 files changed, 46 insertions, 52 deletions
diff --git a/internal/admin/api_entity.go b/internal/admin/api_entity.go index 04b9dca..1049b96 100644 --- a/internal/admin/api_entity.go +++ b/internal/admin/api_entity.go @@ -322,7 +322,14 @@ func (s *AdminServer) entityDelete(w http.ResponseWriter, id string, c entityCRU c.fail(w, http.StatusNotFound, c.notFound(id)) return } - oldContent := backupFile(path) + oldContent, exists, snapErr := snapshotBefore(path) + if snapErr != nil { + c.fail(w, http.StatusInternalServerError, c.removeErr(snapErr)) + return + } + if !exists { + oldContent = nil + } if err := os.Remove(path); err != nil { c.fail(w, http.StatusInternalServerError, c.removeErr(err)) return diff --git a/internal/admin/api_rooms.go b/internal/admin/api_rooms.go index 06e736c..72f4a2c 100644 --- a/internal/admin/api_rooms.go +++ b/internal/admin/api_rooms.go @@ -349,26 +349,9 @@ func (s *AdminServer) handleRoomByID(w http.ResponseWriter, r *http.Request) { return } - courseID, _ := s.detachRoomFromCourse(id) - - if err := os.Remove(path); err != nil { - failJSON(w, fmt.Sprintf("delete room: %v", err)) - return - } - - s.world.RebuildRoomIndex(s.dataDir) - s.world.ClearRoomState(id) - // Drop the room's live mob instances too, or they keep wandering and - // are returned by MobsInRoom for a room that no longer exists. - if s.mobStore != nil { - s.mobStore.RemoveMobsInRoom(id) - } - // Drop any cached in-room games (tables/machines) and refund their - // outstanding wagers — same eviction semantics as bulk delete. - if s.evictRoom != nil { - s.evictRoom(id) - } - + // Clean up references and exits in every OTHER room BEFORE deleting this + // one: a failed write then aborts with the world untouched, instead of + // leaving dangling exits while reporting success. allIDs, _ := listRoomIDs(s.dataDir) var extraFiles []ExtraFile var exitCleaned int @@ -395,7 +378,8 @@ func (s *AdminServer) handleRoomByID(w http.ResponseWriter, r *http.Request) { oldExtra, _ := snapshotFile(otherPath) newContent, writeErr := writeYAMLFile(otherPath, otherRoom) if writeErr != nil { - continue + failJSON(w, fmt.Sprintf("clean exits in room %d: %v", otherID, writeErr)) + return } extraFiles = append(extraFiles, ExtraFile{ FilePath: otherPath, @@ -407,6 +391,26 @@ func (s *AdminServer) handleRoomByID(w http.ResponseWriter, r *http.Request) { } } + courseID, _ := s.detachRoomFromCourse(id) + + if err := os.Remove(path); err != nil { + failJSON(w, fmt.Sprintf("delete room: %v", err)) + return + } + + s.world.RebuildRoomIndex(s.dataDir) + s.world.ClearRoomState(id) + // Drop the room's live mob instances too, or they keep wandering and + // are returned by MobsInRoom for a room that no longer exists. + if s.mobStore != nil { + s.mobStore.RemoveMobsInRoom(id) + } + // Drop any cached in-room games (tables/machines) and refund their + // outstanding wagers — same eviction semantics as bulk delete. + if s.evictRoom != nil { + s.evictRoom(id) + } + s.undoStack.Push(ChangeDesc{ Description: fmt.Sprintf("delete room %d (cleaned %d exits)", id, exitCleaned), FilePath: path, diff --git a/internal/admin/api_triggers.go b/internal/admin/api_triggers.go index ff3e7d6..b392317 100644 --- a/internal/admin/api_triggers.go +++ b/internal/admin/api_triggers.go @@ -120,6 +120,7 @@ func (s *AdminServer) handleTriggerByID(w http.ResponseWriter, r *http.Request) delete(body, "id") delete(body, "_path") delete(body, "_raw") + delete(body, "_kind") oldPath, oldDir, findErr := findTriggerFile(s.dataDir, id) newKind := triggerKind(body) @@ -131,10 +132,10 @@ func (s *AdminServer) handleTriggerByID(w http.ResponseWriter, r *http.Request) oldContent = existing } - // If the kind changed, ensure the target directory exists and delete - // the old path after writing the new one. - if findErr == nil && newSubdir != oldDir { - os.MkdirAll(filepath.Dir(newPath), 0755) + // Ensure the target subdirectory exists even for PUT-as-create. + if err := os.MkdirAll(filepath.Dir(newPath), 0755); err != nil { + failJSON(w, "mkdir error: "+err.Error()) + return } triggerData, err := triggerMapToYAML(body) @@ -170,7 +171,6 @@ func (s *AdminServer) handleTriggerByID(w http.ResponseWriter, r *http.Request) desc.NewFilePath = newPath } s.undoStack.Push(desc) - s.rebuildTriggerIndex() writeJSON(w, map[string]any{"ok": true, "id": id, "kind": newKind}) case http.MethodDelete: @@ -196,7 +196,6 @@ func (s *AdminServer) handleTriggerByID(w http.ResponseWriter, r *http.Request) // new-content image over the file. IsDelete: true, }) - s.rebuildTriggerIndex() writeJSON(w, map[string]any{"ok": true}) default: @@ -285,6 +284,12 @@ func triggerMapToYAML(m map[string]any) ([]byte, error) { } // Handle simple fields. + if v, ok := m["item_id"]; ok { + if s, ok := v.(string); ok { + t.ItemID = s + } + delete(m, "item_id") + } if v, ok := m["on_player_flag"]; ok { if s, ok := v.(string); ok { t.OnPlayerFlag = s @@ -311,5 +316,3 @@ func triggerMapToYAML(m map[string]any) ([]byte, error) { } return yamlBytes, nil } - -func (s *AdminServer) rebuildTriggerIndex() {} diff --git a/internal/admin/server.go b/internal/admin/server.go index 9819924..a68eeda 100644 --- a/internal/admin/server.go +++ b/internal/admin/server.go @@ -946,6 +946,7 @@ func (s *AdminServer) handleEntityDirs(entityType string) http.HandlerFunc { for _, ch := range changes { s.undoStack.Push(ch) } + s.invalidateEntityCaches(entityType) writeJSON(w, map[string]any{"ok": true, "moved": len(changes) - 1}) case "rename_dir": if err := renameEntityDir(s.dataDir, entityType, body.Dir, body.NewName); err != nil { @@ -959,6 +960,7 @@ func (s *AdminServer) handleEntityDirs(entityType string) http.HandlerFunc { newPrefix := filepath.Join(s.dataDir, entityType, body.NewName) s.undoStack.RewritePaths(oldPrefix, newPrefix) } + s.invalidateEntityCaches(entityType) writeJSON(w, map[string]any{"ok": true, "name": body.NewName}) default: failJSON(w, "unknown action") diff --git a/internal/admin/undo.go b/internal/admin/undo.go index d9ef263..d352100 100644 --- a/internal/admin/undo.go +++ b/internal/admin/undo.go @@ -835,18 +835,6 @@ func (us *UndoStack) load() { us.redo = toChanges(sd.Redo) } -func (us *UndoStack) Clear() { - us.mu.Lock() - defer us.mu.Unlock() - us.history = nil - us.redo = nil - us.lastErr = nil - os.Remove(us.filePath) - log.Printf("undo: cleared history") -} - -// LastError returns the error from the most recent failed Undo/Redo, or nil. -// A nil change plus a nil LastError means the history/redo stack was empty. func (us *UndoStack) LastError() error { us.mu.Lock() defer us.mu.Unlock() diff --git a/internal/admin/yaml_util.go b/internal/admin/yaml_util.go index 2ab7ec4..050a3f6 100644 --- a/internal/admin/yaml_util.go +++ b/internal/admin/yaml_util.go @@ -2,7 +2,6 @@ package admin import ( "fmt" - "log" "os" "path/filepath" "strings" @@ -133,15 +132,6 @@ func listYAMLTree(dataDir, subdir string) (*YAMLTree, error) { return tree, nil } -func backupFile(path string) []byte { - data, err := os.ReadFile(path) - if err != nil { - log.Printf("backup: WARNING failed to read %s: %v (undo will not be able to restore this file)", path, err) - return nil - } - return data -} - func snapshotFile(path string) ([]byte, error) { return os.ReadFile(path) } |
