Refactor workspace creation (#16689)
# Introduction Created an env variable to will inject a feature flag during any new workspace init to be created through v2
This commit is contained in:
@@ -1319,7 +1319,8 @@ export enum FeatureFlagKey {
|
||||
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
|
||||
IS_TIMELINE_ACTIVITY_MIGRATED = 'IS_TIMELINE_ACTIVITY_MIGRATED',
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
|
||||
IS_WORKFLOW_RUN_STOPPAGE_ENABLED = 'IS_WORKFLOW_RUN_STOPPAGE_ENABLED'
|
||||
IS_WORKFLOW_RUN_STOPPAGE_ENABLED = 'IS_WORKFLOW_RUN_STOPPAGE_ENABLED',
|
||||
IS_WORKSPACE_CREATION_V2_ENABLED = 'IS_WORKSPACE_CREATION_V2_ENABLED'
|
||||
}
|
||||
|
||||
export type Field = {
|
||||
|
||||
@@ -1302,7 +1302,8 @@ export enum FeatureFlagKey {
|
||||
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
|
||||
IS_TIMELINE_ACTIVITY_MIGRATED = 'IS_TIMELINE_ACTIVITY_MIGRATED',
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
|
||||
IS_WORKFLOW_RUN_STOPPAGE_ENABLED = 'IS_WORKFLOW_RUN_STOPPAGE_ENABLED'
|
||||
IS_WORKFLOW_RUN_STOPPAGE_ENABLED = 'IS_WORKFLOW_RUN_STOPPAGE_ENABLED',
|
||||
IS_WORKSPACE_CREATION_V2_ENABLED = 'IS_WORKSPACE_CREATION_V2_ENABLED'
|
||||
}
|
||||
|
||||
export type Field = {
|
||||
|
||||
@@ -26,3 +26,4 @@ AUTH_MICROSOFT_CALLBACK_URL=http://localhost:3000/auth/microsoft/redirect
|
||||
AUTH_MICROSOFT_APIS_CALLBACK_URL=http://localhost:3000/auth/microsoft-apis/get-access-token
|
||||
|
||||
CLICKHOUSE_URL=http://default:clickhousePassword@localhost:8123/twenty
|
||||
IS_WORKSPACE_CREATION_V2_ENABLED=true
|
||||
|
||||
+1
@@ -16,4 +16,5 @@ export enum FeatureFlagKey {
|
||||
IS_TIMELINE_ACTIVITY_MIGRATED = 'IS_TIMELINE_ACTIVITY_MIGRATED',
|
||||
IS_GLOBAL_WORKSPACE_DATASOURCE_ENABLED = 'IS_GLOBAL_WORKSPACE_DATASOURCE_ENABLED',
|
||||
IS_READ_ON_REPLICA_ENABLED = 'IS_READ_ON_REPLICA_ENABLED',
|
||||
IS_WORKSPACE_CREATION_V2_ENABLED = 'IS_WORKSPACE_CREATION_V2_ENABLED',
|
||||
}
|
||||
|
||||
@@ -1393,6 +1393,16 @@ export class ConfigVariables {
|
||||
@IsOptional()
|
||||
IS_MAPS_AND_ADDRESS_AUTOCOMPLETE_ENABLED = false;
|
||||
|
||||
@ConfigVariablesMetadata({
|
||||
group: ConfigVariablesGroup.OTHER,
|
||||
description:
|
||||
'Enable or disable workspace creation through v2 workspaceMigration',
|
||||
type: ConfigVariableType.BOOLEAN,
|
||||
isEnvOnly: true,
|
||||
})
|
||||
@IsOptional()
|
||||
IS_WORKSPACE_CREATION_V2_ENABLED = false;
|
||||
|
||||
@ConfigVariablesMetadata({
|
||||
group: ConfigVariablesGroup.OTHER,
|
||||
isSensitive: true,
|
||||
|
||||
+11
-1
@@ -17,6 +17,7 @@ import { DnsManagerService } from 'src/engine/core-modules/dns-manager/services/
|
||||
import { CustomDomainManagerService } from 'src/engine/core-modules/domain/custom-domain-manager/services/custom-domain-manager.service';
|
||||
import { SubdomainManagerService } from 'src/engine/core-modules/domain/subdomain-manager/services/subdomain-manager.service';
|
||||
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import {
|
||||
FileWorkspaceFolderDeletionJob,
|
||||
@@ -242,8 +243,17 @@ export class WorkspaceService extends TypeOrmQueryService<WorkspaceEntity> {
|
||||
activationStatus: WorkspaceActivationStatus.ONGOING_CREATION,
|
||||
});
|
||||
|
||||
const isV2SyncEnabled = this.twentyConfigService.get(
|
||||
'IS_WORKSPACE_CREATION_V2_ENABLED',
|
||||
);
|
||||
|
||||
await this.featureFlagService.enableFeatureFlags(
|
||||
DEFAULT_FEATURE_FLAGS,
|
||||
[
|
||||
...DEFAULT_FEATURE_FLAGS,
|
||||
...(isV2SyncEnabled
|
||||
? [FeatureFlagKey.IS_WORKSPACE_CREATION_V2_ENABLED]
|
||||
: []),
|
||||
],
|
||||
workspace.id,
|
||||
);
|
||||
|
||||
|
||||
+1
-1
@@ -205,7 +205,6 @@ describe('WorkspaceEntityManager', () => {
|
||||
IS_AI_ENABLED: false,
|
||||
IS_APPLICATION_ENABLED: false,
|
||||
IS_IMAP_SMTP_CALDAV_ENABLED: false,
|
||||
IS_MORPH_RELATION_ENABLED: false,
|
||||
IS_PAGE_LAYOUT_ENABLED: false,
|
||||
IS_RECORD_PAGE_LAYOUT_ENABLED: false,
|
||||
IS_PUBLIC_DOMAIN_ENABLED: false,
|
||||
@@ -215,6 +214,7 @@ describe('WorkspaceEntityManager', () => {
|
||||
IS_TIMELINE_ACTIVITY_MIGRATED: false,
|
||||
IS_GLOBAL_WORKSPACE_DATASOURCE_ENABLED: false,
|
||||
IS_READ_ON_REPLICA_ENABLED: false,
|
||||
IS_WORKSPACE_CREATION_V2_ENABLED: false,
|
||||
},
|
||||
eventEmitterService: {
|
||||
emitMutationEvent: jest.fn(),
|
||||
|
||||
+7
@@ -23,6 +23,7 @@ import { WorkspaceMigrationEntity } from 'src/engine/metadata-modules/workspace-
|
||||
import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.service';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import { TwentyStandardApplicationService } from 'src/engine/workspace-manager/twenty-standard-application/services/twenty-standard-application.service';
|
||||
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
|
||||
import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service';
|
||||
|
||||
@@ -130,6 +131,12 @@ describe('WorkspaceManagerService', () => {
|
||||
deleteWorkspaceAllObjectMetadata: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: TwentyStandardApplicationService,
|
||||
useValue: {
|
||||
synchronizeTwentyStandardApplicationOrThrow: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: AgentService,
|
||||
useValue: {
|
||||
|
||||
@@ -20,6 +20,7 @@ import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/works
|
||||
import { DevSeederModule } from 'src/engine/workspace-manager/dev-seeder/dev-seeder.module';
|
||||
import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-v2.module';
|
||||
import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module';
|
||||
import { TwentyStandardApplicationModule } from 'src/engine/workspace-manager/twenty-standard-application/twenty-standard-application.module';
|
||||
|
||||
import { WorkspaceManagerService } from './workspace-manager.service';
|
||||
|
||||
@@ -35,6 +36,7 @@ import { WorkspaceManagerService } from './workspace-manager.service';
|
||||
FeatureFlagModule,
|
||||
PermissionsModule,
|
||||
AiAgentModule,
|
||||
TwentyStandardApplicationModule,
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheModule,
|
||||
TypeOrmModule.forFeature([UserWorkspaceEntity, WorkspaceEntity]),
|
||||
RoleModule,
|
||||
|
||||
@@ -5,6 +5,8 @@ import { DataSource, Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { fromApplicationEntityToFlatApplication } from 'src/engine/core-modules/application/utils/from-application-entity-to-flat-application.util';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
@@ -21,6 +23,7 @@ import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspac
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
import { prefillCoreViews } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-core-views';
|
||||
import { standardObjectsPrefillData } from 'src/engine/workspace-manager/standard-objects-prefill-data/standard-objects-prefill-data';
|
||||
import { TwentyStandardApplicationService } from 'src/engine/workspace-manager/twenty-standard-application/services/twenty-standard-application.service';
|
||||
import { ADMIN_ROLE } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-roles/roles/admin-role';
|
||||
import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service';
|
||||
|
||||
@@ -35,12 +38,11 @@ export class WorkspaceManagerService {
|
||||
private readonly workspaceMigrationService: WorkspaceMigrationService,
|
||||
private readonly objectMetadataService: ObjectMetadataService,
|
||||
private readonly dataSourceService: DataSourceService,
|
||||
private readonly workspaceSyncMetadataService: WorkspaceSyncMetadataService,
|
||||
@InjectRepository(UserWorkspaceEntity)
|
||||
private readonly userWorkspaceRepository: Repository<UserWorkspaceEntity>,
|
||||
private readonly roleService: RoleService,
|
||||
private readonly userRoleService: UserRoleService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly twentyStandardApplicationService: TwentyStandardApplicationService,
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
private readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
@InjectRepository(RoleEntity)
|
||||
@@ -50,6 +52,8 @@ export class WorkspaceManagerService {
|
||||
protected readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly workspaceSyncMetadataService: WorkspaceSyncMetadataService,
|
||||
) {}
|
||||
|
||||
public async init({
|
||||
@@ -87,12 +91,39 @@ export class WorkspaceManagerService {
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
// TODO later replace by twenty-standard installation aka workspaceMigration run
|
||||
await this.workspaceSyncMetadataService.synchronize({
|
||||
workspaceId,
|
||||
dataSourceId: dataSourceMetadata.id,
|
||||
featureFlags,
|
||||
});
|
||||
const isV2SyncEnabled =
|
||||
featureFlags[FeatureFlagKey.IS_WORKSPACE_CREATION_V2_ENABLED];
|
||||
|
||||
if (isV2SyncEnabled) {
|
||||
await this.twentyStandardApplicationService.synchronizeTwentyStandardApplicationOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await this.workspaceSyncMetadataService.synchronize({
|
||||
workspaceId,
|
||||
dataSourceId: dataSourceMetadata.id,
|
||||
featureFlags,
|
||||
});
|
||||
|
||||
const prefillStandardObjectsStart = performance.now();
|
||||
|
||||
await this.prefillWorkspaceWithStandardObjectsRecords({
|
||||
dataSourceMetadata,
|
||||
workspaceId,
|
||||
featureFlags,
|
||||
twentyStandardFlatApplication: fromApplicationEntityToFlatApplication(
|
||||
twentyStandardApplication,
|
||||
),
|
||||
});
|
||||
|
||||
const prefillStandardObjectsEnd = performance.now();
|
||||
|
||||
this.logger.log(
|
||||
`Prefill standard objects took ${prefillStandardObjectsEnd - prefillStandardObjectsStart}ms`,
|
||||
);
|
||||
}
|
||||
|
||||
const dataSourceMetadataCreationEnd = performance.now();
|
||||
|
||||
@@ -112,29 +143,19 @@ export class WorkspaceManagerService {
|
||||
userId,
|
||||
workspaceCustomFlatApplication,
|
||||
});
|
||||
|
||||
const prefillStandardObjectsStart = performance.now();
|
||||
|
||||
await this.prefillWorkspaceWithStandardObjectsRecords(
|
||||
dataSourceMetadata,
|
||||
workspaceId,
|
||||
featureFlags,
|
||||
twentyStandardApplication,
|
||||
);
|
||||
|
||||
const prefillStandardObjectsEnd = performance.now();
|
||||
|
||||
this.logger.log(
|
||||
`Prefill standard objects took ${prefillStandardObjectsEnd - prefillStandardObjectsStart}ms`,
|
||||
);
|
||||
}
|
||||
|
||||
private async prefillWorkspaceWithStandardObjectsRecords(
|
||||
dataSourceMetadata: DataSourceEntity,
|
||||
workspaceId: string,
|
||||
featureFlags: Record<string, boolean>,
|
||||
twentyStandardFlatApplication: FlatApplication,
|
||||
) {
|
||||
private async prefillWorkspaceWithStandardObjectsRecords({
|
||||
dataSourceMetadata,
|
||||
workspaceId,
|
||||
featureFlags,
|
||||
twentyStandardFlatApplication,
|
||||
}: {
|
||||
dataSourceMetadata: DataSourceEntity;
|
||||
workspaceId: string;
|
||||
featureFlags: Record<string, boolean>;
|
||||
twentyStandardFlatApplication: FlatApplication;
|
||||
}) {
|
||||
const { flatObjectMetadataMaps, flatFieldMetadataMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
import { randomUUID } from 'crypto';
|
||||
|
||||
import { activateWorkspace } from 'test/integration/graphql/utils/activate-workspace.util';
|
||||
import { deleteUser } from 'test/integration/graphql/utils/delete-user.util';
|
||||
import { findManyApplications } from 'test/integration/graphql/utils/find-many-applications.util';
|
||||
import { getAuthTokensFromLoginToken } from 'test/integration/graphql/utils/get-auth-tokens-from-login-token.util';
|
||||
import { getCurrentUser } from 'test/integration/graphql/utils/get-current-user.util';
|
||||
import { signUpInNewWorkspace } from 'test/integration/graphql/utils/sign-up-in-new-workspace.util';
|
||||
import { signUp } from 'test/integration/graphql/utils/sign-up.util';
|
||||
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
|
||||
import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util.test';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
|
||||
import { updateFeatureFlag } from 'test/integration/metadata/suites/utils/update-feature-flag.util';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications';
|
||||
|
||||
describe('Successful user and workspace creation', () => {
|
||||
let createdUserAccessToken: string | undefined;
|
||||
|
||||
afterEach(async () => {
|
||||
if (!isDefined(createdUserAccessToken)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await deleteUser({
|
||||
accessToken: createdUserAccessToken,
|
||||
expectToFail: false,
|
||||
});
|
||||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
await updateFeatureFlag({
|
||||
expectToFail: false,
|
||||
featureFlag: FeatureFlagKey.IS_WORKSPACE_CREATION_V2_ENABLED,
|
||||
value: false,
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await updateFeatureFlag({
|
||||
expectToFail: false,
|
||||
featureFlag: FeatureFlagKey.IS_WORKSPACE_CREATION_V2_ENABLED,
|
||||
value: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should sign up a new user and create a new workspace successfully', async () => {
|
||||
const uniqueEmail = `test-${randomUUID()}@example.com`;
|
||||
|
||||
const { data } = await signUp({
|
||||
input: {
|
||||
email: uniqueEmail,
|
||||
password: 'Test123!@#',
|
||||
},
|
||||
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
createdUserAccessToken =
|
||||
data.signUp.tokens.accessOrWorkspaceAgnosticToken.token;
|
||||
|
||||
// Mark email as verified to bypass email verification requirement
|
||||
await testDataSource.query(
|
||||
'UPDATE core."user" SET "isEmailVerified" = true WHERE email = $1',
|
||||
[uniqueEmail],
|
||||
);
|
||||
|
||||
const {
|
||||
data: { signUpInNewWorkspace: signUpInNewWorkspaceData },
|
||||
} = await signUpInNewWorkspace({
|
||||
accessToken: createdUserAccessToken,
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const {
|
||||
data: { getAuthTokensFromLoginToken: authTokensData },
|
||||
} = await getAuthTokensFromLoginToken({
|
||||
origin: signUpInNewWorkspaceData.workspace.workspaceUrls.subdomainUrl,
|
||||
loginToken: signUpInNewWorkspaceData.loginToken.token,
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const newWorkspaceAccessToken =
|
||||
authTokensData.tokens.accessOrWorkspaceAgnosticToken.token;
|
||||
|
||||
const {
|
||||
data: { activateWorkspace: activateWorkspaceData },
|
||||
} = await activateWorkspace({
|
||||
accessToken: newWorkspaceAccessToken,
|
||||
displayName: '42 answer',
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
expect(activateWorkspaceData.activationStatus).toBe(
|
||||
WorkspaceActivationStatus.ACTIVE,
|
||||
);
|
||||
|
||||
const {
|
||||
data: { currentUser },
|
||||
} = await getCurrentUser({
|
||||
accessToken: newWorkspaceAccessToken,
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
jestExpectToBeDefined(currentUser.currentWorkspace);
|
||||
const { inviteHash: _, ...expectedCurrentWorkspace } =
|
||||
activateWorkspaceData;
|
||||
|
||||
jestExpectToBeDefined(currentUser.currentWorkspace);
|
||||
expect(currentUser.currentWorkspace).toMatchObject(
|
||||
expectedCurrentWorkspace,
|
||||
);
|
||||
|
||||
const {
|
||||
data: { findManyApplications: findManyApplicationsData },
|
||||
} = await findManyApplications({
|
||||
accessToken: newWorkspaceAccessToken,
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
expect(findManyApplicationsData.length).toBe(2);
|
||||
const twentyStandardApp = findManyApplicationsData.find(
|
||||
(application) =>
|
||||
application.universalIdentifier ===
|
||||
TWENTY_STANDARD_APPLICATION.universalIdentifier,
|
||||
);
|
||||
|
||||
jestExpectToBeDefined(twentyStandardApp);
|
||||
const {
|
||||
sourcePath: _sourcePath,
|
||||
sourceType: _sourceType,
|
||||
...expectedStandardTwentyApplication
|
||||
} = TWENTY_STANDARD_APPLICATION;
|
||||
|
||||
expect(twentyStandardApp).toMatchObject(expectedStandardTwentyApplication);
|
||||
|
||||
const workpsaceCustomApplication = findManyApplicationsData.find(
|
||||
(application) =>
|
||||
application.id ===
|
||||
currentUser.currentWorkspace?.workspaceCustomApplicationId,
|
||||
);
|
||||
|
||||
jestExpectToBeDefined(workpsaceCustomApplication);
|
||||
expect(workpsaceCustomApplication.universalIdentifier).toEqual(
|
||||
workpsaceCustomApplication.id,
|
||||
);
|
||||
});
|
||||
|
||||
it('should delete workspace and related metadata entities when last user is deleted', async () => {
|
||||
const uniqueEmail = `test-delete-${randomUUID()}@example.com`;
|
||||
|
||||
const { data } = await signUp({
|
||||
input: {
|
||||
email: uniqueEmail,
|
||||
password: 'Test123!@#',
|
||||
},
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
createdUserAccessToken =
|
||||
data.signUp.tokens.accessOrWorkspaceAgnosticToken.token;
|
||||
|
||||
// Mark email as verified to bypass email verification requirement
|
||||
await testDataSource.query(
|
||||
'UPDATE core."user" SET "isEmailVerified" = true WHERE email = $1',
|
||||
[uniqueEmail],
|
||||
);
|
||||
|
||||
const {
|
||||
data: { signUpInNewWorkspace: signUpInNewWorkspaceData },
|
||||
} = await signUpInNewWorkspace({
|
||||
accessToken: createdUserAccessToken,
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const workspaceId = signUpInNewWorkspaceData.workspace.id;
|
||||
|
||||
const {
|
||||
data: { getAuthTokensFromLoginToken: authTokensData },
|
||||
} = await getAuthTokensFromLoginToken({
|
||||
origin: signUpInNewWorkspaceData.workspace.workspaceUrls.subdomainUrl,
|
||||
loginToken: signUpInNewWorkspaceData.loginToken.token,
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const newWorkspaceAccessToken =
|
||||
authTokensData.tokens.accessOrWorkspaceAgnosticToken.token;
|
||||
|
||||
await activateWorkspace({
|
||||
accessToken: newWorkspaceAccessToken,
|
||||
displayName: 'Test Workspace for Deletion',
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
await createOneObjectMetadata({
|
||||
input: {
|
||||
nameSingular: 'workspaceEviction',
|
||||
namePlural: 'workspaceEvictions',
|
||||
labelPlural: 'whatevers',
|
||||
labelSingular: 'whatever',
|
||||
isLabelSyncedWithName: false,
|
||||
},
|
||||
token: newWorkspaceAccessToken,
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
const workspaceBeforeDeletion = await testDataSource.query(
|
||||
'SELECT * FROM core.workspace WHERE id = $1',
|
||||
[workspaceId],
|
||||
);
|
||||
|
||||
expect(workspaceBeforeDeletion).toHaveLength(1);
|
||||
|
||||
const tablesToVerify = [
|
||||
'dataSource',
|
||||
'objectMetadata',
|
||||
'fieldMetadata',
|
||||
'indexMetadata',
|
||||
'searchFieldMetadata',
|
||||
'workspaceMigration',
|
||||
'role',
|
||||
'roleTarget',
|
||||
'objectPermission',
|
||||
'fieldPermission',
|
||||
'permissionFlag',
|
||||
'serverlessFunction',
|
||||
'serverlessFunctionLayer',
|
||||
'agent',
|
||||
'remoteServer',
|
||||
'remoteTable',
|
||||
'databaseEventTrigger',
|
||||
'view',
|
||||
'viewField',
|
||||
'viewFilter',
|
||||
'viewFilterGroup',
|
||||
'viewGroup',
|
||||
'viewSort',
|
||||
'cronTrigger',
|
||||
'routeTrigger',
|
||||
];
|
||||
|
||||
let totalRecordsBefore = 0;
|
||||
|
||||
for (const table of tablesToVerify) {
|
||||
const result = await testDataSource.query(
|
||||
`SELECT COUNT(*) as count FROM core."${table}" WHERE "workspaceId" = $1`,
|
||||
[workspaceId],
|
||||
);
|
||||
|
||||
totalRecordsBefore += parseInt(result[0].count);
|
||||
}
|
||||
|
||||
expect(totalRecordsBefore).toBeGreaterThan(0);
|
||||
|
||||
await deleteUser({
|
||||
accessToken: createdUserAccessToken,
|
||||
expectToFail: false,
|
||||
});
|
||||
|
||||
createdUserAccessToken = undefined;
|
||||
|
||||
const workspaceAfterDeletion = await testDataSource.query(
|
||||
'SELECT * FROM core.workspace WHERE id = $1',
|
||||
[workspaceId],
|
||||
);
|
||||
|
||||
expect(workspaceAfterDeletion).toHaveLength(0);
|
||||
|
||||
for (const table of tablesToVerify) {
|
||||
const result = await testDataSource.query(
|
||||
`SELECT COUNT(*) as count FROM core."${table}" WHERE "workspaceId" = $1`,
|
||||
[workspaceId],
|
||||
);
|
||||
const count = parseInt(result[0].count);
|
||||
|
||||
expect({ count, table }).toEqual({ count: 0, table });
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user