package admin import ( "fmt" "net/http" "os" "path/filepath" "strings" ) func (s *AdminServer) handleHazards(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: tree, err := listYAMLTree(s.dataDir, "hazards") 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: s.createHazard(w, r) default: http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed) } } func (s *AdminServer) handleHazardByID(w http.ResponseWriter, r *http.Request) { id := strings.TrimPrefix(r.URL.Path, "/api/hazards/") if id == "" { http.Error(w, `{"error":"missing hazard id"}`, http.StatusBadRequest) return } switch r.Method { case http.MethodGet: s.getHazard(w, r, id) case http.MethodPut: s.updateHazard(w, r, id) case http.MethodDelete: s.deleteHazard(w, r, id) default: http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed) } } func (s *AdminServer) getHazard(w http.ResponseWriter, r *http.Request, id string) { data, path, err := readYAMLFile(s.dataDir, "hazards", id) if err != nil { http.Error(w, `{"error":"hazard not found"}`, http.StatusNotFound) return } m, err := yamlToMap(data) if err != nil { http.Error(w, `{"error":"failed to parse hazard yaml"}`, http.StatusInternalServerError) return } m["_path"] = path m["_raw"] = string(data) writeJSON(w, m) } func (s *AdminServer) updateHazard(w http.ResponseWriter, r *http.Request, id string) { _, path, err := readYAMLFile(s.dataDir, "hazards", id) if err != nil { http.Error(w, `{"error":"hazard 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 hazard"}`, http.StatusInternalServerError) return } newContent, err := writeMapAsYAML(path, m) if err != nil { http.Error(w, `{"error":"failed to write hazard"}`, http.StatusInternalServerError) return } s.world.ClearHazardCache() s.undoStack.Push(ChangeDesc{ Description: fmt.Sprintf("Update hazard %s", id), FilePath: path, OldContent: oldContent, NewContent: newContent, }) writeJSON(w, m) } func (s *AdminServer) deleteHazard(w http.ResponseWriter, r *http.Request, id string) { _, path, err := readYAMLFile(s.dataDir, "hazards", id) if err != nil { http.Error(w, `{"error":"hazard not found"}`, http.StatusNotFound) return } oldContent := backupFile(path) if err := os.Remove(path); err != nil { http.Error(w, `{"error":"failed to delete hazard"}`, http.StatusInternalServerError) return } s.world.ClearHazardCache() s.undoStack.Push(ChangeDesc{ Description: fmt.Sprintf("Delete hazard %s", id), FilePath: path, OldContent: oldContent, IsDelete: true, }) writeJSON(w, map[string]any{"deleted": id}) } func (s *AdminServer) createHazard(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 hazard id"}`, http.StatusBadRequest) return } path := filepath.Join(s.dataDir, "hazards", id+".yaml") if _, err := os.Stat(path); err == nil { http.Error(w, `{"error":"hazard already exists"}`, http.StatusConflict) return } newContent, err := writeMapAsYAML(path, m) if err != nil { http.Error(w, `{"error":"failed to write hazard"}`, http.StatusInternalServerError) return } s.world.ClearHazardCache() s.undoStack.Push(ChangeDesc{ Description: fmt.Sprintf("Create hazard %s", id), FilePath: path, NewContent: newContent, IsCreate: true, }) writeJSON(w, m) }