add command to destroy workspaces (#13447)
Dev tool to enable workspace destroy - two guards added (destroy only billing inactive workspace + soft deleted) closes : https://github.com/twentyhq/core-team-issues/issues/1238 --------- Co-authored-by: Guillim <guillim@users.noreply.github.com>
This commit is contained in:
+48
@@ -0,0 +1,48 @@
|
||||
import { Command, Option } from 'nest-commander';
|
||||
|
||||
import {
|
||||
MigrationCommandOptions,
|
||||
MigrationCommandRunner,
|
||||
} from 'src/database/commands/command-runners/migration.command-runner';
|
||||
import { CleanerWorkspaceService } from 'src/engine/workspace-manager/workspace-cleaner/services/cleaner.workspace-service';
|
||||
|
||||
@Command({
|
||||
name: 'workspace:destroy',
|
||||
description: 'Destroy workspace',
|
||||
})
|
||||
export class DestroyWorkspaceCommand extends MigrationCommandRunner {
|
||||
private workspaceIds: string[] = [];
|
||||
|
||||
constructor(
|
||||
private readonly cleanerWorkspaceService: CleanerWorkspaceService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@Option({
|
||||
flags: '-w, --workspace-id <workspace_id>',
|
||||
description: 'workspace id - mandatory',
|
||||
required: true,
|
||||
})
|
||||
parseWorkspaceId(val: string): string[] {
|
||||
this.workspaceIds.push(val);
|
||||
|
||||
return this.workspaceIds;
|
||||
}
|
||||
|
||||
override async runMigrationCommand(
|
||||
_passedParams: string[],
|
||||
options: MigrationCommandOptions,
|
||||
): Promise<void> {
|
||||
const { dryRun } = options;
|
||||
|
||||
this.logger.log(
|
||||
`${dryRun ? 'DRY RUN - ' : ''}Destroy ${this.workspaceIds.length} workspaces : ${this.workspaceIds.join(', ')}`,
|
||||
);
|
||||
|
||||
await this.cleanerWorkspaceService.destroyBillingDeactivatedAndSoftDeletedWorkspaces(
|
||||
this.workspaceIds,
|
||||
dryRun,
|
||||
);
|
||||
}
|
||||
}
|
||||
+60
@@ -14,6 +14,7 @@ import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
|
||||
import { In, Repository } from 'typeorm';
|
||||
|
||||
import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity';
|
||||
import { SubscriptionStatus } from 'src/engine/core-modules/billing/enums/billing-subscription-status.enum';
|
||||
import { EmailService } from 'src/engine/core-modules/email/email.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
@@ -392,4 +393,63 @@ export class CleanerWorkspaceService {
|
||||
`${dryRun ? 'DRY RUN - ' : ''}batchWarnOrCleanSuspendedWorkspaces done!`,
|
||||
);
|
||||
}
|
||||
|
||||
async destroyBillingDeactivatedAndSoftDeletedWorkspaces(
|
||||
workspaceIds: string[],
|
||||
dryRun = false,
|
||||
): Promise<void> {
|
||||
this.logger.log(
|
||||
`${dryRun ? 'DRY RUN - ' : ''}destroyBillingDeactivatedAndSoftDeletedWorkspaces running...`,
|
||||
);
|
||||
|
||||
const workspaces = await this.workspaceRepository.find({
|
||||
where: {
|
||||
id: In(workspaceIds),
|
||||
},
|
||||
withDeleted: true,
|
||||
});
|
||||
|
||||
for (const workspace of workspaces) {
|
||||
if (!isDefined(workspace.deletedAt)) {
|
||||
this.logger.warn(
|
||||
`${dryRun ? 'DRY RUN - ' : ''}Workspace ${workspace.id} is not soft deleted, skipping`,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.twentyConfigService.get('IS_BILLING_ENABLED')) {
|
||||
const activeBillingSubscription =
|
||||
await this.billingSubscriptionRepository.findOne({
|
||||
where: {
|
||||
workspaceId: workspace.id,
|
||||
status: In([
|
||||
SubscriptionStatus.Active,
|
||||
SubscriptionStatus.Trialing,
|
||||
]),
|
||||
},
|
||||
});
|
||||
|
||||
if (isDefined(activeBillingSubscription)) {
|
||||
this.logger.warn(
|
||||
`${dryRun ? 'DRY RUN - ' : ''}Workspace ${workspace.id} has an active billing subscription, skipping`,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`${dryRun ? 'DRY RUN - ' : ''}Destroying workspace ${workspace.id}`,
|
||||
);
|
||||
|
||||
if (!dryRun) {
|
||||
await this.workspaceService.deleteWorkspace(workspace.id);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`${dryRun ? 'DRY RUN - ' : ''}Destroyed workspace ${workspace.id}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -15,6 +15,7 @@ import { CleanOnboardingWorkspacesCronCommand } from 'src/engine/workspace-manag
|
||||
import { CleanSuspendedWorkspacesCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/clean-suspended-workspaces.command';
|
||||
import { CleanSuspendedWorkspacesCronCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/clean-suspended-workspaces.cron.command';
|
||||
import { DeleteWorkspacesCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/delete-workspaces.command';
|
||||
import { DestroyWorkspaceCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/destroy-workspace.command';
|
||||
import { CleanerWorkspaceService } from 'src/engine/workspace-manager/workspace-cleaner/services/cleaner.workspace-service';
|
||||
|
||||
@Module({
|
||||
@@ -33,6 +34,7 @@ import { CleanerWorkspaceService } from 'src/engine/workspace-manager/workspace-
|
||||
providers: [
|
||||
DeleteWorkspacesCommand,
|
||||
CleanSuspendedWorkspacesCommand,
|
||||
DestroyWorkspaceCommand,
|
||||
CleanSuspendedWorkspacesCronCommand,
|
||||
CleanOnboardingWorkspacesCommand,
|
||||
CleanOnboardingWorkspacesCronCommand,
|
||||
|
||||
Reference in New Issue
Block a user