diff --git a/backend/src/entities/connection/connection.controller.ts b/backend/src/entities/connection/connection.controller.ts index 4949d6e26..3e2aaccc4 100644 --- a/backend/src/entities/connection/connection.controller.ts +++ b/backend/src/entities/connection/connection.controller.ts @@ -431,7 +431,7 @@ export class ConnectionController { cognitoUserName: userId, }, }; - return await this.createGroupInConnectionUseCase.execute(inputData, InTransactionEnum.ON); + return await this.createGroupInConnectionUseCase.execute(inputData, InTransactionEnum.OFF); } @ApiOperation({ summary: 'Find all groups in connection' }) diff --git a/backend/src/entities/connection/use-cases/create-connection.use.case.ts b/backend/src/entities/connection/use-cases/create-connection.use.case.ts index 1cbe4d1b3..1439aac60 100644 --- a/backend/src/entities/connection/use-cases/create-connection.use.case.ts +++ b/backend/src/entities/connection/use-cases/create-connection.use.case.ts @@ -1,31 +1,23 @@ -import { - BadRequestException, - Inject, - Injectable, - InternalServerErrorException, - Scope, -} from "@nestjs/common"; -import { getDataAccessObject } from "@rocketadmin/shared-code/dist/src/data-access-layer/shared/create-data-access-object.js"; -import AbstractUseCase from "../../../common/abstract-use.case.js"; -import { IGlobalDatabaseContext } from "../../../common/application/global-database-context.interface.js"; -import { BaseType } from "../../../common/data-injection.tokens.js"; -import { Messages } from "../../../exceptions/text/messages.js"; -import { Encryptor } from "../../../helpers/encryption/encryptor.js"; -import { - isConnectionTypeAgent, - slackPostMessage, -} from "../../../helpers/index.js"; -import { SharedJobsService } from "../../shared-jobs/shared-jobs.service.js"; -import { UserRoleEnum } from "../../user/enums/user-role.enum.js"; -import { UserEntity } from "../../user/user.entity.js"; -import { CreateConnectionDs } from "../application/data-structures/create-connection.ds.js"; -import { CreatedConnectionDTO } from "../application/dto/created-connection.dto.js"; -import { ConnectionEntity } from "../connection.entity.js"; -import { buildConnectionEntity } from "../utils/build-connection-entity.js"; -import { buildCreatedConnectionDs } from "../utils/build-created-connection.ds.js"; -import { processAWSConnection } from "../utils/process-aws-connection.util.js"; -import { validateCreateConnectionData } from "../utils/validate-create-connection-data.js"; -import { ICreateConnection } from "./use-cases.interfaces.js"; +import { BadRequestException, Inject, Injectable, InternalServerErrorException, Scope } from '@nestjs/common'; +import { getDataAccessObject } from '@rocketadmin/shared-code/dist/src/data-access-layer/shared/create-data-access-object.js'; +import * as Sentry from '@sentry/node'; +import AbstractUseCase from '../../../common/abstract-use.case.js'; +import { IGlobalDatabaseContext } from '../../../common/application/global-database-context.interface.js'; +import { BaseType } from '../../../common/data-injection.tokens.js'; +import { Messages } from '../../../exceptions/text/messages.js'; +import { Encryptor } from '../../../helpers/encryption/encryptor.js'; +import { isConnectionTypeAgent, slackPostMessage } from '../../../helpers/index.js'; +import { SharedJobsService } from '../../shared-jobs/shared-jobs.service.js'; +import { UserRoleEnum } from '../../user/enums/user-role.enum.js'; +import { UserEntity } from '../../user/user.entity.js'; +import { CreateConnectionDs } from '../application/data-structures/create-connection.ds.js'; +import { CreatedConnectionDTO } from '../application/dto/created-connection.dto.js'; +import { ConnectionEntity } from '../connection.entity.js'; +import { buildConnectionEntity } from '../utils/build-connection-entity.js'; +import { buildCreatedConnectionDs } from '../utils/build-created-connection.ds.js'; +import { processAWSConnection } from '../utils/process-aws-connection.util.js'; +import { validateCreateConnectionData } from '../utils/validate-create-connection-data.js'; +import { ICreateConnection } from './use-cases.interfaces.js'; @Injectable({ scope: Scope.REQUEST }) export class CreateConnectionUseCase @@ -39,41 +31,28 @@ export class CreateConnectionUseCase ) { super(); } - protected async implementation( - createConnectionData: CreateConnectionDs, - ): Promise { + protected async implementation(createConnectionData: CreateConnectionDs): Promise { const { creation_info: { authorId, masterPwd }, } = createConnectionData; - const connectionAuthor: UserEntity = - await this._dbContext.userRepository.findOneUserById(authorId); + const connectionAuthor: UserEntity = await this._dbContext.userRepository.findOneUserById(authorId); if (!connectionAuthor) { throw new InternalServerErrorException(Messages.USER_NOT_FOUND); } - if ( - connectionAuthor.role !== UserRoleEnum.ADMIN && - connectionAuthor.role !== UserRoleEnum.DB_ADMIN - ) { - throw new BadRequestException( - Messages.CANT_CREATE_CONNECTION_USER_NON_COMPANY_ADMIN, - ); + if (connectionAuthor.role !== UserRoleEnum.ADMIN && connectionAuthor.role !== UserRoleEnum.DB_ADMIN) { + throw new BadRequestException(Messages.CANT_CREATE_CONNECTION_USER_NON_COMPANY_ADMIN); } await slackPostMessage( - Messages.USER_TRY_CREATE_CONNECTION( - connectionAuthor.email, - createConnectionData.connection_parameters.type, - ), + Messages.USER_TRY_CREATE_CONNECTION(connectionAuthor.email, createConnectionData.connection_parameters.type), ); await validateCreateConnectionData(createConnectionData); createConnectionData = await processAWSConnection(createConnectionData); let isConnectionTestedSuccessfully: boolean = false; - if ( - !isConnectionTypeAgent(createConnectionData.connection_parameters.type) - ) { + if (!isConnectionTypeAgent(createConnectionData.connection_parameters.type)) { const connectionParamsCopy = { ...createConnectionData.connection_parameters, }; @@ -84,10 +63,7 @@ export class CreateConnectionUseCase } catch (e) { const text: string = e.message.toLowerCase(); isConnectionTestedSuccessfully = false; - if ( - text.includes("ssl required") || - text.includes("ssl connection required") - ) { + if (text.includes('ssl required') || text.includes('ssl connection required')) { createConnectionData.connection_parameters.ssl = true; connectionParamsCopy.ssl = true; try { @@ -104,79 +80,49 @@ export class CreateConnectionUseCase } let connectionCopy: ConnectionEntity = null; try { - const createdConnection: ConnectionEntity = await buildConnectionEntity( - createConnectionData, - connectionAuthor, - ); + const createdConnection: ConnectionEntity = await buildConnectionEntity(createConnectionData, connectionAuthor); const savedConnection: ConnectionEntity = - await this._dbContext.connectionRepository.saveNewConnection( - createdConnection, - ); + await this._dbContext.connectionRepository.saveNewConnection(createdConnection); connectionCopy = { ...savedConnection } as ConnectionEntity; - if ( - savedConnection.masterEncryption && - masterPwd && - !isConnectionTypeAgent(savedConnection.type) - ) { - connectionCopy = Encryptor.decryptConnectionCredentials( - connectionCopy, - masterPwd, - ); + if (savedConnection.masterEncryption && masterPwd && !isConnectionTypeAgent(savedConnection.type)) { + connectionCopy = Encryptor.decryptConnectionCredentials(connectionCopy, masterPwd); } let token: string; if (isConnectionTypeAgent(savedConnection.type)) { - token = - await this._dbContext.agentRepository.createNewAgentForConnectionAndReturnToken( - savedConnection, - ); + token = await this._dbContext.agentRepository.createNewAgentForConnectionAndReturnToken(savedConnection); } - const createdAdminGroup = - await this._dbContext.groupRepository.createdAdminGroupInConnection( - savedConnection, - connectionAuthor, - ); - await this._dbContext.permissionRepository.createdDefaultAdminPermissionsInGroup( - createdAdminGroup, + const createdAdminGroup = await this._dbContext.groupRepository.createdAdminGroupInConnection( + savedConnection, + connectionAuthor, ); + await this._dbContext.permissionRepository.createdDefaultAdminPermissionsInGroup(createdAdminGroup); delete createdAdminGroup.connection; await this._dbContext.userRepository.saveUserEntity(connectionAuthor); createdConnection.groups = [createdAdminGroup]; - const foundUserCompany = - await this._dbContext.companyInfoRepository.findOneCompanyInfoByUserIdWithConnections( - connectionAuthor.id, - ); + const foundUserCompany = await this._dbContext.companyInfoRepository.findOneCompanyInfoByUserIdWithConnections( + connectionAuthor.id, + ); if (foundUserCompany) { const connection = await this._dbContext.connectionRepository.findOne({ where: { id: savedConnection.id }, }); connection.company = foundUserCompany; - await this._dbContext.connectionRepository.saveUpdatedConnection( - connection, - ); + await this._dbContext.connectionRepository.saveUpdatedConnection(connection); } await slackPostMessage( - Messages.USER_CREATED_CONNECTION( - connectionAuthor.email, - createConnectionData.connection_parameters.type, - ), - ); - const connectionRO = buildCreatedConnectionDs( - savedConnection, - token, - masterPwd, + Messages.USER_CREATED_CONNECTION(connectionAuthor.email, createConnectionData.connection_parameters.type), ); + const connectionRO = buildCreatedConnectionDs(savedConnection, token, masterPwd); return connectionRO; } finally { - if ( - isConnectionTestedSuccessfully && - !isConnectionTypeAgent(connectionCopy.type) - ) { - // await this.sharedJobsService.scanDatabaseAndCreateWidgets(connectionCopy); - await this.sharedJobsService.scanDatabaseAndCreateSettingsAndWidgetsWithAI( - connectionCopy, - ); + if (isConnectionTestedSuccessfully && !isConnectionTypeAgent(connectionCopy.type)) { + // Fire-and-forget: run AI scan in background without blocking response + this.sharedJobsService.scanDatabaseAndCreateSettingsAndWidgetsWithAI(connectionCopy).catch((error) => { + console.error('Background AI scan failed:', error); + Sentry.captureException(error); + }); } } }