diff --git a/admin/console.go b/admin/console.go
index 973e435d..9fc95e73 100644
--- a/admin/console.go
+++ b/admin/console.go
@@ -12,7 +12,7 @@ import (
"mu/wallet"
)
-// ConsoleHandler provides an admin console for managing the system.
+// ConsoleHandler provides an admin console.
func ConsoleHandler(w http.ResponseWriter, r *http.Request) {
_, _, err := auth.RequireAdmin(r)
if err != nil {
@@ -20,56 +20,107 @@ func ConsoleHandler(w http.ResponseWriter, r *http.Request) {
return
}
- // Handle command
- cmd := ""
- output := ""
+ // POST: run command and return result
if r.Method == "POST" {
r.ParseForm()
- cmd = strings.TrimSpace(r.FormValue("cmd"))
+ cmd := strings.TrimSpace(r.FormValue("cmd"))
+ output := ""
if cmd != "" {
output = runCommand(cmd)
}
- // Redirect with results to prevent form resubmission
+ // If Accept: application/json, return JSON
+ if app.WantsJSON(r) || r.Header.Get("Content-Type") == "application/json" {
+ app.RespondJSON(w, map[string]string{"output": output})
+ return
+ }
+ // Fallback: redirect
http.Redirect(w, r, "/admin/console?cmd="+url.QueryEscape(cmd)+"&output="+url.QueryEscape(output), http.StatusSeeOther)
return
}
- // GET — show form + results from redirect
+ // GET: render page
prevCmd := r.URL.Query().Get("cmd")
prevOutput := r.URL.Query().Get("output")
var sb strings.Builder
+ sb.WriteString(`
`)
- // Form
- sb.WriteString(`
`)
- sb.WriteString(`
`)
-
- // Output
+ // Output area
+ sb.WriteString(`
`)
if prevOutput != "" {
- sb.WriteString(fmt.Sprintf(`
%s
`, htmlEsc(prevOutput)))
+ sb.WriteString(fmt.Sprintf(`
> %s
+%s`, esc(prevCmd), esc(prevOutput)))
}
sb.WriteString(`
`)
- // Help
- sb.WriteString(`
-
search <query> · delete <type> <id> · user <id> · wallet <id> · types · stats
-
`)
+ // Input — form for fallback, JS for interactive
+ sb.WriteString(`
`)
+
+ sb.WriteString(`
search · delete · user · wallet · types · stats · help
`)
+ sb.WriteString(`
`)
+
+ // JS: intercept form, use fetch, append output inline
+ sb.WriteString(``)
html := app.RenderHTMLForRequest("Console", "Admin Console", sb.String(), r)
w.Write([]byte(html))
}
-func htmlEsc(s string) string {
- s = strings.ReplaceAll(s, "&", "&")
- s = strings.ReplaceAll(s, "<", "<")
- s = strings.ReplaceAll(s, ">", ">")
- s = strings.ReplaceAll(s, `"`, """)
- return s
-}
-
func runCommand(cmd string) string {
parts := strings.Fields(cmd)
if len(parts) == 0 {
@@ -135,9 +186,17 @@ func runCommand(cmd string) string {
return fmt.Sprintf("Index entries: %d\nSQLite: %v", stats.TotalEntries, stats.UsingSQLite)
case "help":
- return "search
· delete · user · wallet · types · stats"
+ return "search — search indexed content\ndelete — delete by type and ID\nuser — view user details\nwallet — view wallet balance\ntypes — list deletable content types\nstats — index stats"
default:
- return fmt.Sprintf("Unknown command: %s", parts[0])
+ return fmt.Sprintf("Unknown: %s. Type help for commands.", parts[0])
}
}
+
+func esc(s string) string {
+ s = strings.ReplaceAll(s, "&", "&")
+ s = strings.ReplaceAll(s, "<", "<")
+ s = strings.ReplaceAll(s, ">", ">")
+ s = strings.ReplaceAll(s, `"`, """)
+ return s
+}