feat(server): handle account deleting properly (#12399)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Users are now prevented from deleting their account if they own one or more team workspaces. A clear error message instructs users to transfer ownership or delete those workspaces first.
  - Disabled (banned) users are explicitly prevented from signing in or re-registering.
  - Added new error messages and translations to improve clarity around account deletion restrictions.

- **Bug Fixes**
  - Disabled users are now explicitly handled to prevent sign-in attempts.

- **Tests**
  - Introduced comprehensive end-to-end tests covering account deletion, banning, and re-registration scenarios.

- **Chores**
  - Improved event handling for user deletion and subscription cancellation.
  - Updated localization resources with new error messages.
  - Renamed payment event handler class for clarity.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
forehalo
2025-05-23 03:57:29 +00:00
parent f99b143bf9
commit f38b8fef4d
15 changed files with 235 additions and 23 deletions

View File

@@ -6,7 +6,7 @@ import { Models } from '../../models';
import { SubscriptionPlan } from './types';
@Injectable()
export class QuotaOverride {
export class PaymentEventHandlers {
constructor(
private readonly workspace: WorkspaceService,
private readonly models: Models,

View File

@@ -11,13 +11,13 @@ import { UserModule } from '../../core/user';
import { WorkspaceModule } from '../../core/workspaces';
import { StripeWebhookController } from './controller';
import { SubscriptionCronJobs } from './cron';
import { PaymentEventHandlers } from './event';
import { LicenseController } from './license/controller';
import {
SelfhostTeamSubscriptionManager,
UserSubscriptionManager,
WorkspaceSubscriptionManager,
} from './manager';
import { QuotaOverride } from './quota';
import {
SubscriptionResolver,
UserSubscriptionResolver,
@@ -49,7 +49,7 @@ import { StripeWebhook } from './webhook';
SelfhostTeamSubscriptionManager,
SubscriptionCronJobs,
WorkspaceSubscriptionResolver,
QuotaOverride,
PaymentEventHandlers,
],
controllers: [StripeWebhookController, LicenseController],
})

View File

@@ -10,6 +10,7 @@ import {
InternalServerError,
InvalidCheckoutParameters,
Mutex,
OnEvent,
SubscriptionAlreadyExists,
SubscriptionPlanNotFound,
TooManyRequest,
@@ -683,4 +684,17 @@ export class UserSubscriptionManager extends SubscriptionManager {
throw new Error('user should exists for stripe subscription or invoice.');
}
}
@OnEvent('user.deleted')
async onUserDeleted({ id }: Events['user.deleted']) {
const subscription = await this.db.subscription.findFirst({
where: {
targetId: id,
},
});
if (subscription?.stripeSubscriptionId) {
await this.stripe.subscriptions.cancel(subscription.stripeSubscriptionId);
}
}
}