From b1bb205d5501b09902c616cf5b1cc834d8466719 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Wed, 22 Apr 2026 21:27:37 +0200 Subject: [PATCH] admin: add delete user with confirmation dialog --- api/admin/handler.go | 43 +++++++++++++++++++++++++++++++++++++++ internal/db/queries.sql | 3 +++ internal/server/routes.go | 2 ++ web/templates/admin.templ | 9 ++++++++ 4 files changed, 57 insertions(+) diff --git a/api/admin/handler.go b/api/admin/handler.go index da46603..e35d43a 100644 --- a/api/admin/handler.go +++ b/api/admin/handler.go @@ -142,6 +142,49 @@ func (h *Handler) HandleAddUserForm(w http.ResponseWriter, r *http.Request) { } } +func (h *Handler) HandleDeleteUser(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) + return + } + + userID := r.URL.Path[len("/admin/users/"):] + if userID == "" { + writeInlineError(w, "Invalid user ID") + return + } + + // Don't allow deleting yourself + currentUser, ok := r.Context().Value(webcontext.UserKey).(*database.User) + if !ok || currentUser == nil { + writeInlineError(w, "Not authenticated") + return + } + if userID == currentUser.ID { + writeInlineError(w, "Cannot delete your own account") + return + } + + err := h.db.DeleteUser(r.Context(), userID) + if err != nil { + log.Printf("delete user error: %v", err) + writeInlineError(w, "Failed to delete user") + return + } + + users, err := h.db.ListUsers(r.Context()) + if err != nil { + log.Printf("list users error: %v", err) + writeInlineError(w, "User deleted but failed to refresh list") + return + } + + if err := templates.AdminUsersList(users).Render(r.Context(), w); err != nil { + log.Printf("render error: %v", err) + writeInlineError(w, "User deleted but failed to render list") + } +} + func writeInlineError(w http.ResponseWriter, message string) { w.Header().Set("Content-Type", "text/html") w.WriteHeader(http.StatusBadRequest) diff --git a/internal/db/queries.sql b/internal/db/queries.sql index 0ce3de5..c343e0e 100644 --- a/internal/db/queries.sql +++ b/internal/db/queries.sql @@ -7,6 +7,9 @@ SELECT * FROM user WHERE username = ? LIMIT 1; -- name: ListUsers :many SELECT * FROM user ORDER BY created_at DESC; +-- name: DeleteUser :exec +DELETE FROM user WHERE id = ?; + -- name: CreateUser :one INSERT INTO user (id, username, password_hash) VALUES (?, ?, ?) diff --git a/internal/server/routes.go b/internal/server/routes.go index 0c135f1..d9f75bd 100644 --- a/internal/server/routes.go +++ b/internal/server/routes.go @@ -111,6 +111,8 @@ func NewRouter(cfg Config) http.Handler { mux.Handle("/admin/users/", middleware.RequireAdmin(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { path := r.URL.Path switch { + case strings.HasSuffix(path, "/delete"): + adminHandler.HandleDeleteUser(w, r) case strings.HasSuffix(path, "/watchlist"): adminHandler.HandleUserWatchlist(w, r) case strings.HasSuffix(path, "/continue-watching"): diff --git a/web/templates/admin.templ b/web/templates/admin.templ index 5e78072..10e80c6 100644 --- a/web/templates/admin.templ +++ b/web/templates/admin.templ @@ -69,6 +69,15 @@ templ AdminUsersList(users []database.User) { > View + }