6694 remove raw queries from connected account (#7101)

Closes #6694

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Raphaël Bosi
2024-10-08 13:31:44 +02:00
committed by GitHub
parent 4156d7821c
commit 33d5a57ea2
19 changed files with 95 additions and 403 deletions

View File

@ -1,18 +1,11 @@
import { Module } from '@nestjs/common';
import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module';
import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service';
import { EmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/services/email-alias-manager.service';
import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
@Module({
imports: [
ObjectMetadataRepositoryModule.forFeature([
ConnectedAccountWorkspaceEntity,
]),
OAuth2ClientManagerModule,
],
imports: [OAuth2ClientManagerModule],
providers: [EmailAliasManagerService, GoogleEmailAliasManagerService],
exports: [EmailAliasManagerService],
})

View File

@ -1,21 +1,18 @@
import { Injectable } from '@nestjs/common';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/google-email-alias-manager.service';
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
@Injectable()
export class EmailAliasManagerService {
constructor(
@InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity)
private readonly connectedAccountRepository: ConnectedAccountRepository,
private readonly googleEmailAliasManagerService: GoogleEmailAliasManagerService,
private readonly twentyORMManager: TwentyORMManager,
) {}
public async refreshHandleAliases(
connectedAccount: ConnectedAccountWorkspaceEntity,
workspaceId: string,
) {
let handleAliases: string[];
@ -32,10 +29,16 @@ export class EmailAliasManagerService {
);
}
await this.connectedAccountRepository.updateHandleAliases(
handleAliases,
connectedAccount.id,
workspaceId,
const connectedAccountRepository =
await this.twentyORMManager.getRepository<ConnectedAccountWorkspaceEntity>(
'connectedAccount',
);
await connectedAccountRepository.update(
{ id: connectedAccount.id },
{
handleAliases: handleAliases.join(','), // TODO: modify handleAliases to be of fieldmetadatatype array
},
);
}
}

View File

@ -1,17 +1,10 @@
import { Module } from '@nestjs/common';
import { ObjectMetadataRepositoryModule } from 'src/engine/object-metadata-repository/object-metadata-repository.module';
import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/refresh-access-token-manager/drivers/google/services/google-api-refresh-access-token.service';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
@Module({
imports: [
ObjectMetadataRepositoryModule.forFeature([
ConnectedAccountWorkspaceEntity,
]),
MessagingCommonModule,
],
imports: [MessagingCommonModule],
providers: [GoogleAPIRefreshAccessTokenService],
exports: [GoogleAPIRefreshAccessTokenService],
})

View File

@ -1,20 +1,18 @@
import { Injectable } from '@nestjs/common';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/refresh-access-token-manager/drivers/google/services/google-api-refresh-access-token.service';
import {
RefreshAccessTokenException,
RefreshAccessTokenExceptionCode,
} from 'src/modules/connected-account/refresh-access-token-manager/exceptions/refresh-access-token.exception';
import { ConnectedAccountRepository } from 'src/modules/connected-account/repositories/connected-account.repository';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
@Injectable()
export class RefreshAccessTokenService {
constructor(
private readonly googleAPIRefreshAccessTokenService: GoogleAPIRefreshAccessTokenService,
@InjectObjectMetadataRepository(ConnectedAccountWorkspaceEntity)
private readonly connectedAccountRepository: ConnectedAccountRepository,
private readonly twentyORMManager: TwentyORMManager,
) {}
async refreshAndSaveAccessToken(
@ -44,10 +42,16 @@ export class RefreshAccessTokenService {
);
}
await this.connectedAccountRepository.updateAccessToken(
accessToken,
connectedAccount.id,
workspaceId,
const connectedAccountRepository =
await this.twentyORMManager.getRepository<ConnectedAccountWorkspaceEntity>(
'connectedAccount',
);
await connectedAccountRepository.update(
{ id: connectedAccount.id },
{
accessToken,
},
);
return accessToken;

View File

@ -1,240 +0,0 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { EntityManager } from 'typeorm';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
@Injectable()
export class ConnectedAccountRepository {
constructor(
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
) {}
public async getAll(
workspaceId: string,
transactionManager?: EntityManager,
): Promise<ConnectedAccountWorkspaceEntity[]> {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
return await this.workspaceDataSourceService.executeRawQuery(
`SELECT * FROM ${dataSourceSchema}."connectedAccount" WHERE "provider" = 'google'`,
[],
workspaceId,
transactionManager,
);
}
public async getByIds(
connectedAccountIds: string[],
workspaceId: string,
transactionManager?: EntityManager,
): Promise<ConnectedAccountWorkspaceEntity[]> {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
return await this.workspaceDataSourceService.executeRawQuery(
`SELECT * FROM ${dataSourceSchema}."connectedAccount" WHERE "id" = ANY($1)`,
[connectedAccountIds],
workspaceId,
transactionManager,
);
}
public async getAllByWorkspaceMemberId(
workspaceMemberId: string,
workspaceId: string,
transactionManager?: EntityManager,
): Promise<ConnectedAccountWorkspaceEntity[] | undefined> {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
const connectedAccounts =
await this.workspaceDataSourceService.executeRawQuery(
`SELECT * FROM ${dataSourceSchema}."connectedAccount" WHERE "accountOwnerId" = $1`,
[workspaceMemberId],
workspaceId,
transactionManager,
);
return connectedAccounts;
}
public async getAllByHandleAndWorkspaceMemberId(
handle: string,
workspaceMemberId: string,
workspaceId: string,
transactionManager?: EntityManager,
): Promise<ConnectedAccountWorkspaceEntity[] | undefined> {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
const connectedAccounts =
await this.workspaceDataSourceService.executeRawQuery(
`SELECT * FROM ${dataSourceSchema}."connectedAccount" WHERE "handle" = $1 AND "accountOwnerId" = $2 LIMIT 1`,
[handle, workspaceMemberId],
workspaceId,
transactionManager,
);
return connectedAccounts;
}
public async create(
connectedAccount: Pick<
ConnectedAccountWorkspaceEntity,
| 'id'
| 'handle'
| 'provider'
| 'accessToken'
| 'refreshToken'
| 'accountOwnerId'
>,
workspaceId: string,
transactionManager?: EntityManager,
): Promise<ConnectedAccountWorkspaceEntity> {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
return await this.workspaceDataSourceService.executeRawQuery(
`INSERT INTO ${dataSourceSchema}."connectedAccount" ("id", "handle", "provider", "accessToken", "refreshToken", "accountOwnerId") VALUES ($1, $2, $3, $4, $5, $6)`,
[
connectedAccount.id,
connectedAccount.handle,
connectedAccount.provider,
connectedAccount.accessToken,
connectedAccount.refreshToken,
connectedAccount.accountOwnerId,
],
workspaceId,
transactionManager,
);
}
public async updateAccessTokenAndRefreshToken(
accessToken: string,
refreshToken: string,
connectedAccountId: string,
workspaceId: string,
transactionManager?: EntityManager,
) {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
await this.workspaceDataSourceService.executeRawQuery(
`UPDATE ${dataSourceSchema}."connectedAccount" SET "accessToken" = $1, "refreshToken" = $2, "authFailedAt" = NULL WHERE "id" = $3`,
[accessToken, refreshToken, connectedAccountId],
workspaceId,
transactionManager,
);
}
public async getById(
connectedAccountId: string,
workspaceId: string,
transactionManager?: EntityManager,
): Promise<ConnectedAccountWorkspaceEntity | undefined> {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
const connectedAccounts =
await this.workspaceDataSourceService.executeRawQuery(
`SELECT * FROM ${dataSourceSchema}."connectedAccount" WHERE "id" = $1 LIMIT 1`,
[connectedAccountId],
workspaceId,
transactionManager,
);
return connectedAccounts[0];
}
public async getByIdOrFail(
connectedAccountId: string,
workspaceId: string,
transactionManager?: EntityManager,
): Promise<ConnectedAccountWorkspaceEntity> {
const connectedAccount = await this.getById(
connectedAccountId,
workspaceId,
transactionManager,
);
if (!connectedAccount) {
throw new NotFoundException(
`Connected account with id ${connectedAccountId} not found in workspace ${workspaceId}`,
);
}
return connectedAccount;
}
public async updateAccessToken(
accessToken: string,
connectedAccountId: string,
workspaceId: string,
transactionManager?: EntityManager,
) {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
await this.workspaceDataSourceService.executeRawQuery(
`UPDATE ${dataSourceSchema}."connectedAccount" SET "accessToken" = $1, "authFailedAt" = NULL WHERE "id" = $2`,
[accessToken, connectedAccountId],
workspaceId,
transactionManager,
);
}
public async updateAuthFailedAt(
connectedAccountId: string,
workspaceId: string,
transactionManager?: EntityManager,
) {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
await this.workspaceDataSourceService.executeRawQuery(
`UPDATE ${dataSourceSchema}."connectedAccount" SET "authFailedAt" = NOW() WHERE "id" = $1`,
[connectedAccountId],
workspaceId,
transactionManager,
);
}
public async getConnectedAccountOrThrow(
workspaceId: string,
connectedAccountId: string,
): Promise<ConnectedAccountWorkspaceEntity> {
const connectedAccount = await this.getById(
connectedAccountId,
workspaceId,
);
if (!connectedAccount) {
throw new Error(
`Connected account ${connectedAccountId} not found in workspace ${workspaceId}`,
);
}
return connectedAccount;
}
public async updateHandleAliases(
handleAliases: string[],
connectedAccountId: string,
workspaceId: string,
transactionManager?: EntityManager,
) {
const dataSourceSchema =
this.workspaceDataSourceService.getSchemaName(workspaceId);
await this.workspaceDataSourceService.executeRawQuery(
`UPDATE ${dataSourceSchema}."connectedAccount" SET "handleAliases" = $1 WHERE "id" = $2`,
// TODO: modify handleAliases to be of fieldmetadatatype array
[handleAliases.join(','), connectedAccountId],
workspaceId,
transactionManager,
);
}
}