feat: drop calendar repository (#5824)

This PR is replacing and removing all the raw queries and repositories
with the new `TwentyORM` and injection system using
`@InjectWorkspaceRepository`.
Some logic that was contained inside repositories has been moved to the
services.
In this PR we're only replacing repositories for calendar feature.

---------

Co-authored-by: Weiko <corentin@twenty.com>
Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Jérémy M
2024-06-22 09:26:58 +02:00
committed by GitHub
parent 91b0c2bb8e
commit 0b4bfce324
90 changed files with 979 additions and 1541 deletions

View File

@ -28,6 +28,8 @@ import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/s
import { CalendarChannelWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-channel.workspace-entity';
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module';
import { TwentyORMModule } from 'src/engine/twenty-orm/twenty-orm.module';
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { AuthResolver } from './auth.resolver';
@ -60,11 +62,12 @@ const jwtModule = JwtModule.registerAsync({
ObjectMetadataRepositoryModule.forFeature([
ConnectedAccountWorkspaceEntity,
MessageChannelWorkspaceEntity,
CalendarChannelWorkspaceEntity,
]),
HttpModule,
UserWorkspaceModule,
OnboardingModule,
TwentyORMModule.forFeature([CalendarChannelWorkspaceEntity]),
WorkspaceDataSourceModule,
],
controllers: [
GoogleAuthController,

View File

@ -138,6 +138,7 @@ export class AuthResolver {
}
const transientToken = await this.tokenService.generateTransientToken(
workspaceMember.id,
user.id,
user.defaultWorkspace.id,
);

View File

@ -16,9 +16,7 @@ import { GoogleAPIsService } from 'src/engine/core-modules/auth/services/google-
import { TokenService } from 'src/engine/core-modules/auth/services/token.service';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
import { WorkspaceMemberRepository } from 'src/modules/workspace-member/repositories/workspace-member.repository';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import { LoadServiceWithWorkspaceContext } from 'src/engine/twenty-orm/context/load-service-with-workspace.context';
@Controller('auth/google-apis')
export class GoogleAPIsAuthController {
@ -27,8 +25,7 @@ export class GoogleAPIsAuthController {
private readonly tokenService: TokenService,
private readonly environmentService: EnvironmentService,
private readonly onboardingService: OnboardingService,
@InjectObjectMetadataRepository(WorkspaceMemberWorkspaceEntity)
private readonly workspaceMemberService: WorkspaceMemberRepository,
private readonly loadServiceWithWorkspaceContext: LoadServiceWithWorkspaceContext,
) {}
@Get()
@ -56,7 +53,7 @@ export class GoogleAPIsAuthController {
messageVisibility,
} = user;
const { workspaceMemberId, workspaceId } =
const { workspaceMemberId, userId, workspaceId } =
await this.tokenService.verifyTransientToken(transientToken);
const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');
@ -71,7 +68,13 @@ export class GoogleAPIsAuthController {
throw new Error('Workspace not found');
}
await this.googleAPIsService.refreshGoogleRefreshToken({
const googleAPIsServiceInstance =
await this.loadServiceWithWorkspaceContext.load(
this.googleAPIsService,
workspaceId,
);
await googleAPIsServiceInstance.refreshGoogleRefreshToken({
handle: email,
workspaceMemberId: workspaceMemberId,
workspaceId: workspaceId,
@ -81,12 +84,14 @@ export class GoogleAPIsAuthController {
messageVisibility,
});
const userId = (
await this.workspaceMemberService.find(workspaceMemberId, workspaceId)
)?.userId;
if (userId) {
await this.onboardingService.skipSyncEmailOnboardingStep(
const onboardingServiceInstance =
await this.loadServiceWithWorkspaceContext.load(
this.onboardingService,
workspaceId,
);
await onboardingServiceInstance.skipSyncEmailOnboardingStep(
userId,
workspaceId,
);

View File

@ -3,17 +3,14 @@ import { Injectable } from '@nestjs/common';
import { EntityManager } from 'typeorm';
import { v4 } from 'uuid';
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { MessageQueue } from 'src/engine/integrations/message-queue/message-queue.constants';
import { MessageQueueService } from 'src/engine/integrations/message-queue/services/message-queue.service';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator';
import {
GoogleCalendarSyncJobData,
GoogleCalendarSyncJob,
} from 'src/modules/calendar/jobs/google-calendar-sync.job';
import { CalendarChannelRepository } from 'src/modules/calendar/repositories/calendar-channel.repository';
import {
CalendarChannelWorkspaceEntity,
CalendarChannelVisibility,
@ -35,12 +32,16 @@ import {
MessagingMessageListFetchJobData,
} from 'src/modules/messaging/message-import-manager/jobs/messaging-message-list-fetch.job';
import { InjectMessageQueue } from 'src/engine/integrations/message-queue/decorators/message-queue.decorator';
import { InjectWorkspaceRepository } from 'src/engine/twenty-orm/decorators/inject-workspace-repository.decorator';
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
import { InjectWorkspaceDatasource } from 'src/engine/twenty-orm/decorators/inject-workspace-datasource.decorator';
@Injectable()
export class GoogleAPIsService {
constructor(
private readonly dataSourceService: DataSourceService,
private readonly typeORMService: TypeORMService,
@InjectWorkspaceDatasource()
private readonly workspaceDataSource: WorkspaceDataSource,
@InjectMessageQueue(MessageQueue.messagingQueue)
private readonly messageQueueService: MessageQueueService,
@InjectMessageQueue(MessageQueue.calendarQueue)
@ -50,8 +51,8 @@ export class GoogleAPIsService {
private readonly connectedAccountRepository: ConnectedAccountRepository,
@InjectObjectMetadataRepository(MessageChannelWorkspaceEntity)
private readonly messageChannelRepository: MessageChannelRepository,
@InjectObjectMetadataRepository(CalendarChannelWorkspaceEntity)
private readonly calendarChannelRepository: CalendarChannelRepository,
@InjectWorkspaceRepository(CalendarChannelWorkspaceEntity)
private readonly calendarChannelRepository: WorkspaceRepository<CalendarChannelWorkspaceEntity>,
) {}
async refreshGoogleRefreshToken(input: {
@ -71,14 +72,6 @@ export class GoogleAPIsService {
messageVisibility,
} = input;
const dataSourceMetadata =
await this.dataSourceService.getLastDataSourceMetadataFromWorkspaceIdOrFail(
workspaceId,
);
const workspaceDataSource =
await this.typeORMService.connectToDataSource(dataSourceMetadata);
const isCalendarEnabled = this.environmentService.get(
'CALENDAR_PROVIDER_GOOGLE_ENABLED',
);
@ -93,65 +86,67 @@ export class GoogleAPIsService {
const existingAccountId = connectedAccounts?.[0]?.id;
const newOrExistingConnectedAccountId = existingAccountId ?? v4();
await workspaceDataSource?.transaction(async (manager: EntityManager) => {
if (!existingAccountId) {
await this.connectedAccountRepository.create(
{
id: newOrExistingConnectedAccountId,
handle,
provider: ConnectedAccountProvider.GOOGLE,
accessToken: input.accessToken,
refreshToken: input.refreshToken,
accountOwnerId: workspaceMemberId,
},
workspaceId,
manager,
);
await this.messageChannelRepository.create(
{
id: v4(),
connectedAccountId: newOrExistingConnectedAccountId,
type: MessageChannelType.EMAIL,
handle,
visibility:
messageVisibility || MessageChannelVisibility.SHARE_EVERYTHING,
syncStatus: MessageChannelSyncStatus.ONGOING,
},
workspaceId,
manager,
);
if (isCalendarEnabled) {
await this.calendarChannelRepository.create(
await this.workspaceDataSource.transaction(
async (manager: EntityManager) => {
if (!existingAccountId) {
await this.connectedAccountRepository.create(
{
id: v4(),
connectedAccountId: newOrExistingConnectedAccountId,
id: newOrExistingConnectedAccountId,
handle,
visibility:
calendarVisibility ||
CalendarChannelVisibility.SHARE_EVERYTHING,
provider: ConnectedAccountProvider.GOOGLE,
accessToken: input.accessToken,
refreshToken: input.refreshToken,
accountOwnerId: workspaceMemberId,
},
workspaceId,
manager,
);
}
} else {
await this.connectedAccountRepository.updateAccessTokenAndRefreshToken(
input.accessToken,
input.refreshToken,
newOrExistingConnectedAccountId,
workspaceId,
manager,
);
await this.messageChannelRepository.resetSync(
newOrExistingConnectedAccountId,
workspaceId,
manager,
);
}
});
await this.messageChannelRepository.create(
{
id: v4(),
connectedAccountId: newOrExistingConnectedAccountId,
type: MessageChannelType.EMAIL,
handle,
visibility:
messageVisibility || MessageChannelVisibility.SHARE_EVERYTHING,
syncStatus: MessageChannelSyncStatus.ONGOING,
},
workspaceId,
manager,
);
if (isCalendarEnabled) {
await this.calendarChannelRepository.save(
{
id: v4(),
connectedAccountId: newOrExistingConnectedAccountId,
handle,
visibility:
calendarVisibility ||
CalendarChannelVisibility.SHARE_EVERYTHING,
},
{},
manager,
);
}
} else {
await this.connectedAccountRepository.updateAccessTokenAndRefreshToken(
input.accessToken,
input.refreshToken,
newOrExistingConnectedAccountId,
workspaceId,
manager,
);
await this.messageChannelRepository.resetSync(
newOrExistingConnectedAccountId,
workspaceId,
manager,
);
}
},
);
if (this.environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED')) {
const messageChannels =

View File

@ -147,6 +147,7 @@ export class TokenService {
async generateTransientToken(
workspaceMemberId: string,
userId: string,
workspaceId: string,
): Promise<AuthToken> {
const secret = this.environmentService.get('LOGIN_TOKEN_SECRET');
@ -158,6 +159,7 @@ export class TokenService {
const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn));
const jwtPayload = {
sub: workspaceMemberId,
userId,
workspaceId,
};
@ -234,6 +236,7 @@ export class TokenService {
async verifyTransientToken(transientToken: string): Promise<{
workspaceMemberId: string;
userId: string;
workspaceId: string;
}> {
const transientTokenSecret =
@ -243,6 +246,7 @@ export class TokenService {
return {
workspaceMemberId: payload.sub,
userId: payload.userId,
workspaceId: payload.workspaceId,
};
}