diff options
Diffstat (limited to 'internal/admin/api_rooms.go')
| -rw-r--r-- | internal/admin/api_rooms.go | 136 |
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"}) |
