From eea9f527edfec7754ccbffd6aa166d94f32be3c3 Mon Sep 17 00:00:00 2001 From: Lucca Dukic <109136188+LuccaBitfly@users.noreply.github.com> Date: Wed, 15 Jan 2025 10:09:19 +0100 Subject: [PATCH] fix: don't allow user deletion with active subscriptions See: BEDS-924 --- backend/pkg/api/data_access/dummy.go | 4 ++++ backend/pkg/api/data_access/user.go | 23 +++++++++++++++++++++++ backend/pkg/api/handlers/auth.go | 18 ++++++++++++++---- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/backend/pkg/api/data_access/dummy.go b/backend/pkg/api/data_access/dummy.go index 76e4a94a4..d45874650 100644 --- a/backend/pkg/api/data_access/dummy.go +++ b/backend/pkg/api/data_access/dummy.go @@ -805,3 +805,7 @@ func (d *DummyService) QueueTestWebhookNotification(ctx context.Context, userId func (d *DummyService) GetPairedDeviceUserId(ctx context.Context, pairedDeviceId uint64) (uint64, error) { return getDummyData[uint64](ctx) } + +func (d *DummyService) GetHasUserActiveSubscription(ctx context.Context, userId uint64) (bool, error) { + return getDummyData[bool](ctx) +} diff --git a/backend/pkg/api/data_access/user.go b/backend/pkg/api/data_access/user.go index 62e689ed4..349ceb8d3 100644 --- a/backend/pkg/api/data_access/user.go +++ b/backend/pkg/api/data_access/user.go @@ -33,6 +33,7 @@ type UserRepository interface { GetUserInfo(ctx context.Context, id uint64) (*t.UserInfo, error) GetUserDashboards(ctx context.Context, userId uint64) (*t.UserDashboardsData, error) GetUserValidatorDashboardCount(ctx context.Context, userId uint64, active bool) (uint64, error) + GetHasUserActiveSubscription(ctx context.Context, userId uint64) (bool, error) } func (d *DataAccessService) GetUserByEmail(ctx context.Context, email string) (uint64, error) { @@ -398,3 +399,25 @@ func (d *DataAccessService) GetUserValidatorDashboardCount(ctx context.Context, return count, err } + +func (d *DataAccessService) GetHasUserActiveSubscription(ctx context.Context, userId uint64) (bool, error) { + var hasUserActiveSubscription bool + err := db.UserReader.GetContext(ctx, &hasUserActiveSubscription, ` + SELECT EXISTS ( + SELECT uss.price_id + FROM users_stripe_subscriptions uss + LEFT JOIN users u ON u.stripe_customer_id = uss.customer_id + WHERE uss.active = true AND u.id = $1 + + UNION + + SELECT product_id + FROM users_app_subscriptions uas + LEFT JOIN users u ON u.id = uas.user_id + WHERE uas.active = true AND u.id = $1 + )`, userId) + if err != nil { + return false, err + } + return hasUserActiveSubscription, nil +} diff --git a/backend/pkg/api/handlers/auth.go b/backend/pkg/api/handlers/auth.go index 357a47cb5..6716bc16e 100644 --- a/backend/pkg/api/handlers/auth.go +++ b/backend/pkg/api/handlers/auth.go @@ -739,20 +739,30 @@ func (h *HandlerService) InternalPostLogout(w http.ResponseWriter, r *http.Reque } func (h *HandlerService) InternalDeleteUser(w http.ResponseWriter, r *http.Request) { - user, err := h.getUserBySession(r) + userId, err := h.GetUserIdBySession(r) if err != nil { handleErr(w, r, err) return } - // TODO allow if user has any subsciptions etc? - err = h.daService.RemoveUser(r.Context(), user.Id) + ctx := r.Context() + hasUserActiveSubscription, err := h.daService.GetHasUserActiveSubscription(ctx, userId) if err != nil { handleErr(w, r, err) return } + if hasUserActiveSubscription { + handleErr(w, r, newConflictErr("user has an active premium subscription or premium API plan, please cancel them first before deleting the account")) + return + } - err = h.purgeAllSessionsForUser(r.Context(), user.Id) + err = h.daService.RemoveUser(ctx, userId) + if err != nil { + handleErr(w, r, err) + return + } + + err = h.purgeAllSessionsForUser(ctx, userId) if err != nil { handleErr(w, r, err) return