package admin import ( "fmt" "net/http" "os" "path/filepath" "strings" "thehouseoficarus/internal/behavior" ) func (s *AdminServer) handleDrops(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: ids, err := listYAMLFiles(s.dataDir, "drops") if err != nil { writeJSON(w, map[string]any{"error": err.Error()}) return } if ids == nil { ids = []string{} } writeJSON(w, ids) case http.MethodPost: s.createDrop(w, r) default: http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed) } } func (s *AdminServer) handleDropByID(w http.ResponseWriter, r *http.Request) { id := strings.TrimPrefix(r.URL.Path, "/api/drops/") if id == "" { http.Error(w, `{"error":"missing drop id"}`, http.StatusBadRequest) return } switch r.Method { case http.MethodGet: s.getDrop(w, r, id) case http.MethodPut: s.updateDrop(w, r, id) case http.MethodDelete: s.deleteDrop(w, r, id) default: http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed) } } func (s *AdminServer) getDrop(w http.ResponseWriter, r *http.Request, id string) { data, path, err := readYAMLFile(s.dataDir, "drops", id) if err != nil { http.Error(w, `{"error":"drop not found"}`, http.StatusNotFound) return } m, err := yamlToMap(data) if err != nil { http.Error(w, `{"error":"failed to parse drop yaml"}`, http.StatusInternalServerError) return } m["_path"] = path m["_raw"] = string(data) writeJSON(w, m) } func (s *AdminServer) updateDrop(w http.ResponseWriter, r *http.Request, id string) { _, path, err := readYAMLFile(s.dataDir, "drops", id) if err != nil { http.Error(w, `{"error":"drop not found"}`, http.StatusNotFound) return } var m map[string]any if err := readJSON(r, &m); err != nil { http.Error(w, `{"error":"invalid json body"}`, http.StatusBadRequest) return } m["id"] = id oldContent, err := snapshotFile(path) if err != nil { http.Error(w, `{"error":"failed to read existing drop"}`, http.StatusInternalServerError) return } newContent, err := writeMapAsYAML(path, m) if err != nil { http.Error(w, `{"error":"failed to write drop"}`, http.StatusInternalServerError) return } behavior.ClearDropIndex() s.undoStack.Push(ChangeDesc{ Description: fmt.Sprintf("Update drop %s", id), FilePath: path, OldContent: oldContent, NewContent: newContent, }) writeJSON(w, m) } func (s *AdminServer) deleteDrop(w http.ResponseWriter, r *http.Request, id string) { _, path, err := readYAMLFile(s.dataDir, "drops", id) if err != nil { http.Error(w, `{"error":"drop not found"}`, http.StatusNotFound) return } oldContent := backupFile(path) if err := os.Remove(path); err != nil { http.Error(w, `{"error":"failed to delete drop"}`, http.StatusInternalServerError) return } behavior.ClearDropIndex() s.undoStack.Push(ChangeDesc{ Description: fmt.Sprintf("Delete drop %s", id), FilePath: path, OldContent: oldContent, IsDelete: true, }) writeJSON(w, map[string]any{"deleted": id}) } func (s *AdminServer) createDrop(w http.ResponseWriter, r *http.Request) { var m map[string]any if err := readJSON(r, &m); err != nil { http.Error(w, `{"error":"invalid json body"}`, http.StatusBadRequest) return } id, ok := m["id"].(string) if !ok || strings.TrimSpace(id) == "" { http.Error(w, `{"error":"missing drop id"}`, http.StatusBadRequest) return } path := filepath.Join(s.dataDir, "drops", id+".yaml") if _, err := os.Stat(path); err == nil { http.Error(w, `{"error":"drop already exists"}`, http.StatusConflict) return } newContent, err := writeMapAsYAML(path, m) if err != nil { http.Error(w, `{"error":"failed to write drop"}`, http.StatusInternalServerError) return } behavior.ClearDropIndex() s.undoStack.Push(ChangeDesc{ Description: fmt.Sprintf("Create drop %s", id), FilePath: path, NewContent: newContent, IsCreate: true, }) writeJSON(w, m) }