aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/api_files.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/api_files.go')
-rw-r--r--internal/admin/api_files.go135
1 files changed, 135 insertions, 0 deletions
diff --git a/internal/admin/api_files.go b/internal/admin/api_files.go
new file mode 100644
index 0000000..2a87dd3
--- /dev/null
+++ b/internal/admin/api_files.go
@@ -0,0 +1,135 @@
+package admin
+
+import (
+ "io"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+func (s *AdminServer) handleFiles(w http.ResponseWriter, r *http.Request) {
+ relPath := r.URL.Query().Get("path")
+ relPath = strings.TrimPrefix(relPath, "/")
+ relPath = strings.TrimPrefix(relPath, "data/")
+
+ switch r.Method {
+ case http.MethodGet:
+ if relPath == "" {
+ entries, err := os.ReadDir(s.dataDir)
+ if err != nil {
+ writeJSON(w, map[string]any{"error": err.Error()})
+ return
+ }
+ var files []map[string]any
+ for _, e := range entries {
+ files = append(files, map[string]any{
+ "name": e.Name(),
+ "dir": e.IsDir(),
+ })
+ }
+ writeJSON(w, files)
+ return
+ }
+
+ fullPath := filepath.Join(s.dataDir, relPath)
+ info, err := os.Stat(fullPath)
+ if err != nil {
+ writeJSON(w, map[string]any{"error": "not found: " + relPath})
+ return
+ }
+
+ if info.IsDir() {
+ entries, err := os.ReadDir(fullPath)
+ if err != nil {
+ writeJSON(w, map[string]any{"error": err.Error()})
+ return
+ }
+ var files []map[string]any
+ for _, e := range entries {
+ files = append(files, map[string]any{
+ "name": e.Name(),
+ "dir": e.IsDir(),
+ })
+ }
+ writeJSON(w, files)
+ return
+ }
+
+ data, err := os.ReadFile(fullPath)
+ if err != nil {
+ writeJSON(w, map[string]any{"error": "read error: " + err.Error()})
+ return
+ }
+ writeJSON(w, map[string]any{
+ "name": info.Name(),
+ "content": string(data),
+ "path": relPath,
+ })
+
+ case http.MethodPut, http.MethodPost:
+ if relPath == "" {
+ writeJSON(w, map[string]any{"error": "missing path"})
+ return
+ }
+ fullPath := filepath.Join(s.dataDir, relPath)
+
+ body, err := io.ReadAll(r.Body)
+ if err != nil {
+ writeJSON(w, map[string]any{"error": "read body: " + err.Error()})
+ return
+ }
+
+ var oldContent []byte
+ if existing, err := snapshotFile(fullPath); err == nil {
+ oldContent = existing
+ }
+
+ dir := filepath.Dir(fullPath)
+ if err := os.MkdirAll(dir, 0755); err != nil {
+ writeJSON(w, map[string]any{"error": "mkdir: " + err.Error()})
+ return
+ }
+
+ if err := os.WriteFile(fullPath, body, 0644); err != nil {
+ writeJSON(w, map[string]any{"error": "write error: " + err.Error()})
+ return
+ }
+
+ isCreate := oldContent == nil
+ desc := "Updated file " + relPath
+ if isCreate {
+ desc = "Created file " + relPath
+ }
+ s.undoStack.Push(ChangeDesc{
+ Description: desc,
+ FilePath: fullPath,
+ OldContent: oldContent,
+ NewContent: body,
+ IsCreate: isCreate,
+ })
+ writeJSON(w, map[string]any{"ok": true, "path": relPath})
+
+ case http.MethodDelete:
+ if relPath == "" {
+ writeJSON(w, map[string]any{"error": "missing path"})
+ return
+ }
+ fullPath := filepath.Join(s.dataDir, relPath)
+ oldContent, _ := snapshotFile(fullPath)
+ if err := os.Remove(fullPath); err != nil {
+ writeJSON(w, map[string]any{"error": "delete error: " + err.Error()})
+ return
+ }
+ s.undoStack.Push(ChangeDesc{
+ Description: "Deleted file " + relPath,
+ FilePath: fullPath,
+ OldContent: oldContent,
+ IsDelete: true,
+ })
+ writeJSON(w, map[string]any{"ok": true, "path": relPath})
+
+ default:
+ http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
+ }
+}