mirror of
https://github.com/twentyhq/twenty
synced 2026-04-29 01:17:31 +00:00
https://github.com/user-attachments/assets/4be785e0-ea8a-4c8e-840e-6fa0a663d7ba Closes #11938 --------- Co-authored-by: martmull <martmull@hotmail.fr>
322 lines
12 KiB
TypeScript
322 lines
12 KiB
TypeScript
import { Logger } from '@nestjs/common';
|
|
|
|
import { Command, CommandRunner } from 'nest-commander';
|
|
import { DataSource } from 'typeorm';
|
|
|
|
import { seedCoreSchema } from 'src/database/typeorm-seeds/core';
|
|
import {
|
|
SEED_ACME_WORKSPACE_ID,
|
|
SEED_APPLE_WORKSPACE_ID,
|
|
} from 'src/database/typeorm-seeds/core/workspaces';
|
|
import {
|
|
getDevSeedCompanyCustomFields,
|
|
getDevSeedPeopleCustomFields,
|
|
} from 'src/database/typeorm-seeds/metadata/fieldsMetadata';
|
|
import { seedApiKey } from 'src/database/typeorm-seeds/workspace/api-key';
|
|
import { seedCalendarChannels } from 'src/database/typeorm-seeds/workspace/calendar-channel';
|
|
import { seedCalendarChannelEventAssociations } from 'src/database/typeorm-seeds/workspace/calendar-channel-event-association';
|
|
import { seedCalendarEventParticipants } from 'src/database/typeorm-seeds/workspace/calendar-event-participants';
|
|
import { seedCalendarEvents } from 'src/database/typeorm-seeds/workspace/calendar-events';
|
|
import { seedCompanies } from 'src/database/typeorm-seeds/workspace/companies';
|
|
import { seedConnectedAccount } from 'src/database/typeorm-seeds/workspace/connected-account';
|
|
import { seedWorkspaceFavorites } from 'src/database/typeorm-seeds/workspace/favorites';
|
|
import { seedMessageChannelMessageAssociation } from 'src/database/typeorm-seeds/workspace/message-channel-message-associations';
|
|
import { seedMessageChannel } from 'src/database/typeorm-seeds/workspace/message-channels';
|
|
import { seedMessageParticipant } from 'src/database/typeorm-seeds/workspace/message-participants';
|
|
import { seedMessageThread } from 'src/database/typeorm-seeds/workspace/message-threads';
|
|
import { seedMessage } from 'src/database/typeorm-seeds/workspace/messages';
|
|
import { seedOpportunity } from 'src/database/typeorm-seeds/workspace/opportunities';
|
|
import { seedPeople } from 'src/database/typeorm-seeds/workspace/seedPeople';
|
|
import { seedWorkspaceMember } from 'src/database/typeorm-seeds/workspace/workspace-members';
|
|
import { rawDataSource } from 'src/database/typeorm/raw/raw.datasource';
|
|
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
|
|
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
|
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
|
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
|
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/field-metadata.service';
|
|
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
|
|
import { PETS_DATA_SEEDS } from 'src/engine/seeder/data-seeds/pets-data-seeds';
|
|
import { SURVEY_RESULTS_DATA_SEEDS } from 'src/engine/seeder/data-seeds/survey-results-data-seeds';
|
|
import { PETS_METADATA_SEEDS } from 'src/engine/seeder/metadata-seeds/pets-metadata-seeds';
|
|
import { SURVEY_RESULTS_METADATA_SEEDS } from 'src/engine/seeder/metadata-seeds/survey-results-metadata-seeds';
|
|
import { SeederService } from 'src/engine/seeder/seeder.service';
|
|
import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
|
import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite';
|
|
import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service';
|
|
import { createWorkspaceViews } from 'src/engine/workspace-manager/standard-objects-prefill-data/create-workspace-views';
|
|
import { seedViewWithDemoData } from 'src/engine/workspace-manager/standard-objects-prefill-data/seed-view-with-demo-data';
|
|
import { opportunitiesTableByStageView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-table-by-stage.view';
|
|
import { WorkspaceManagerService } from 'src/engine/workspace-manager/workspace-manager.service';
|
|
import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids';
|
|
// TODO: implement dry-run
|
|
@Command({
|
|
name: 'workspace:seed:dev',
|
|
description:
|
|
'Seed workspace with initial data. This command is intended for development only.',
|
|
})
|
|
export class DataSeedWorkspaceCommand extends CommandRunner {
|
|
workspaceIds = [SEED_APPLE_WORKSPACE_ID, SEED_ACME_WORKSPACE_ID];
|
|
private readonly logger = new Logger(DataSeedWorkspaceCommand.name);
|
|
|
|
constructor(
|
|
private readonly dataSourceService: DataSourceService,
|
|
private readonly typeORMService: TypeORMService,
|
|
private readonly fieldMetadataService: FieldMetadataService,
|
|
private readonly objectMetadataService: ObjectMetadataService,
|
|
private readonly seederService: SeederService,
|
|
private readonly workspaceManagerService: WorkspaceManagerService,
|
|
private readonly twentyConfigService: TwentyConfigService,
|
|
private readonly workspaceCacheStorageService: WorkspaceCacheStorageService,
|
|
) {
|
|
super();
|
|
}
|
|
|
|
async run(): Promise<void> {
|
|
try {
|
|
for (const workspaceId of this.workspaceIds) {
|
|
await this.createWorkspaceSchema(workspaceId);
|
|
}
|
|
} catch (error) {
|
|
this.logger.error(error);
|
|
|
|
return;
|
|
}
|
|
|
|
for (const workspaceId of this.workspaceIds) {
|
|
await this.seedWorkspace(workspaceId);
|
|
}
|
|
}
|
|
|
|
async createWorkspaceSchema(workspaceId: string) {
|
|
const workspaceCachedMetadataVersion =
|
|
await this.workspaceCacheStorageService.getMetadataVersion(workspaceId);
|
|
|
|
await this.workspaceCacheStorageService.flush(
|
|
workspaceId,
|
|
workspaceCachedMetadataVersion,
|
|
);
|
|
|
|
await rawDataSource.initialize();
|
|
|
|
const isBillingEnabled = this.twentyConfigService.get('IS_BILLING_ENABLED');
|
|
const appVersion = this.twentyConfigService.get('APP_VERSION');
|
|
|
|
await seedCoreSchema({
|
|
dataSource: rawDataSource,
|
|
workspaceId,
|
|
seedBilling: isBillingEnabled,
|
|
appVersion,
|
|
});
|
|
|
|
await rawDataSource.destroy();
|
|
|
|
await this.workspaceManagerService.initDev(workspaceId);
|
|
}
|
|
|
|
async seedWorkspace(workspaceId: string) {
|
|
const dataSourceMetadata =
|
|
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
|
|
workspaceId,
|
|
);
|
|
|
|
const mainDataSource = this.typeORMService.getMainDataSource();
|
|
|
|
if (!mainDataSource) {
|
|
throw new Error('Could not connect to workspace data source');
|
|
}
|
|
|
|
try {
|
|
const { objectMetadataStandardIdToIdMap } =
|
|
await this.objectMetadataService.getObjectMetadataStandardIdToIdMap(
|
|
workspaceId,
|
|
);
|
|
|
|
await this.seedCompanyCustomFields(
|
|
objectMetadataStandardIdToIdMap[STANDARD_OBJECT_IDS.company].id,
|
|
workspaceId,
|
|
);
|
|
|
|
await this.seedPeopleCustomFields(
|
|
objectMetadataStandardIdToIdMap[STANDARD_OBJECT_IDS.person].id,
|
|
workspaceId,
|
|
);
|
|
|
|
await this.seedCustomObjects({
|
|
dataSourceMetadata,
|
|
});
|
|
|
|
await this.seedRecords({
|
|
mainDataSource,
|
|
dataSourceMetadata,
|
|
});
|
|
} catch (error) {
|
|
this.logger.error(error);
|
|
}
|
|
}
|
|
|
|
async seedCustomObjects({
|
|
dataSourceMetadata,
|
|
}: {
|
|
dataSourceMetadata: DataSourceEntity;
|
|
}) {
|
|
await this.seederService.seedCustomObjects(
|
|
dataSourceMetadata.id,
|
|
dataSourceMetadata.workspaceId,
|
|
PETS_METADATA_SEEDS,
|
|
);
|
|
|
|
await this.seederService.seedCustomObjects(
|
|
dataSourceMetadata.id,
|
|
dataSourceMetadata.workspaceId,
|
|
SURVEY_RESULTS_METADATA_SEEDS,
|
|
);
|
|
}
|
|
|
|
async seedRecords({
|
|
mainDataSource,
|
|
dataSourceMetadata,
|
|
}: {
|
|
mainDataSource: DataSource;
|
|
dataSourceMetadata: DataSourceEntity;
|
|
}) {
|
|
await this.seedStandardObjectRecords(mainDataSource, dataSourceMetadata);
|
|
|
|
await this.seederService.seedCustomObjectRecords(
|
|
dataSourceMetadata.workspaceId,
|
|
PETS_METADATA_SEEDS,
|
|
PETS_DATA_SEEDS,
|
|
);
|
|
|
|
await this.seederService.seedCustomObjectRecords(
|
|
dataSourceMetadata.workspaceId,
|
|
SURVEY_RESULTS_METADATA_SEEDS,
|
|
SURVEY_RESULTS_DATA_SEEDS,
|
|
);
|
|
}
|
|
|
|
async seedStandardObjectRecords(
|
|
mainDataSource: DataSource,
|
|
dataSourceMetadata: DataSourceEntity,
|
|
) {
|
|
await mainDataSource.transaction(
|
|
async (entityManager: WorkspaceEntityManager) => {
|
|
const { objectMetadataStandardIdToIdMap } =
|
|
await this.objectMetadataService.getObjectMetadataStandardIdToIdMap(
|
|
dataSourceMetadata.workspaceId,
|
|
);
|
|
|
|
await seedCompanies(entityManager, dataSourceMetadata.schema);
|
|
await seedPeople(entityManager, dataSourceMetadata.schema);
|
|
await seedOpportunity(entityManager, dataSourceMetadata.schema);
|
|
await seedWorkspaceMember(
|
|
entityManager,
|
|
dataSourceMetadata.schema,
|
|
dataSourceMetadata.workspaceId,
|
|
);
|
|
|
|
if (dataSourceMetadata.workspaceId === SEED_APPLE_WORKSPACE_ID) {
|
|
await seedApiKey(entityManager, dataSourceMetadata.schema);
|
|
await seedMessageThread(entityManager, dataSourceMetadata.schema);
|
|
await seedConnectedAccount(entityManager, dataSourceMetadata.schema);
|
|
|
|
await seedMessage(entityManager, dataSourceMetadata.schema);
|
|
await seedMessageChannel(entityManager, dataSourceMetadata.schema);
|
|
await seedMessageChannelMessageAssociation(
|
|
entityManager,
|
|
dataSourceMetadata.schema,
|
|
);
|
|
await seedMessageParticipant(
|
|
entityManager,
|
|
dataSourceMetadata.schema,
|
|
);
|
|
|
|
await seedCalendarEvents(entityManager, dataSourceMetadata.schema);
|
|
await seedCalendarChannels(entityManager, dataSourceMetadata.schema);
|
|
await seedCalendarChannelEventAssociations(
|
|
entityManager,
|
|
dataSourceMetadata.schema,
|
|
);
|
|
await seedCalendarEventParticipants(
|
|
entityManager,
|
|
dataSourceMetadata.schema,
|
|
);
|
|
}
|
|
|
|
const viewDefinitionsWithId = await seedViewWithDemoData(
|
|
entityManager,
|
|
dataSourceMetadata.schema,
|
|
objectMetadataStandardIdToIdMap,
|
|
);
|
|
|
|
const devViewDefinitionsWithId = await createWorkspaceViews(
|
|
entityManager,
|
|
dataSourceMetadata.schema,
|
|
[opportunitiesTableByStageView(objectMetadataStandardIdToIdMap)],
|
|
);
|
|
|
|
viewDefinitionsWithId.push(...devViewDefinitionsWithId);
|
|
|
|
await seedWorkspaceFavorites(
|
|
viewDefinitionsWithId
|
|
.filter(
|
|
(view) =>
|
|
view.key === 'INDEX' &&
|
|
shouldSeedWorkspaceFavorite(
|
|
view.objectMetadataId,
|
|
objectMetadataStandardIdToIdMap,
|
|
),
|
|
)
|
|
.map((view) => view.id),
|
|
entityManager,
|
|
dataSourceMetadata.schema,
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
async seedCompanyCustomFields(
|
|
companyObjectMetadataId: string,
|
|
workspaceId: string,
|
|
) {
|
|
if (!companyObjectMetadataId) {
|
|
throw new Error(
|
|
`Company object metadata not found for workspace ${workspaceId}, can't seed custom fields`,
|
|
);
|
|
}
|
|
|
|
const DEV_SEED_COMPANY_CUSTOM_FIELDS = getDevSeedCompanyCustomFields(
|
|
companyObjectMetadataId,
|
|
workspaceId,
|
|
);
|
|
|
|
await this.fieldMetadataService.createMany(
|
|
DEV_SEED_COMPANY_CUSTOM_FIELDS.map((customField) => ({
|
|
...customField,
|
|
isCustom: true,
|
|
})),
|
|
);
|
|
}
|
|
|
|
async seedPeopleCustomFields(
|
|
personObjectMetadataId: string,
|
|
workspaceId: string,
|
|
) {
|
|
if (!personObjectMetadataId) {
|
|
throw new Error(
|
|
`Person object metadata not found for workspace ${workspaceId}, can't seed custom fields`,
|
|
);
|
|
}
|
|
|
|
const DEV_SEED_PERSON_CUSTOM_FIELDS = getDevSeedPeopleCustomFields(
|
|
personObjectMetadataId,
|
|
workspaceId,
|
|
);
|
|
|
|
await this.fieldMetadataService.createMany(
|
|
DEV_SEED_PERSON_CUSTOM_FIELDS.map((customField) => ({
|
|
...customField,
|
|
isCustom: true,
|
|
})),
|
|
);
|
|
}
|
|
}
|