package admin import ( "net/http" "os" "path/filepath" "strings" ) func (s *AdminServer) handleTechs(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: tree, err := listYAMLTree(s.dataDir, "techs") if err != nil { writeJSON(w, map[string]any{"error": err.Error()}) return } if tree == nil { tree = &YAMLTree{Root: []string{}, Dirs: map[string][]string{}} } writeJSON(w, tree) case http.MethodPost: var m map[string]any if err := readJSON(r, &m); err != nil { writeJSON(w, map[string]any{"error": "invalid json"}) return } id, _ := m["id"].(string) if strings.TrimSpace(id) == "" { writeJSON(w, map[string]any{"error": "missing id"}) return } delete(m, "id") path := filepath.Join(s.dataDir, "techs", id+".yaml") if _, err := os.Stat(path); err == nil { writeJSON(w, map[string]any{"error": "tech already exists"}) return } newContent, err := writeMapAsYAML(path, m) if err != nil { writeJSON(w, map[string]any{"error": "write error: " + err.Error()}) return } s.undoStack.Push(ChangeDesc{ Description: "Created tech " + id, FilePath: path, NewContent: newContent, IsCreate: true, }) writeJSON(w, map[string]any{"ok": true, "id": id}) default: http.Error(w, "method not allowed", http.StatusMethodNotAllowed) } } func (s *AdminServer) handleTechByID(w http.ResponseWriter, r *http.Request) { id := strings.TrimPrefix(r.URL.Path, "/api/techs/") if id == "" { http.Error(w, `{"error":"missing id"}`, http.StatusBadRequest) return } switch r.Method { case http.MethodGet: data, path, err := findYAMLFileInSubdirs(s.dataDir, "techs", id) if err != nil { writeJSON(w, map[string]any{"error": "not found: " + id}) return } raw, err := yamlToMap(data) if err != nil { writeJSON(w, map[string]any{"error": "parse error: " + err.Error()}) return } raw["id"] = id raw["_path"] = path raw["_raw"] = string(data) writeJSON(w, raw) case http.MethodPost, http.MethodPut: var body map[string]any if err := readJSON(r, &body); err != nil { writeJSON(w, map[string]any{"error": "invalid JSON: " + err.Error()}) return } delete(body, "id") delete(body, "_path") delete(body, "_raw") path := filepath.Join(s.dataDir, "techs", id+".yaml") var oldContent []byte if existing, err := snapshotFile(path); err == nil { oldContent = existing } newContent, err := writeMapAsYAML(path, body) if err != nil { writeJSON(w, map[string]any{"error": "write error: " + err.Error()}) return } isCreate := oldContent == nil desc := "Updated tech " + id if isCreate { desc = "Created tech " + id } s.undoStack.Push(ChangeDesc{ Description: desc, FilePath: path, OldContent: oldContent, NewContent: newContent, IsCreate: isCreate, }) writeJSON(w, map[string]any{"ok": true, "id": id}) case http.MethodDelete: _, path, err := findYAMLFileInSubdirs(s.dataDir, "techs", id) if err != nil { writeJSON(w, map[string]any{"error": "not found: " + id}) return } oldContent, _ := snapshotFile(path) if err := os.Remove(path); err != nil { writeJSON(w, map[string]any{"error": "delete error: " + err.Error()}) return } s.undoStack.Push(ChangeDesc{ Description: "Deleted tech " + id, FilePath: path, OldContent: oldContent, IsDelete: true, }) writeJSON(w, map[string]any{"ok": true, "id": id}) default: http.Error(w, "method not allowed", http.StatusMethodNotAllowed) } }