package api import ( "context" "errors" "net/http" "time" "github.com/gofiber/fiber/v3" accountdomain "git.ipao.vip/rogee/creator-hub/internal/account" "git.ipao.vip/rogee/creator-hub/internal/creator" hub "git.ipao.vip/rogee/creator-hub/internal/environment" ) func registerAccountDeletion(app *fiber.App, phaseAStore *accountdomain.Store, hubStore *hub.Store, creatorStore *creator.Store, credentials accountdomain.CredentialBridge) { app.Delete("/api/phase-a/accounts/:id", func(c fiber.Ctx) error { accountID := c.Params("id") if err := phaseAStore.CheckAccountDeletion(c.Context(), accountID); err != nil { return phaseAError(c, err) } if err := creatorStore.CheckOwnedAccountDeletion(c.Context(), accountID); err != nil { return creatorError(c, err) } environment, hasEnvironment, err := accountEnvironment(c.Context(), hubStore, accountID) if err != nil { return hubError(c, err) } unlock := func() {} if hasEnvironment { aliases := []string{environment.Alias} exitIDs := []string{} if environment.Exit.ID != "" { exitIDs = append(exitIDs, environment.Exit.ID) } unlock, err = hubStore.LockResources(c.Context(), aliases, exitIDs) if err != nil { return hubError(c, err) } defer unlock() gateway, gatewayErr := hubStore.GetGateway(c.Context(), environment.Gateway) if gatewayErr != nil { return hubError(c, gatewayErr) } if err := creatorStore.InvalidateListener(c.Context(), accountID, "账号删除"); err != nil { return creatorError(c, err) } if _, err := removeGatewayRuntime(c.Context(), hubStore, gateway, environment); err != nil { return hubError(c, err) } if err := purgeAccountProfile(c.Context(), gateway, environment); err != nil { return hubError(c, err) } } if err := phaseAStore.DeleteAccountData(c.Context(), accountID); err != nil { return phaseAError(c, err) } if err := creatorStore.DeleteOwnedAccountData(c.Context(), accountID); err != nil { return creatorError(c, err) } if hasEnvironment { if err := hubStore.DeleteAccountEnvironment(c.Context(), accountID); err != nil { return hubError(c, err) } } if err := phaseAStore.DeleteAccount(c.Context(), accountID, credentials); err != nil { return phaseAError(c, err) } return c.SendStatus(fiber.StatusNoContent) }) app.Delete("/api/creator/competitors/:id", func(c fiber.Ctx) error { if err := creatorStore.DeleteCompetitor(c.Context(), c.Params("id")); err != nil { return creatorError(c, err) } return c.SendStatus(fiber.StatusNoContent) }) } type environmentContextStore interface { GetEnvironmentContextForAccount(context.Context, string) (hub.EnvironmentContext, error) } func accountEnvironment(ctx context.Context, store environmentContextStore, accountID string) (hub.EnvironmentContext, bool, error) { if store == nil { return hub.EnvironmentContext{}, false, creator.ErrUnavailable } environment, err := store.GetEnvironmentContextForAccount(ctx, accountID) if errors.Is(err, hub.ErrNotFound) { return hub.EnvironmentContext{}, false, nil } if err != nil { return hub.EnvironmentContext{}, false, err } return environment, true, nil } func purgeAccountProfile(ctx context.Context, gateway hub.Gateway, environment hub.EnvironmentContext) error { payload := gatewayCleanupGenerationPayload(environment) payload["purge_profile"] = true status, body, err := gatewayCall(ctx, gateway, http.MethodDelete, "/v1/browsers/"+environment.Alias, payload, 30*time.Second) if err != nil { return gatewayUnreachable(err) } if status == http.StatusNoContent || status == http.StatusNotFound { return nil } return gatewayRejected(status, body) } // RegisterAccountDeletion exposes destructive account routes to the grouped API package. func RegisterAccountDeletion(app *fiber.App, accountStore *accountdomain.Store, environmentStore *hub.Store, creatorStore *creator.Store, credentials accountdomain.CredentialBridge) { registerAccountDeletion(app, accountStore, environmentStore, creatorStore, credentials) }