aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/api_objects.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/api_objects.go')
-rw-r--r--internal/admin/api_objects.go166
1 files changed, 166 insertions, 0 deletions
diff --git a/internal/admin/api_objects.go b/internal/admin/api_objects.go
new file mode 100644
index 0000000..e4a2c60
--- /dev/null
+++ b/internal/admin/api_objects.go
@@ -0,0 +1,166 @@
+package admin
+
+import (
+ "fmt"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+func (s *AdminServer) handleObjects(w http.ResponseWriter, r *http.Request) {
+ switch r.Method {
+ case http.MethodGet:
+ ids, err := listYAMLFiles(s.dataDir, "objects")
+ if err != nil {
+ http.Error(w, `{"error":"failed to list objects"}`, http.StatusInternalServerError)
+ return
+ }
+ if ids == nil {
+ ids = []string{}
+ }
+ writeJSON(w, ids)
+ case http.MethodPost:
+ s.createObject(w, r)
+ default:
+ http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
+ }
+}
+
+func (s *AdminServer) handleObjectByID(w http.ResponseWriter, r *http.Request) {
+ id := strings.TrimPrefix(r.URL.Path, "/api/objects/")
+ if id == "" {
+ http.Error(w, `{"error":"missing object id"}`, http.StatusBadRequest)
+ return
+ }
+
+ switch r.Method {
+ case http.MethodGet:
+ s.getObject(w, r, id)
+ case http.MethodPut:
+ s.updateObject(w, r, id)
+ case http.MethodDelete:
+ s.deleteObject(w, r, id)
+ default:
+ http.Error(w, `{"error":"method not allowed"}`, http.StatusMethodNotAllowed)
+ }
+}
+
+func (s *AdminServer) findObjectFile(id string) ([]byte, string, error) {
+ data, path, err := readYAMLFile(s.dataDir, "objects", id)
+ if err == nil {
+ return data, path, nil
+ }
+ return findYAMLFileInSubdirs(s.dataDir, "objects", id)
+}
+
+func (s *AdminServer) getObject(w http.ResponseWriter, r *http.Request, id string) {
+ data, path, err := s.findObjectFile(id)
+ if err != nil {
+ http.Error(w, `{"error":"object not found"}`, http.StatusNotFound)
+ return
+ }
+ m, err := yamlToMap(data)
+ if err != nil {
+ http.Error(w, `{"error":"failed to parse object yaml"}`, http.StatusInternalServerError)
+ return
+ }
+ m["_path"] = path
+ m["_raw"] = string(data)
+ writeJSON(w, m)
+}
+
+func (s *AdminServer) updateObject(w http.ResponseWriter, r *http.Request, id string) {
+ _, path, err := s.findObjectFile(id)
+ if err != nil {
+ http.Error(w, `{"error":"object 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 object"}`, http.StatusInternalServerError)
+ return
+ }
+
+ newContent, err := writeMapAsYAML(path, m)
+ if err != nil {
+ http.Error(w, `{"error":"failed to write object"}`, http.StatusInternalServerError)
+ return
+ }
+
+ s.undoStack.Push(ChangeDesc{
+ Description: fmt.Sprintf("Update object %s", id),
+ FilePath: path,
+ OldContent: oldContent,
+ NewContent: newContent,
+ })
+
+ writeJSON(w, m)
+}
+
+func (s *AdminServer) deleteObject(w http.ResponseWriter, r *http.Request, id string) {
+ _, path, err := s.findObjectFile(id)
+ if err != nil {
+ http.Error(w, `{"error":"object not found"}`, http.StatusNotFound)
+ return
+ }
+
+ oldContent := backupFile(path)
+
+ if err := os.Remove(path); err != nil {
+ http.Error(w, `{"error":"failed to delete object"}`, http.StatusInternalServerError)
+ return
+ }
+
+ s.undoStack.Push(ChangeDesc{
+ Description: fmt.Sprintf("Delete object %s", id),
+ FilePath: path,
+ OldContent: oldContent,
+ IsDelete: true,
+ })
+
+ writeJSON(w, map[string]any{"deleted": id})
+}
+
+func (s *AdminServer) createObject(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, _ := m["id"].(string)
+ if strings.TrimSpace(id) == "" {
+ http.Error(w, `{"error":"missing object id"}`, http.StatusBadRequest)
+ return
+ }
+
+ if _, _, err := s.findObjectFile(id); err == nil {
+ http.Error(w, `{"error":"object already exists"}`, http.StatusConflict)
+ return
+ }
+
+ path := filepath.Join(s.dataDir, "objects", id+".yaml")
+
+ newContent, err := writeMapAsYAML(path, m)
+ if err != nil {
+ http.Error(w, `{"error":"failed to write object"}`, http.StatusInternalServerError)
+ return
+ }
+
+ s.undoStack.Push(ChangeDesc{
+ Description: fmt.Sprintf("Create object %s", id),
+ FilePath: path,
+ NewContent: newContent,
+ IsCreate: true,
+ })
+
+ writeJSON(w, m)
+}