Просмотр исходного кода

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 часов назад
Родитель
Сommit
052409ef21
2 измененных файлов с 9 добавлено и 9 удалено
  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)
 }