import { Injectable, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { 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 { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; import { RoleService } from 'src/engine/metadata-modules/role/role.service'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; import { MEMBER_ROLE_LABEL } from 'src/engine/metadata-modules/permissions/constants/member-role-label.constants'; import { InjectWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/inject-workspace-scoped-repository.decorator'; import { WorkspaceScopedRepository } from 'src/engine/twenty-orm/workspace-scoped-repository/workspace-scoped-repository'; import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service'; import { STANDARD_ROLE } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-role.constant'; import { TwentyStandardApplicationService } from 'src/engine/workspace-manager/twenty-standard-application/services/twenty-standard-application.service'; @Injectable() export class WorkspaceManagerService { private readonly logger = new Logger(WorkspaceManagerService.name); constructor( private readonly workspaceDataSourceService: WorkspaceDataSourceService, @InjectRepository(UserWorkspaceEntity) private readonly userWorkspaceRepository: Repository, private readonly roleService: RoleService, private readonly userRoleService: UserRoleService, private readonly twentyStandardApplicationService: TwentyStandardApplicationService, @InjectRepository(WorkspaceEntity) private readonly workspaceRepository: Repository, @InjectWorkspaceScopedRepository(RoleEntity) private readonly roleRepository: WorkspaceScopedRepository, private readonly applicationService: ApplicationService, ) {} public async init({ workspace, userId, }: { workspace: WorkspaceEntity; userId: string; }): Promise { const workspaceId = workspace.id; const schemaCreationStart = performance.now(); const schemaName = await this.workspaceDataSourceService.createWorkspaceDBSchema( workspaceId, ); const schemaCreationEnd = performance.now(); this.logger.log( `Schema creation took ${schemaCreationEnd - schemaCreationStart}ms`, ); const dataSourceMetadataCreationStart = performance.now(); await this.workspaceRepository.update(workspaceId, { databaseSchema: schemaName, }); await this.applicationService.createTwentyStandardApplication({ workspaceId, }); await this.twentyStandardApplicationService.synchronizeTwentyStandardApplicationOrThrow( { workspaceId, }, ); const dataSourceMetadataCreationEnd = performance.now(); this.logger.log( `Metadata creation took ${dataSourceMetadataCreationEnd - dataSourceMetadataCreationStart}ms`, ); const { workspaceCustomFlatApplication } = await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( { workspaceId, }, ); await this.setupDefaultRoles({ workspaceId, userId, workspaceCustomFlatApplication, }); } private async setupDefaultRoles({ userId, workspaceId, workspaceCustomFlatApplication, }: { workspaceId: string; userId: string; workspaceCustomFlatApplication: FlatApplication; }): Promise { const adminRole = await this.roleRepository.findOne(workspaceId, { where: { universalIdentifier: STANDARD_ROLE.admin.universalIdentifier, }, }); if (adminRole) { const userWorkspace = await this.userWorkspaceRepository.findOneOrFail({ where: { workspaceId, userId }, }); await this.userRoleService.assignRoleToManyUserWorkspace({ workspaceId, userWorkspaceIds: [userWorkspace.id], roleId: adminRole.id, }); } const existingMemberRole = await this.roleRepository.findOne(workspaceId, { where: { label: MEMBER_ROLE_LABEL }, }); const memberRole = existingMemberRole ?? (await this.roleService.createMemberRole({ workspaceId, ownerFlatApplication: workspaceCustomFlatApplication, })); await this.workspaceRepository.update(workspaceId, { defaultRoleId: memberRole.id, }); } }