admin: add delete user with confirmation dialog
This commit is contained in:
@@ -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) {
|
func writeInlineError(w http.ResponseWriter, message string) {
|
||||||
w.Header().Set("Content-Type", "text/html")
|
w.Header().Set("Content-Type", "text/html")
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ SELECT * FROM user WHERE username = ? LIMIT 1;
|
|||||||
-- name: ListUsers :many
|
-- name: ListUsers :many
|
||||||
SELECT * FROM user ORDER BY created_at DESC;
|
SELECT * FROM user ORDER BY created_at DESC;
|
||||||
|
|
||||||
|
-- name: DeleteUser :exec
|
||||||
|
DELETE FROM user WHERE id = ?;
|
||||||
|
|
||||||
-- name: CreateUser :one
|
-- name: CreateUser :one
|
||||||
INSERT INTO user (id, username, password_hash)
|
INSERT INTO user (id, username, password_hash)
|
||||||
VALUES (?, ?, ?)
|
VALUES (?, ?, ?)
|
||||||
|
|||||||
@@ -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) {
|
mux.Handle("/admin/users/", middleware.RequireAdmin(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
path := r.URL.Path
|
path := r.URL.Path
|
||||||
switch {
|
switch {
|
||||||
|
case strings.HasSuffix(path, "/delete"):
|
||||||
|
adminHandler.HandleDeleteUser(w, r)
|
||||||
case strings.HasSuffix(path, "/watchlist"):
|
case strings.HasSuffix(path, "/watchlist"):
|
||||||
adminHandler.HandleUserWatchlist(w, r)
|
adminHandler.HandleUserWatchlist(w, r)
|
||||||
case strings.HasSuffix(path, "/continue-watching"):
|
case strings.HasSuffix(path, "/continue-watching"):
|
||||||
|
|||||||
@@ -69,6 +69,15 @@ templ AdminUsersList(users []database.User) {
|
|||||||
>
|
>
|
||||||
View
|
View
|
||||||
</a>
|
</a>
|
||||||
|
<button
|
||||||
|
hx-delete={ templ.URL(fmt.Sprintf("/admin/users/%s/delete", user.ID)) }
|
||||||
|
hx-target="#users-list"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-confirm={ fmt.Sprintf("Are you sure you want to delete %s? This cannot be undone.", user.Username) }
|
||||||
|
class="rounded bg-(--surface-button) px-3 py-1 text-xs text-(--danger) opacity-80 transition-opacity duration-150 hover:opacity-100"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user