Răsfoiți Sursa

fix(api): delete users synchronously and report failures

The remove user endpoint ran RemoveUser in a fire-and-forget goroutine
and returned 204 before the deletion was committed. The removed user's
API keys and sessions kept working until the DELETE landed, and if it
failed the error was only logged, leaving the account in place while
the client was told it had been removed.

The goroutine was originally added to avoid long-running transactions
when deleting large users, but RemoveUser is now a single DELETE that
relies on ON DELETE CASCADE, so running it in the background no longer
helps. Wait for the deletion to complete and return a server error if
it fails, matching the web UI behavior.
Fred 13 ore în urmă
părinte
comite
052409ef21
2 a modificat fișierele cu 9 adăugiri și 9 ștergeri
  1. 4 0
      internal/api/api_integration_test.go
  2. 5 9
      internal/api/user_handlers.go

+ 4 - 0
internal/api/api_integration_test.go

@@ -380,6 +380,10 @@ func TestRemoveUserEndpointAsAdmin(t *testing.T) {
 	if err := client.DeleteUser(user.ID); err != nil {
 		t.Fatal(err)
 	}
+
+	if _, err := client.UserByID(user.ID); !errors.Is(err, miniflux.ErrNotFound) {
+		t.Fatalf(`The user should be removed once the delete request returns, got error: %v`, err)
+	}
 }
 
 func TestRemoveUserEndpointAsRegularUser(t *testing.T) {

+ 5 - 9
internal/api/user_handlers.go

@@ -6,7 +6,6 @@ package api // import "miniflux.app/v2/internal/api"
 import (
 	json_parser "encoding/json"
 	"errors"
-	"log/slog"
 	"net/http"
 
 	"miniflux.app/v2/internal/http/request"
@@ -267,13 +266,10 @@ func (h *handler) removeUserHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	go func() {
-		if err := h.store.RemoveUser(user.ID); err != nil {
-			slog.Error("Unable to delete user",
-				slog.Int64("user_id", user.ID),
-				slog.Any("error", err),
-			)
-		}
-	}()
+	if err := h.store.RemoveUser(user.ID); err != nil {
+		response.JSONServerError(w, r, err)
+		return
+	}
+
 	response.NoContent(w, r)
 }