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.go145
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"}})
+}