diff options
Diffstat (limited to 'internal/admin/api_rooms.go')
| -rw-r--r-- | internal/admin/api_rooms.go | 145 |
1 files changed, 134 insertions, 11 deletions
diff --git a/internal/admin/api_rooms.go b/internal/admin/api_rooms.go index d1193f0..b7f7d0e 100644 --- a/internal/admin/api_rooms.go +++ b/internal/admin/api_rooms.go @@ -318,22 +318,85 @@ func (s *AdminServer) handleRoomDirs(w http.ResponseWriter, r *http.Request) { if err != nil || !d.IsDir() || path == base { return nil } - entries, rdErr := os.ReadDir(path) - if rdErr != nil { - return nil - } - for _, e := range entries { - if !e.IsDir() && filepath.Ext(e.Name()) == ".yaml" { - rel, _ := filepath.Rel(base, path) - dirs = append(dirs, rel) - return nil - } - } + rel, _ := filepath.Rel(base, path) + dirs = append(dirs, rel) return nil }) writeJSON(w, dirs) } +func (s *AdminServer) handleRenameRoomDir(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + var body struct { + Dir string `json:"dir"` + NewName string `json:"new_name"` + } + if err := readJSON(r, &body); err != nil || body.NewName == "" { + writeJSON(w, map[string]any{"error": "invalid"}) + return + } + if body.Dir == "" { + writeJSON(w, map[string]any{"error": "cannot rename root"}) + return + } + newName := strings.TrimSpace(body.NewName) + if newName == "" || strings.ContainsAny(newName, "/\\") || newName == "." || newName == ".." { + writeJSON(w, map[string]any{"error": "invalid directory name"}) + return + } + base := filepath.Join(s.dataDir, "rooms") + parent := filepath.Dir(body.Dir) + oldPath := filepath.Join(base, body.Dir) + newRel := filepath.Join(parent, newName) + newPath := filepath.Join(base, newRel) + if _, err := os.Stat(oldPath); os.IsNotExist(err) { + writeJSON(w, map[string]any{"error": "directory not found"}) + return + } + if _, err := os.Stat(newPath); err == nil { + writeJSON(w, map[string]any{"error": "directory already exists: " + newRel}) + return + } + if err := os.Rename(oldPath, newPath); err != nil { + writeJSON(w, map[string]any{"error": "rename failed: " + err.Error()}) + return + } + s.world.RebuildRoomIndex(s.dataDir) + writeJSON(w, map[string]any{"ok": true, "new_dir": newRel}) +} + +func (s *AdminServer) handleCreateRoomDir(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + var body struct { + Name string `json:"name"` + } + if err := readJSON(r, &body); err != nil { + writeJSON(w, map[string]any{"error": "invalid"}) + return + } + name := strings.TrimSpace(body.Name) + if name == "" || strings.ContainsAny(name, "/\\") || name == "." || name == ".." { + writeJSON(w, map[string]any{"error": "invalid directory name"}) + return + } + newPath := filepath.Join(s.dataDir, "rooms", name) + if _, err := os.Stat(newPath); err == nil { + writeJSON(w, map[string]any{"error": "directory already exists"}) + return + } + if err := os.Mkdir(newPath, 0755); err != nil { + writeJSON(w, map[string]any{"error": "create failed: " + err.Error()}) + return + } + writeJSON(w, map[string]any{"ok": true, "name": name}) +} + func (s *AdminServer) handleRoomLink(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodPost: @@ -844,3 +907,63 @@ func (s *AdminServer) handleResolveDuplicate(w http.ResponseWriter, r *http.Requ writeJSON(w, map[string]any{"error": "unknown action: " + body.Action}) } } + +func (s *AdminServer) handleCreateEmptyRoom(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed) + return + } + var body struct { + Dir string `json:"dir"` + } + if err := readJSON(r, &body); err != nil { + writeJSON(w, map[string]any{"error": "invalid"}) + return + } + base := filepath.Join(s.dataDir, "rooms") + targetDir := base + if body.Dir != "" { + targetDir = filepath.Join(base, body.Dir) + if _, err := os.Stat(targetDir); os.IsNotExist(err) { + writeJSON(w, map[string]any{"error": "directory not found"}) + return + } + } + + used := map[int]bool{} + filepath.WalkDir(base, func(path string, d os.DirEntry, err error) error { + if err != nil || d.IsDir() || filepath.Ext(d.Name()) != ".yaml" { + return nil + } + name := d.Name() + id, convErr := strconv.Atoi(name[:len(name)-5]) + if convErr == nil && id > 0 { + used[id] = true + } + return nil + }) + + id := 1 + for used[id] { + id++ + } + + path := filepath.Join(targetDir, strconv.Itoa(id)+".yaml") + m := map[string]any{ + "name": "New Room", + "description": "An empty room.", + } + newContent, writeErr := writeMapAsYAML(path, m) + if writeErr != nil { + writeJSON(w, map[string]any{"error": "write room: " + writeErr.Error()}) + return + } + s.world.RebuildRoomIndex(s.dataDir) + s.undoStack.Push(ChangeDesc{ + Description: fmt.Sprintf("create room %d", id), + FilePath: path, + NewContent: newContent, + IsCreate: true, + }) + writeJSON(w, map[string]any{"room": map[string]any{"id": id, "name": "New Room"}}) +} |
