aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/api_rooms.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/api_rooms.go')
-rw-r--r--internal/admin/api_rooms.go136
1 files changed, 129 insertions, 7 deletions
diff --git a/internal/admin/api_rooms.go b/internal/admin/api_rooms.go
index 1339bcd..84c3348 100644
--- a/internal/admin/api_rooms.go
+++ b/internal/admin/api_rooms.go
@@ -841,7 +841,7 @@ func (s *AdminServer) handleRoomRename(w http.ResponseWriter, r *http.Request) {
NewID int `json:"new_id"`
}
if err := readJSON(r, &body); err != nil || body.ID <= 0 || body.NewID <= 0 {
- writeJSON(w, map[string]any{"error": "invalid"})
+ writeJSONError(w, "invalid", http.StatusBadRequest)
return
}
if body.ID == body.NewID {
@@ -850,33 +850,33 @@ func (s *AdminServer) handleRoomRename(w http.ResponseWriter, r *http.Request) {
}
oldPath, ok := s.world.GetRoomPath(body.ID)
if !ok {
- writeJSON(w, map[string]any{"error": "room not found"})
+ writeJSONError(w, "room not found", http.StatusBadRequest)
return
}
if _, ok := s.world.GetRoomPath(body.NewID); ok {
- writeJSON(w, map[string]any{"error": fmt.Sprintf("room %d already exists", body.NewID)})
+ writeJSONError(w, fmt.Sprintf("room %d already exists", body.NewID), http.StatusConflict)
return
}
dir := filepath.Dir(oldPath)
newPath := filepath.Join(dir, strconv.Itoa(body.NewID)+".yaml")
if _, err := os.Stat(newPath); err == nil {
- writeJSON(w, map[string]any{"error": fmt.Sprintf("room %d already exists", body.NewID)})
+ writeJSONError(w, fmt.Sprintf("room %d already exists", body.NewID), http.StatusConflict)
return
}
data, err := os.ReadFile(oldPath)
if err != nil {
- writeJSON(w, map[string]any{"error": "read: " + err.Error()})
+ writeJSONError(w, "read: "+err.Error(), http.StatusInternalServerError)
return
}
if err := os.WriteFile(newPath, data, 0644); err != nil {
- writeJSON(w, map[string]any{"error": "write: " + err.Error()})
+ writeJSONError(w, "write: "+err.Error(), http.StatusInternalServerError)
return
}
if err := os.Remove(oldPath); err != nil {
- writeJSON(w, map[string]any{"error": "remove old: " + err.Error()})
+ writeJSONError(w, "remove old: "+err.Error(), http.StatusInternalServerError)
return
}
@@ -925,6 +925,128 @@ func (s *AdminServer) handleRoomRename(w http.ResponseWriter, r *http.Request) {
writeJSON(w, map[string]any{"ok": true})
}
+func (s *AdminServer) handleRoomSwap(w http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodPost {
+ http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+ var body struct {
+ From int `json:"from"`
+ Dir string `json:"dir"`
+ }
+ if err := readJSON(r, &body); err != nil || body.From <= 0 || body.Dir == "" {
+ writeJSONError(w, "invalid body, need from and dir", http.StatusBadRequest)
+ return
+ }
+
+ dir := world.ExitDir(strings.ToLower(body.Dir))
+ if _, ok := world.OppositeExit[dir]; !ok {
+ writeJSONError(w, "invalid direction: "+body.Dir, http.StatusBadRequest)
+ return
+ }
+
+ aID := body.From
+ aRoom, err := s.world.LoadRoom(aID)
+ if err != nil {
+ writeJSONError(w, fmt.Sprintf("could not load room #%d: %v", aID, err), http.StatusBadRequest)
+ return
+ }
+ aExit, hasExit := aRoom.Exits[dir]
+ if !hasExit {
+ writeJSONError(w, fmt.Sprintf("room #%d has no %s exit", aID, dir), http.StatusBadRequest)
+ return
+ }
+ bID := aExit.Room
+ if bID <= 0 {
+ writeJSONError(w, fmt.Sprintf("room #%d %s exit is invalid", aID, dir), http.StatusBadRequest)
+ return
+ }
+ if bID == aID {
+ writeJSONError(w, "cannot swap a room with itself", http.StatusBadRequest)
+ return
+ }
+
+ aPath, aOK := s.world.GetRoomPath(aID)
+ if !aOK {
+ writeJSONError(w, fmt.Sprintf("could not find file for room #%d", aID), http.StatusInternalServerError)
+ return
+ }
+ bPath, bOK := s.world.GetRoomPath(bID)
+ if !bOK {
+ writeJSONError(w, fmt.Sprintf("could not find file for room #%d", bID), http.StatusInternalServerError)
+ return
+ }
+
+ oldA, _ := snapshotFile(aPath)
+ oldB, _ := snapshotFile(bPath)
+
+ dataA, err := os.ReadFile(aPath)
+ if err != nil {
+ writeJSONError(w, "read A: "+err.Error(), http.StatusInternalServerError)
+ return
+ }
+ dataB, err := os.ReadFile(bPath)
+ if err != nil {
+ writeJSONError(w, "read B: "+err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ mapA, err := yamlToMap(dataA)
+ if err != nil {
+ writeJSONError(w, "parse A: "+err.Error(), http.StatusInternalServerError)
+ return
+ }
+ mapB, err := yamlToMap(dataB)
+ if err != nil {
+ writeJSONError(w, "parse B: "+err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ idA := mapA["id"]
+ exitsA := mapA["exits"]
+ idB := mapB["id"]
+ exitsB := mapB["exits"]
+
+ newA := make(map[string]any, len(mapB))
+ for k, v := range mapB {
+ newA[k] = v
+ }
+ newA["id"] = idA
+ newA["exits"] = exitsA
+
+ newB := make(map[string]any, len(mapA))
+ for k, v := range mapA {
+ newB[k] = v
+ }
+ newB["id"] = idB
+ newB["exits"] = exitsB
+
+ newAContent, err := writeMapAsYAML(aPath, newA)
+ if err != nil {
+ writeJSONError(w, "write A: "+err.Error(), http.StatusInternalServerError)
+ return
+ }
+ newBContent, err := writeMapAsYAML(bPath, newB)
+ if err != nil {
+ os.WriteFile(aPath, oldA, 0644)
+ writeJSONError(w, "write B: "+err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ s.undoStack.Push(ChangeDesc{
+ Description: fmt.Sprintf("swap room %d with %d (%s)", aID, bID, dir),
+ FilePath: aPath,
+ OldContent: oldA,
+ NewContent: newAContent,
+ ExtraFiles: []ExtraFile{{
+ FilePath: bPath,
+ OldContent: oldB,
+ NewContent: newBContent,
+ }},
+ })
+ writeJSON(w, map[string]any{"ok": true, "a": aID, "b": bID})
+}
+
func (s *AdminServer) handleDuplicateRooms(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
writeJSON(w, map[string]any{"error": "method not allowed"})