aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/api_drops.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/api_drops.go')
-rw-r--r--internal/admin/api_drops.go168
1 files changed, 168 insertions, 0 deletions
diff --git a/internal/admin/api_drops.go b/internal/admin/api_drops.go
new file mode 100644
index 0000000..7645d39
--- /dev/null
+++ b/internal/admin/api_drops.go
@@ -0,0 +1,168 @@
+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)
+}