microsoft sync failed (#10381)
This PR is supposed to solve an issue with the syncrhonisation of messages, specifically with microsoft driver. Microsoft calls don't need access_Token so refreshing toekns was not implemented. However, microsoft rely on its client which calls its refresfh_token, and I might have missed some underlying dependency from microsoft impelemtation so I setup the access token process to refresh it Needs a talk before to be merged Fix : https://github.com/twentyhq/twenty/issues/10367 EDIT: it was a problem with microsoft making refreshtoken expire (contrarily to google) which needs to be handled.
This commit is contained in:
@ -30,7 +30,7 @@ import { CalendarEventParticipantManagerModule } from 'src/modules/calendar/cale
|
|||||||
import { CalendarCommonModule } from 'src/modules/calendar/common/calendar-common.module';
|
import { CalendarCommonModule } from 'src/modules/calendar/common/calendar-common.module';
|
||||||
import { CalendarChannelSyncStatusService } from 'src/modules/calendar/common/services/calendar-channel-sync-status.service';
|
import { CalendarChannelSyncStatusService } from 'src/modules/calendar/common/services/calendar-channel-sync-status.service';
|
||||||
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
|
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
|
||||||
import { RefreshAccessTokenManagerModule } from 'src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module';
|
import { RefreshTokensManagerModule } from 'src/modules/connected-account/refresh-tokens-manager/connected-account-refresh-tokens-manager.module';
|
||||||
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@ -47,7 +47,7 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta
|
|||||||
GoogleCalendarDriverModule,
|
GoogleCalendarDriverModule,
|
||||||
MicrosoftCalendarDriverModule,
|
MicrosoftCalendarDriverModule,
|
||||||
BillingModule,
|
BillingModule,
|
||||||
RefreshAccessTokenManagerModule,
|
RefreshTokensManagerModule,
|
||||||
ConnectedAccountModule,
|
ConnectedAccountModule,
|
||||||
CalendarCommonModule,
|
CalendarCommonModule,
|
||||||
HealthModule,
|
HealthModule,
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
import { Module } from '@nestjs/common';
|
|
||||||
|
|
||||||
import { GoogleAPIRefreshAccessTokenModule } from 'src/modules/connected-account/refresh-access-token-manager/drivers/google/google-api-refresh-access-token.module';
|
|
||||||
import { RefreshAccessTokenService } from 'src/modules/connected-account/refresh-access-token-manager/services/refresh-access-token.service';
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [GoogleAPIRefreshAccessTokenModule],
|
|
||||||
providers: [RefreshAccessTokenService],
|
|
||||||
exports: [RefreshAccessTokenService],
|
|
||||||
})
|
|
||||||
export class RefreshAccessTokenManagerModule {}
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
|
|
||||||
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 { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RefreshAccessTokenService {
|
|
||||||
constructor(
|
|
||||||
private readonly googleAPIRefreshAccessTokenService: GoogleAPIRefreshAccessTokenService,
|
|
||||||
private readonly twentyORMManager: TwentyORMManager,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
async refreshAndSaveAccessToken(
|
|
||||||
connectedAccount: ConnectedAccountWorkspaceEntity,
|
|
||||||
workspaceId: string,
|
|
||||||
): Promise<string> {
|
|
||||||
const refreshToken = connectedAccount.refreshToken;
|
|
||||||
let accessToken: string;
|
|
||||||
|
|
||||||
if (!refreshToken) {
|
|
||||||
throw new RefreshAccessTokenException(
|
|
||||||
`No refresh token found for connected account ${connectedAccount.id} in workspace ${workspaceId}`,
|
|
||||||
RefreshAccessTokenExceptionCode.REFRESH_TOKEN_NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (connectedAccount.provider) {
|
|
||||||
case 'microsoft':
|
|
||||||
return '';
|
|
||||||
case 'google': {
|
|
||||||
try {
|
|
||||||
accessToken = await this.refreshAccessToken(
|
|
||||||
connectedAccount,
|
|
||||||
refreshToken,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
throw new RefreshAccessTokenException(
|
|
||||||
`Error refreshing access token for connected account ${connectedAccount.id} in workspace ${workspaceId}: ${error.message}`,
|
|
||||||
RefreshAccessTokenExceptionCode.REFRESH_ACCESS_TOKEN_FAILED,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const connectedAccountRepository =
|
|
||||||
await this.twentyORMManager.getRepository<ConnectedAccountWorkspaceEntity>(
|
|
||||||
'connectedAccount',
|
|
||||||
);
|
|
||||||
|
|
||||||
await connectedAccountRepository.update(
|
|
||||||
{ id: connectedAccount.id },
|
|
||||||
{
|
|
||||||
accessToken,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return accessToken;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new Error('Provider not supported for access token refresh');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async refreshAccessToken(
|
|
||||||
connectedAccount: ConnectedAccountWorkspaceEntity,
|
|
||||||
refreshToken: string,
|
|
||||||
): Promise<string> {
|
|
||||||
switch (connectedAccount.provider) {
|
|
||||||
case 'google':
|
|
||||||
return this.googleAPIRefreshAccessTokenService.refreshAccessToken(
|
|
||||||
refreshToken,
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
throw new RefreshAccessTokenException(
|
|
||||||
`Provider ${connectedAccount.provider} is not supported`,
|
|
||||||
RefreshAccessTokenExceptionCode.PROVIDER_NOT_SUPPORTED,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { GoogleAPIRefreshAccessTokenModule } from 'src/modules/connected-account/refresh-tokens-manager/drivers/google/google-api-refresh-access-token.module';
|
||||||
|
import { MicrosoftAPIRefreshAccessTokenModule } from 'src/modules/connected-account/refresh-tokens-manager/drivers/microsoft/microsoft-api-refresh-access-token.module';
|
||||||
|
import { ConnectedAccountRefreshTokensService } from 'src/modules/connected-account/refresh-tokens-manager/services/connected-account-refresh-tokens.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
GoogleAPIRefreshAccessTokenModule,
|
||||||
|
MicrosoftAPIRefreshAccessTokenModule,
|
||||||
|
],
|
||||||
|
providers: [ConnectedAccountRefreshTokensService],
|
||||||
|
exports: [ConnectedAccountRefreshTokensService],
|
||||||
|
})
|
||||||
|
export class RefreshTokensManagerModule {}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/refresh-access-token-manager/drivers/google/services/google-api-refresh-access-token.service';
|
import { GoogleAPIRefreshAccessTokenService } from 'src/modules/connected-account/refresh-tokens-manager/drivers/google/services/google-api-refresh-access-token.service';
|
||||||
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
|
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@ -1,15 +1,27 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||||
|
|
||||||
|
export type GoogleTokens = {
|
||||||
|
accessToken: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface GoogleRefreshTokenResponse {
|
||||||
|
access_token: string;
|
||||||
|
id_token?: string;
|
||||||
|
token_type?: string;
|
||||||
|
expires_in?: number;
|
||||||
|
scope?: string;
|
||||||
|
}
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GoogleAPIRefreshAccessTokenService {
|
export class GoogleAPIRefreshAccessTokenService {
|
||||||
constructor(private readonly environmentService: EnvironmentService) {}
|
constructor(private readonly environmentService: EnvironmentService) {}
|
||||||
|
|
||||||
async refreshAccessToken(refreshToken: string): Promise<string> {
|
async refreshAccessToken(refreshToken: string): Promise<GoogleTokens> {
|
||||||
const response = await axios.post(
|
const response = await axios.post<GoogleRefreshTokenResponse>(
|
||||||
'https://oauth2.googleapis.com/token',
|
'https://oauth2.googleapis.com/token',
|
||||||
{
|
{
|
||||||
client_id: this.environmentService.get('AUTH_GOOGLE_CLIENT_ID'),
|
client_id: this.environmentService.get('AUTH_GOOGLE_CLIENT_ID'),
|
||||||
@ -24,6 +36,10 @@ export class GoogleAPIRefreshAccessTokenService {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return response.data.access_token;
|
z.string().parse(response.data.access_token);
|
||||||
|
|
||||||
|
return {
|
||||||
|
accessToken: response.data.access_token,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { EnvironmentModule } from 'src/engine/core-modules/environment/environment.module';
|
||||||
|
import { MicrosoftAPIRefreshAccessTokenService } from 'src/modules/connected-account/refresh-tokens-manager/drivers/microsoft/services/microsoft-api-refresh-tokens.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [EnvironmentModule],
|
||||||
|
providers: [MicrosoftAPIRefreshAccessTokenService],
|
||||||
|
exports: [MicrosoftAPIRefreshAccessTokenService],
|
||||||
|
})
|
||||||
|
export class MicrosoftAPIRefreshAccessTokenModule {}
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
|
||||||
|
|
||||||
|
export type MicrosoftTokens = {
|
||||||
|
accessToken: string;
|
||||||
|
refreshToken: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface MicrosoftRefreshTokenResponse {
|
||||||
|
access_token: string;
|
||||||
|
refresh_token: string;
|
||||||
|
scope: string;
|
||||||
|
token_type: string;
|
||||||
|
expires_in: number;
|
||||||
|
id_token?: string;
|
||||||
|
}
|
||||||
|
@Injectable()
|
||||||
|
export class MicrosoftAPIRefreshAccessTokenService {
|
||||||
|
constructor(private readonly environmentService: EnvironmentService) {}
|
||||||
|
|
||||||
|
async refreshTokens(refreshToken: string): Promise<MicrosoftTokens> {
|
||||||
|
const response = await axios.post<MicrosoftRefreshTokenResponse>(
|
||||||
|
'https://login.microsoftonline.com/common/oauth2/v2.0/token',
|
||||||
|
new URLSearchParams({
|
||||||
|
client_id: this.environmentService.get('AUTH_MICROSOFT_CLIENT_ID'),
|
||||||
|
client_secret: this.environmentService.get(
|
||||||
|
'AUTH_MICROSOFT_CLIENT_SECRET',
|
||||||
|
),
|
||||||
|
refresh_token: refreshToken,
|
||||||
|
grant_type: 'refresh_token',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
z.object({
|
||||||
|
access_token: z.string(),
|
||||||
|
refresh_token: z.string(),
|
||||||
|
}).parse(response.data);
|
||||||
|
|
||||||
|
return {
|
||||||
|
accessToken: response.data.access_token,
|
||||||
|
refreshToken: response.data.refresh_token,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +1,15 @@
|
|||||||
import { CustomException } from 'src/utils/custom-exception';
|
import { CustomException } from 'src/utils/custom-exception';
|
||||||
|
|
||||||
export class RefreshAccessTokenException extends CustomException {
|
export class ConnectedAccountRefreshAccessTokenException extends CustomException {
|
||||||
constructor(message: string, code: RefreshAccessTokenExceptionCode) {
|
constructor(
|
||||||
|
message: string,
|
||||||
|
code: ConnectedAccountRefreshAccessTokenExceptionCode,
|
||||||
|
) {
|
||||||
super(message, code);
|
super(message, code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum RefreshAccessTokenExceptionCode {
|
export enum ConnectedAccountRefreshAccessTokenExceptionCode {
|
||||||
REFRESH_TOKEN_NOT_FOUND = 'REFRESH_TOKEN_NOT_FOUND',
|
REFRESH_TOKEN_NOT_FOUND = 'REFRESH_TOKEN_NOT_FOUND',
|
||||||
REFRESH_ACCESS_TOKEN_FAILED = 'REFRESH_ACCESS_TOKEN_FAILED',
|
REFRESH_ACCESS_TOKEN_FAILED = 'REFRESH_ACCESS_TOKEN_FAILED',
|
||||||
PROVIDER_NOT_SUPPORTED = 'PROVIDER_NOT_SUPPORTED',
|
PROVIDER_NOT_SUPPORTED = 'PROVIDER_NOT_SUPPORTED',
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { assertUnreachable, ConnectedAccountProvider } from 'twenty-shared';
|
||||||
|
|
||||||
|
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||||
|
import {
|
||||||
|
GoogleAPIRefreshAccessTokenService,
|
||||||
|
GoogleTokens,
|
||||||
|
} from 'src/modules/connected-account/refresh-tokens-manager/drivers/google/services/google-api-refresh-access-token.service';
|
||||||
|
import {
|
||||||
|
MicrosoftAPIRefreshAccessTokenService,
|
||||||
|
MicrosoftTokens,
|
||||||
|
} from 'src/modules/connected-account/refresh-tokens-manager/drivers/microsoft/services/microsoft-api-refresh-tokens.service';
|
||||||
|
import {
|
||||||
|
ConnectedAccountRefreshAccessTokenException,
|
||||||
|
ConnectedAccountRefreshAccessTokenExceptionCode,
|
||||||
|
} from 'src/modules/connected-account/refresh-tokens-manager/exceptions/connected-account-refresh-tokens.exception';
|
||||||
|
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||||
|
|
||||||
|
export type ConnectedAccountTokens = GoogleTokens | MicrosoftTokens;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ConnectedAccountRefreshTokensService {
|
||||||
|
constructor(
|
||||||
|
private readonly googleAPIRefreshAccessTokenService: GoogleAPIRefreshAccessTokenService,
|
||||||
|
private readonly microsoftAPIRefreshAccessTokenService: MicrosoftAPIRefreshAccessTokenService,
|
||||||
|
private readonly twentyORMManager: TwentyORMManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async refreshAndSaveTokens(
|
||||||
|
connectedAccount: ConnectedAccountWorkspaceEntity,
|
||||||
|
workspaceId: string,
|
||||||
|
): Promise<string> {
|
||||||
|
const refreshToken = connectedAccount.refreshToken;
|
||||||
|
|
||||||
|
if (!refreshToken) {
|
||||||
|
throw new ConnectedAccountRefreshAccessTokenException(
|
||||||
|
`No refresh token found for connected account ${connectedAccount.id} in workspace ${workspaceId}`,
|
||||||
|
ConnectedAccountRefreshAccessTokenExceptionCode.REFRESH_TOKEN_NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const connectedAccountTokens = await this.refreshTokens(
|
||||||
|
connectedAccount,
|
||||||
|
refreshToken,
|
||||||
|
workspaceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const connectedAccountRepository =
|
||||||
|
await this.twentyORMManager.getRepository<ConnectedAccountWorkspaceEntity>(
|
||||||
|
'connectedAccount',
|
||||||
|
);
|
||||||
|
|
||||||
|
await connectedAccountRepository.update(
|
||||||
|
{ id: connectedAccount.id },
|
||||||
|
connectedAccountTokens,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Error saving the new tokens for connected account ${connectedAccount.id} in workspace ${workspaceId}: ${error.message} `,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return connectedAccountTokens.accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
async refreshTokens(
|
||||||
|
connectedAccount: ConnectedAccountWorkspaceEntity,
|
||||||
|
refreshToken: string,
|
||||||
|
workspaceId: string,
|
||||||
|
): Promise<ConnectedAccountTokens> {
|
||||||
|
try {
|
||||||
|
switch (connectedAccount.provider) {
|
||||||
|
case ConnectedAccountProvider.GOOGLE:
|
||||||
|
return this.googleAPIRefreshAccessTokenService.refreshAccessToken(
|
||||||
|
refreshToken,
|
||||||
|
);
|
||||||
|
case ConnectedAccountProvider.MICROSOFT:
|
||||||
|
return this.microsoftAPIRefreshAccessTokenService.refreshTokens(
|
||||||
|
refreshToken,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return assertUnreachable(
|
||||||
|
connectedAccount.provider,
|
||||||
|
`Provider ${connectedAccount.provider} not supported`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new ConnectedAccountRefreshAccessTokenException(
|
||||||
|
`Error refreshing tokens for connected account ${connectedAccount.id} in workspace ${workspaceId}: ${error.message} ${error?.response?.data?.error_description}`,
|
||||||
|
ConnectedAccountRefreshAccessTokenExceptionCode.REFRESH_ACCESS_TOKEN_FAILED,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,12 +4,20 @@ import { Process } from 'src/engine/core-modules/message-queue/decorators/proces
|
|||||||
import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
|
import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
|
||||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||||
|
import { ConnectedAccountRefreshAccessTokenExceptionCode } from 'src/modules/connected-account/refresh-tokens-manager/exceptions/connected-account-refresh-tokens.exception';
|
||||||
|
import { ConnectedAccountRefreshTokensService } from 'src/modules/connected-account/refresh-tokens-manager/services/connected-account-refresh-tokens.service';
|
||||||
import { isThrottled } from 'src/modules/connected-account/utils/is-throttled';
|
import { isThrottled } from 'src/modules/connected-account/utils/is-throttled';
|
||||||
import {
|
import {
|
||||||
MessageChannelSyncStage,
|
MessageChannelSyncStage,
|
||||||
MessageChannelWorkspaceEntity,
|
MessageChannelWorkspaceEntity,
|
||||||
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
|
import { MessageImportDriverExceptionCode } from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception';
|
||||||
|
import { MessageImportExceptionCode } from 'src/modules/messaging/message-import-manager/exceptions/message-import.exception';
|
||||||
import { MessagingFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-full-message-list-fetch.service';
|
import { MessagingFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-full-message-list-fetch.service';
|
||||||
|
import {
|
||||||
|
MessageImportExceptionHandlerService,
|
||||||
|
MessageImportSyncStep,
|
||||||
|
} from 'src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service';
|
||||||
import { MessagingPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-partial-message-list-fetch.service';
|
import { MessagingPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-partial-message-list-fetch.service';
|
||||||
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
|
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
|
||||||
|
|
||||||
@ -30,6 +38,8 @@ export class MessagingMessageListFetchJob {
|
|||||||
private readonly messagingPartialMessageListFetchService: MessagingPartialMessageListFetchService,
|
private readonly messagingPartialMessageListFetchService: MessagingPartialMessageListFetchService,
|
||||||
private readonly messagingTelemetryService: MessagingTelemetryService,
|
private readonly messagingTelemetryService: MessagingTelemetryService,
|
||||||
private readonly twentyORMManager: TwentyORMManager,
|
private readonly twentyORMManager: TwentyORMManager,
|
||||||
|
private readonly connectedAccountRefreshTokensService: ConnectedAccountRefreshTokensService,
|
||||||
|
private readonly messageImportErrorHandlerService: MessageImportExceptionHandlerService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Process(MessagingMessageListFetchJob.name)
|
@Process(MessagingMessageListFetchJob.name)
|
||||||
@ -64,72 +74,112 @@ export class MessagingMessageListFetchJob {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
try {
|
||||||
isThrottled(
|
if (
|
||||||
messageChannel.syncStageStartedAt,
|
isThrottled(
|
||||||
messageChannel.throttleFailureCount,
|
messageChannel.syncStageStartedAt,
|
||||||
)
|
messageChannel.throttleFailureCount,
|
||||||
) {
|
)
|
||||||
return;
|
) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (messageChannel.syncStage) {
|
try {
|
||||||
case MessageChannelSyncStage.PARTIAL_MESSAGE_LIST_FETCH_PENDING:
|
messageChannel.connectedAccount.accessToken =
|
||||||
this.logger.log(
|
await this.connectedAccountRefreshTokensService.refreshAndSaveTokens(
|
||||||
`Fetching partial message list for workspace ${workspaceId} and messageChannelId ${messageChannel.id}`,
|
messageChannel.connectedAccount,
|
||||||
);
|
workspaceId,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
switch (error.code) {
|
||||||
|
case ConnectedAccountRefreshAccessTokenExceptionCode.REFRESH_ACCESS_TOKEN_FAILED:
|
||||||
|
case ConnectedAccountRefreshAccessTokenExceptionCode.REFRESH_TOKEN_NOT_FOUND:
|
||||||
|
await this.messagingTelemetryService.track({
|
||||||
|
eventName: `refresh_token.error.insufficient_permissions`,
|
||||||
|
workspaceId,
|
||||||
|
connectedAccountId: messageChannel.connectedAccountId,
|
||||||
|
messageChannelId: messageChannel.id,
|
||||||
|
message: `${error.code}: ${error.reason ?? ''}`,
|
||||||
|
});
|
||||||
|
throw {
|
||||||
|
code: MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS,
|
||||||
|
message: error.message,
|
||||||
|
};
|
||||||
|
case ConnectedAccountRefreshAccessTokenExceptionCode.PROVIDER_NOT_SUPPORTED:
|
||||||
|
throw {
|
||||||
|
code: MessageImportExceptionCode.PROVIDER_NOT_SUPPORTED,
|
||||||
|
message: error.message,
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await this.messagingTelemetryService.track({
|
switch (messageChannel.syncStage) {
|
||||||
eventName: 'partial_message_list_fetch.started',
|
case MessageChannelSyncStage.PARTIAL_MESSAGE_LIST_FETCH_PENDING:
|
||||||
workspaceId,
|
this.logger.log(
|
||||||
connectedAccountId: messageChannel.connectedAccount.id,
|
`Fetching partial message list for workspace ${workspaceId} and messageChannelId ${messageChannel.id}`,
|
||||||
messageChannelId: messageChannel.id,
|
);
|
||||||
});
|
|
||||||
|
|
||||||
await this.messagingPartialMessageListFetchService.processMessageListFetch(
|
await this.messagingTelemetryService.track({
|
||||||
messageChannel,
|
eventName: 'partial_message_list_fetch.started',
|
||||||
messageChannel.connectedAccount,
|
workspaceId,
|
||||||
workspaceId,
|
connectedAccountId: messageChannel.connectedAccount.id,
|
||||||
);
|
messageChannelId: messageChannel.id,
|
||||||
|
});
|
||||||
|
|
||||||
await this.messagingTelemetryService.track({
|
await this.messagingPartialMessageListFetchService.processMessageListFetch(
|
||||||
eventName: 'partial_message_list_fetch.completed',
|
messageChannel,
|
||||||
workspaceId,
|
messageChannel.connectedAccount,
|
||||||
connectedAccountId: messageChannel.connectedAccount.id,
|
workspaceId,
|
||||||
messageChannelId: messageChannel.id,
|
);
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
await this.messagingTelemetryService.track({
|
||||||
|
eventName: 'partial_message_list_fetch.completed',
|
||||||
|
workspaceId,
|
||||||
|
connectedAccountId: messageChannel.connectedAccount.id,
|
||||||
|
messageChannelId: messageChannel.id,
|
||||||
|
});
|
||||||
|
|
||||||
case MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING:
|
break;
|
||||||
this.logger.log(
|
|
||||||
`Fetching full message list for workspace ${workspaceId} and account ${messageChannel.connectedAccount.id}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
await this.messagingTelemetryService.track({
|
case MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING:
|
||||||
eventName: 'full_message_list_fetch.started',
|
this.logger.log(
|
||||||
workspaceId,
|
`Fetching full message list for workspace ${workspaceId} and account ${messageChannel.connectedAccount.id}`,
|
||||||
connectedAccountId: messageChannel.connectedAccount.id,
|
);
|
||||||
messageChannelId: messageChannel.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.messagingFullMessageListFetchService.processMessageListFetch(
|
await this.messagingTelemetryService.track({
|
||||||
messageChannel,
|
eventName: 'full_message_list_fetch.started',
|
||||||
messageChannel.connectedAccount,
|
workspaceId,
|
||||||
workspaceId,
|
connectedAccountId: messageChannel.connectedAccount.id,
|
||||||
);
|
messageChannelId: messageChannel.id,
|
||||||
|
});
|
||||||
|
|
||||||
await this.messagingTelemetryService.track({
|
await this.messagingFullMessageListFetchService.processMessageListFetch(
|
||||||
eventName: 'full_message_list_fetch.completed',
|
messageChannel,
|
||||||
workspaceId,
|
messageChannel.connectedAccount,
|
||||||
connectedAccountId: messageChannel.connectedAccount.id,
|
workspaceId,
|
||||||
messageChannelId: messageChannel.id,
|
);
|
||||||
});
|
|
||||||
|
|
||||||
break;
|
await this.messagingTelemetryService.track({
|
||||||
|
eventName: 'full_message_list_fetch.completed',
|
||||||
|
workspaceId,
|
||||||
|
connectedAccountId: messageChannel.connectedAccount.id,
|
||||||
|
messageChannelId: messageChannel.id,
|
||||||
|
});
|
||||||
|
|
||||||
default:
|
break;
|
||||||
break;
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
await this.messageImportErrorHandlerService.handleDriverException(
|
||||||
|
error,
|
||||||
|
MessageImportSyncStep.FULL_OR_PARTIAL_MESSAGE_LIST_FETCH,
|
||||||
|
messageChannel,
|
||||||
|
workspaceId,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
|||||||
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
|
||||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||||
import { EmailAliasManagerModule } from 'src/modules/connected-account/email-alias-manager/email-alias-manager.module';
|
import { EmailAliasManagerModule } from 'src/modules/connected-account/email-alias-manager/email-alias-manager.module';
|
||||||
import { RefreshAccessTokenManagerModule } from 'src/modules/connected-account/refresh-access-token-manager/refresh-access-token-manager.module';
|
import { RefreshTokensManagerModule } from 'src/modules/connected-account/refresh-tokens-manager/connected-account-refresh-tokens-manager.module';
|
||||||
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
|
import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-common.module';
|
||||||
import { MessagingMessageCleanerModule } from 'src/modules/messaging/message-cleaner/messaging-message-cleaner.module';
|
import { MessagingMessageCleanerModule } from 'src/modules/messaging/message-cleaner/messaging-message-cleaner.module';
|
||||||
import { MessagingSingleMessageImportCommand } from 'src/modules/messaging/message-import-manager/commands/messaging-single-message-import.command';
|
import { MessagingSingleMessageImportCommand } from 'src/modules/messaging/message-import-manager/commands/messaging-single-message-import.command';
|
||||||
@ -25,11 +25,11 @@ import { MessagingMessageListFetchJob } from 'src/modules/messaging/message-impo
|
|||||||
import { MessagingMessagesImportJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job';
|
import { MessagingMessagesImportJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-messages-import.job';
|
||||||
import { MessagingOngoingStaleJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job';
|
import { MessagingOngoingStaleJob } from 'src/modules/messaging/message-import-manager/jobs/messaging-ongoing-stale.job';
|
||||||
import { MessagingMessageImportManagerMessageChannelListener } from 'src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener';
|
import { MessagingMessageImportManagerMessageChannelListener } from 'src/modules/messaging/message-import-manager/listeners/messaging-import-manager-message-channel.listener';
|
||||||
import { MessageImportExceptionHandlerService } from 'src/modules/messaging/message-import-manager/services/message-import-exception-handler.service';
|
|
||||||
import { MessagingCursorService } from 'src/modules/messaging/message-import-manager/services/messaging-cursor.service';
|
import { MessagingCursorService } from 'src/modules/messaging/message-import-manager/services/messaging-cursor.service';
|
||||||
import { MessagingFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-full-message-list-fetch.service';
|
import { MessagingFullMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-full-message-list-fetch.service';
|
||||||
import { MessagingGetMessageListService } from 'src/modules/messaging/message-import-manager/services/messaging-get-message-list.service';
|
import { MessagingGetMessageListService } from 'src/modules/messaging/message-import-manager/services/messaging-get-message-list.service';
|
||||||
import { MessagingGetMessagesService } from 'src/modules/messaging/message-import-manager/services/messaging-get-messages.service';
|
import { MessagingGetMessagesService } from 'src/modules/messaging/message-import-manager/services/messaging-get-messages.service';
|
||||||
|
import { MessageImportExceptionHandlerService } from 'src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service';
|
||||||
import { MessagingMessageService } from 'src/modules/messaging/message-import-manager/services/messaging-message.service';
|
import { MessagingMessageService } from 'src/modules/messaging/message-import-manager/services/messaging-message.service';
|
||||||
import { MessagingMessagesImportService } from 'src/modules/messaging/message-import-manager/services/messaging-messages-import.service';
|
import { MessagingMessagesImportService } from 'src/modules/messaging/message-import-manager/services/messaging-messages-import.service';
|
||||||
import { MessagingPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-partial-message-list-fetch.service';
|
import { MessagingPartialMessageListFetchService } from 'src/modules/messaging/message-import-manager/services/messaging-partial-message-list-fetch.service';
|
||||||
@ -38,7 +38,7 @@ import { MessageParticipantManagerModule } from 'src/modules/messaging/message-p
|
|||||||
import { MessagingMonitoringModule } from 'src/modules/messaging/monitoring/messaging-monitoring.module';
|
import { MessagingMonitoringModule } from 'src/modules/messaging/monitoring/messaging-monitoring.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
RefreshAccessTokenManagerModule,
|
RefreshTokensManagerModule,
|
||||||
WorkspaceDataSourceModule,
|
WorkspaceDataSourceModule,
|
||||||
MessagingGmailDriverModule,
|
MessagingGmailDriverModule,
|
||||||
MessagingMicrosoftDriverModule,
|
MessagingMicrosoftDriverModule,
|
||||||
|
|||||||
@ -11,12 +11,12 @@ import { MessageChannelSyncStatusService } from 'src/modules/messaging/common/se
|
|||||||
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
||||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
import { MessagingMessageCleanerService } from 'src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service';
|
import { MessagingMessageCleanerService } from 'src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service';
|
||||||
|
import { MessagingCursorService } from 'src/modules/messaging/message-import-manager/services/messaging-cursor.service';
|
||||||
|
import { MessagingGetMessageListService } from 'src/modules/messaging/message-import-manager/services/messaging-get-message-list.service';
|
||||||
import {
|
import {
|
||||||
MessageImportExceptionHandlerService,
|
MessageImportExceptionHandlerService,
|
||||||
MessageImportSyncStep,
|
MessageImportSyncStep,
|
||||||
} from 'src/modules/messaging/message-import-manager/services/message-import-exception-handler.service';
|
} from 'src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service';
|
||||||
import { MessagingCursorService } from 'src/modules/messaging/message-import-manager/services/messaging-cursor.service';
|
|
||||||
import { MessagingGetMessageListService } from 'src/modules/messaging/message-import-manager/services/messaging-get-message-list.service';
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MessagingFullMessageListFetchService {
|
export class MessagingFullMessageListFetchService {
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import {
|
|||||||
export enum MessageImportSyncStep {
|
export enum MessageImportSyncStep {
|
||||||
FULL_MESSAGE_LIST_FETCH = 'FULL_MESSAGE_LIST_FETCH',
|
FULL_MESSAGE_LIST_FETCH = 'FULL_MESSAGE_LIST_FETCH',
|
||||||
PARTIAL_MESSAGE_LIST_FETCH = 'PARTIAL_MESSAGE_LIST_FETCH',
|
PARTIAL_MESSAGE_LIST_FETCH = 'PARTIAL_MESSAGE_LIST_FETCH',
|
||||||
|
FULL_OR_PARTIAL_MESSAGE_LIST_FETCH = 'FULL_OR_PARTIAL_MESSAGE_LIST_FETCH',
|
||||||
MESSAGES_IMPORT = 'MESSAGES_IMPORT',
|
MESSAGES_IMPORT = 'MESSAGES_IMPORT',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8,8 +8,8 @@ import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
|||||||
import { BlocklistRepository } from 'src/modules/blocklist/repositories/blocklist.repository';
|
import { BlocklistRepository } from 'src/modules/blocklist/repositories/blocklist.repository';
|
||||||
import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity';
|
import { BlocklistWorkspaceEntity } from 'src/modules/blocklist/standard-objects/blocklist.workspace-entity';
|
||||||
import { EmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/services/email-alias-manager.service';
|
import { EmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/services/email-alias-manager.service';
|
||||||
import { RefreshAccessTokenExceptionCode } from 'src/modules/connected-account/refresh-access-token-manager/exceptions/refresh-access-token.exception';
|
import { ConnectedAccountRefreshAccessTokenExceptionCode } from 'src/modules/connected-account/refresh-tokens-manager/exceptions/connected-account-refresh-tokens.exception';
|
||||||
import { RefreshAccessTokenService } from 'src/modules/connected-account/refresh-access-token-manager/services/refresh-access-token.service';
|
import { ConnectedAccountRefreshTokensService } from 'src/modules/connected-account/refresh-tokens-manager/services/connected-account-refresh-tokens.service';
|
||||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||||
import { MessageChannelSyncStatusService } from 'src/modules/messaging/common/services/message-channel-sync-status.service';
|
import { MessageChannelSyncStatusService } from 'src/modules/messaging/common/services/message-channel-sync-status.service';
|
||||||
import {
|
import {
|
||||||
@ -19,11 +19,11 @@ import {
|
|||||||
import { MessageImportDriverExceptionCode } from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception';
|
import { MessageImportDriverExceptionCode } from 'src/modules/messaging/message-import-manager/drivers/exceptions/message-import-driver.exception';
|
||||||
import { MESSAGING_GMAIL_USERS_MESSAGES_GET_BATCH_SIZE } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-get-batch-size.constant';
|
import { MESSAGING_GMAIL_USERS_MESSAGES_GET_BATCH_SIZE } from 'src/modules/messaging/message-import-manager/drivers/gmail/constants/messaging-gmail-users-messages-get-batch-size.constant';
|
||||||
import { MessageImportExceptionCode } from 'src/modules/messaging/message-import-manager/exceptions/message-import.exception';
|
import { MessageImportExceptionCode } from 'src/modules/messaging/message-import-manager/exceptions/message-import.exception';
|
||||||
|
import { MessagingGetMessagesService } from 'src/modules/messaging/message-import-manager/services/messaging-get-messages.service';
|
||||||
import {
|
import {
|
||||||
MessageImportExceptionHandlerService,
|
MessageImportExceptionHandlerService,
|
||||||
MessageImportSyncStep,
|
MessageImportSyncStep,
|
||||||
} from 'src/modules/messaging/message-import-manager/services/message-import-exception-handler.service';
|
} from 'src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service';
|
||||||
import { MessagingGetMessagesService } from 'src/modules/messaging/message-import-manager/services/messaging-get-messages.service';
|
|
||||||
import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service';
|
import { MessagingSaveMessagesAndEnqueueContactCreationService } from 'src/modules/messaging/message-import-manager/services/messaging-save-messages-and-enqueue-contact-creation.service';
|
||||||
import { filterEmails } from 'src/modules/messaging/message-import-manager/utils/filter-emails.util';
|
import { filterEmails } from 'src/modules/messaging/message-import-manager/utils/filter-emails.util';
|
||||||
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
|
import { MessagingTelemetryService } from 'src/modules/messaging/monitoring/services/messaging-telemetry.service';
|
||||||
@ -37,7 +37,7 @@ export class MessagingMessagesImportService {
|
|||||||
private readonly cacheStorage: CacheStorageService,
|
private readonly cacheStorage: CacheStorageService,
|
||||||
private readonly messageChannelSyncStatusService: MessageChannelSyncStatusService,
|
private readonly messageChannelSyncStatusService: MessageChannelSyncStatusService,
|
||||||
private readonly saveMessagesAndEnqueueContactCreationService: MessagingSaveMessagesAndEnqueueContactCreationService,
|
private readonly saveMessagesAndEnqueueContactCreationService: MessagingSaveMessagesAndEnqueueContactCreationService,
|
||||||
private readonly refreshAccessTokenService: RefreshAccessTokenService,
|
private readonly connectedAccountRefreshTokensService: ConnectedAccountRefreshTokensService,
|
||||||
private readonly messagingTelemetryService: MessagingTelemetryService,
|
private readonly messagingTelemetryService: MessagingTelemetryService,
|
||||||
@InjectObjectMetadataRepository(BlocklistWorkspaceEntity)
|
@InjectObjectMetadataRepository(BlocklistWorkspaceEntity)
|
||||||
private readonly blocklistRepository: BlocklistRepository,
|
private readonly blocklistRepository: BlocklistRepository,
|
||||||
@ -79,14 +79,14 @@ export class MessagingMessagesImportService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
connectedAccount.accessToken =
|
connectedAccount.accessToken =
|
||||||
await this.refreshAccessTokenService.refreshAndSaveAccessToken(
|
await this.connectedAccountRefreshTokensService.refreshAndSaveTokens(
|
||||||
connectedAccount,
|
connectedAccount,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
switch (error.code) {
|
switch (error.code) {
|
||||||
case RefreshAccessTokenExceptionCode.REFRESH_ACCESS_TOKEN_FAILED:
|
case ConnectedAccountRefreshAccessTokenExceptionCode.REFRESH_ACCESS_TOKEN_FAILED:
|
||||||
case RefreshAccessTokenExceptionCode.REFRESH_TOKEN_NOT_FOUND:
|
case ConnectedAccountRefreshAccessTokenExceptionCode.REFRESH_TOKEN_NOT_FOUND:
|
||||||
await this.messagingTelemetryService.track({
|
await this.messagingTelemetryService.track({
|
||||||
eventName: `refresh_token.error.insufficient_permissions`,
|
eventName: `refresh_token.error.insufficient_permissions`,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@ -98,7 +98,7 @@ export class MessagingMessagesImportService {
|
|||||||
code: MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS,
|
code: MessageImportDriverExceptionCode.INSUFFICIENT_PERMISSIONS,
|
||||||
message: error.message,
|
message: error.message,
|
||||||
};
|
};
|
||||||
case RefreshAccessTokenExceptionCode.PROVIDER_NOT_SUPPORTED:
|
case ConnectedAccountRefreshAccessTokenExceptionCode.PROVIDER_NOT_SUPPORTED:
|
||||||
throw {
|
throw {
|
||||||
code: MessageImportExceptionCode.PROVIDER_NOT_SUPPORTED,
|
code: MessageImportExceptionCode.PROVIDER_NOT_SUPPORTED,
|
||||||
message: error.message,
|
message: error.message,
|
||||||
|
|||||||
@ -11,12 +11,12 @@ import { MessageChannelSyncStatusService } from 'src/modules/messaging/common/se
|
|||||||
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity';
|
||||||
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
import { MessageChannelWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
|
||||||
import { MessagingMessageCleanerService } from 'src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service';
|
import { MessagingMessageCleanerService } from 'src/modules/messaging/message-cleaner/services/messaging-message-cleaner.service';
|
||||||
|
import { MessagingCursorService } from 'src/modules/messaging/message-import-manager/services/messaging-cursor.service';
|
||||||
|
import { MessagingGetMessageListService } from 'src/modules/messaging/message-import-manager/services/messaging-get-message-list.service';
|
||||||
import {
|
import {
|
||||||
MessageImportExceptionHandlerService,
|
MessageImportExceptionHandlerService,
|
||||||
MessageImportSyncStep,
|
MessageImportSyncStep,
|
||||||
} from 'src/modules/messaging/message-import-manager/services/message-import-exception-handler.service';
|
} from 'src/modules/messaging/message-import-manager/services/messaging-import-exception-handler.service';
|
||||||
import { MessagingCursorService } from 'src/modules/messaging/message-import-manager/services/messaging-cursor.service';
|
|
||||||
import { MessagingGetMessageListService } from 'src/modules/messaging/message-import-manager/services/messaging-get-message-list.service';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MessagingPartialMessageListFetchService {
|
export class MessagingPartialMessageListFetchService {
|
||||||
|
|||||||
3
packages/twenty-shared/src/utils/assertUnreachable.ts
Normal file
3
packages/twenty-shared/src/utils/assertUnreachable.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const assertUnreachable = (x: never, errorMessage?: string): never => {
|
||||||
|
throw new Error(errorMessage ?? "Didn't expect to get here.");
|
||||||
|
};
|
||||||
@ -1,5 +1,7 @@
|
|||||||
|
export * from './assertUnreachable';
|
||||||
export * from './fieldMetadata';
|
export * from './fieldMetadata';
|
||||||
export * from './image';
|
export * from './image';
|
||||||
export * from './strings';
|
export * from './strings';
|
||||||
export * from './url';
|
export * from './url';
|
||||||
export * from './validation';
|
export * from './validation';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user