Compare commits

...

1 Commits

Author SHA1 Message Date
Félix Malfait c84de47ea6 Fix auth connection (#15869)
Better to do auth this way than in module
2025-11-17 18:16:29 +01:00
9 changed files with 58 additions and 39 deletions
@@ -2,7 +2,7 @@
import { Injectable, Logger } from '@nestjs/common';
import { type GaxiosError } from 'gaxios';
import { type calendar_v3 as calendarV3 } from 'googleapis';
import { google, type calendar_v3 as calendarV3 } from 'googleapis';
import { formatGoogleCalendarEvents } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/format-google-calendar-event.util';
import { parseGaxiosError } from 'src/modules/calendar/calendar-event-import-manager/drivers/google-calendar/utils/parse-gaxios-error.util';
@@ -31,7 +31,10 @@ export class GoogleCalendarGetEventsService {
connectedAccount,
);
const googleCalendarClient = oAuth2Client.calendar({ version: 'v3' });
const googleCalendarClient = google.calendar({
version: 'v3',
auth: oAuth2Client,
});
let nextSyncToken: string | null | undefined;
let nextPageToken: string | undefined;
@@ -1,5 +1,7 @@
import { Injectable } from '@nestjs/common';
import { google } from 'googleapis';
import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service';
import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
@@ -17,11 +19,12 @@ export class GoogleEmailAliasManagerService {
connectedAccount,
);
const people = oAuth2Client.people({
const peopleClient = google.people({
version: 'v1',
auth: oAuth2Client,
});
const emailsResponse = await people.people.get({
const emailsResponse = await peopleClient.people.get({
resourceName: 'people/me',
personFields: 'emailAddresses',
});
@@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { google, GoogleApis } from 'googleapis';
import { google, type Auth } from 'googleapis';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
@@ -11,7 +11,9 @@ export class GoogleOAuth2ClientManagerService {
private readonly logger: Logger,
) {}
public async getOAuth2Client(refreshToken: string): Promise<GoogleApis> {
public async getOAuth2Client(
refreshToken: string,
): Promise<Auth.OAuth2Client> {
const gmailClientId = this.twentyConfigService.get('AUTH_GOOGLE_CLIENT_ID');
const gmailClientSecret = this.twentyConfigService.get(
'AUTH_GOOGLE_CLIENT_SECRET',
@@ -27,9 +29,7 @@ export class GoogleOAuth2ClientManagerService {
refresh_token: refreshToken,
});
google.options({ auth: oAuth2Client });
return google;
return oAuth2Client;
} catch (error) {
this.logger.error(
`Error in ${GoogleOAuth2ClientManagerService.name}`,
@@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common';
import { type Client } from '@microsoft/microsoft-graph-client';
import { GoogleApis } from 'googleapis';
import { type Auth } from 'googleapis';
import { GoogleOAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/drivers/google/google-oauth2-client-manager.service';
import { MicrosoftOAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/drivers/microsoft/microsoft-oauth2-client-manager.service';
@@ -19,7 +19,7 @@ export class OAuth2ClientManagerService {
ConnectedAccountWorkspaceEntity,
'provider' | 'refreshToken'
>,
): Promise<GoogleApis> {
): Promise<Auth.OAuth2Client> {
return this.googleOAuth2ClientManagerService.getOAuth2Client(
connectedAccount.refreshToken,
);
@@ -1,5 +1,7 @@
import { Injectable, Logger } from '@nestjs/common';
import { google } from 'googleapis';
import {
MessageFolder,
MessageFolderDriver,
@@ -39,7 +41,10 @@ export class GmailGetAllFoldersService implements MessageFolderDriver {
connectedAccount,
);
const gmailClient = oAuth2Client.gmail({ version: 'v1' });
const gmailClient = google.gmail({
version: 'v1',
auth: oAuth2Client,
});
const response = await gmailClient.users.labels
.list({ userId: 'me' })
@@ -1,5 +1,6 @@
import { Test, type TestingModule } from '@nestjs/testing';
import { google } from 'googleapis';
import { ConnectedAccountProvider } from 'twenty-shared/types';
import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service';
@@ -63,6 +64,10 @@ describe('GmailGetMessageListService', () => {
);
});
afterEach(() => {
jest.restoreAllMocks();
});
describe('getMessageList', () => {
it('should return 0 messageExternalIds when gmail returns 0 messages', async () => {
const mockGmailClient = {
@@ -78,13 +83,11 @@ describe('GmailGetMessageListService', () => {
},
};
const mockOAuth2Client = {
gmail: jest.fn().mockReturnValue(mockGmailClient),
};
jest.spyOn(google, 'gmail').mockReturnValue(mockGmailClient as never);
(
oAuth2ClientManagerService.getGoogleOAuth2Client as jest.Mock
).mockResolvedValue(mockOAuth2Client);
).mockResolvedValue({});
const result = await service.getMessageLists({
messageChannel: { syncCursor: '', id: 'my-id' },
@@ -133,13 +136,11 @@ describe('GmailGetMessageListService', () => {
},
};
const mockOAuth2Client = {
gmail: jest.fn().mockReturnValue(mockGmailClient),
};
jest.spyOn(google, 'gmail').mockReturnValue(mockGmailClient as never);
(
oAuth2ClientManagerService.getGoogleOAuth2Client as jest.Mock
).mockResolvedValue(mockOAuth2Client);
).mockResolvedValue({});
const result = await service.getMessageLists({
messageChannel: { syncCursor: '', id: 'my-id' },
@@ -188,13 +189,11 @@ describe('GmailGetMessageListService', () => {
},
};
const mockOAuth2Client = {
gmail: jest.fn().mockReturnValue(mockGmailClient),
};
jest.spyOn(google, 'gmail').mockReturnValue(mockGmailClient as never);
(
oAuth2ClientManagerService.getGoogleOAuth2Client as jest.Mock
).mockResolvedValue(mockOAuth2Client);
).mockResolvedValue({});
const result = await service.getMessageLists({
messageChannel: { syncCursor: '', id: 'my-id' },
@@ -224,13 +223,11 @@ describe('GmailGetMessageListService', () => {
},
};
const mockOAuth2Client = {
gmail: jest.fn().mockReturnValue(mockGmailClient),
};
jest.spyOn(google, 'gmail').mockReturnValue(mockGmailClient as never);
(
oAuth2ClientManagerService.getGoogleOAuth2Client as jest.Mock
).mockResolvedValue(mockOAuth2Client);
).mockResolvedValue({});
const result = await service.getMessageLists({
messageChannel: { syncCursor: '', id: 'my-id' },
@@ -1,7 +1,7 @@
import { Injectable, Logger } from '@nestjs/common';
import { isNonEmptyString } from '@sniptt/guards';
import { type gmail_v1 as gmailV1 } from 'googleapis';
import { google, type gmail_v1 as gmailV1 } from 'googleapis';
import { isDefined } from 'twenty-shared/utils';
import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service';
@@ -42,7 +42,10 @@ export class GmailGetMessageListService {
await this.oAuth2ClientManagerService.getGoogleOAuth2Client(
connectedAccount,
);
const gmailClient = oAuth2Client.gmail({ version: 'v1' });
const gmailClient = google.gmail({
version: 'v1',
auth: oAuth2Client,
});
let pageToken: string | undefined;
let hasMoreMessages = true;
@@ -143,7 +146,10 @@ export class GmailGetMessageListService {
await this.oAuth2ClientManagerService.getGoogleOAuth2Client(
connectedAccount,
);
const gmailClient = oAuth2Client.gmail({ version: 'v1' });
const gmailClient = google.gmail({
version: 'v1',
auth: oAuth2Client,
});
if (!isNonEmptyString(messageChannel.syncCursor)) {
return this.getMessageListWithoutCursor(connectedAccount, messageFolders);
@@ -1,5 +1,6 @@
import { Test, type TestingModule } from '@nestjs/testing';
import { google } from 'googleapis';
import { ConnectedAccountProvider } from 'twenty-shared/types';
import { OAuth2ClientManagerService } from 'src/modules/connected-account/oauth2-client-manager/services/oauth2-client-manager.service';
@@ -27,7 +28,7 @@ describe('MessagingSendMessageService - Gmail HTML Support', () => {
},
getProfile: jest
.fn()
.mockResolvedValue({ data: { emailAdress: 'test@example.com' } }),
.mockResolvedValue({ data: { emailAddress: 'test@example.com' } }),
},
};
@@ -45,12 +46,12 @@ describe('MessagingSendMessageService - Gmail HTML Support', () => {
},
};
const mockOAuth2Client = {
gmail: jest.fn().mockReturnValue(mockGmailClient),
people: jest.fn().mockReturnValue(mockPeopleClient),
};
const mockOAuth2Client = {};
beforeEach(async () => {
jest.spyOn(google, 'gmail').mockReturnValue(mockGmailClient as never);
jest.spyOn(google, 'people').mockReturnValue(mockPeopleClient as never);
const module: TestingModule = await Test.createTestingModule({
providers: [
MessagingSendMessageService,
@@ -79,7 +80,8 @@ describe('MessagingSendMessageService - Gmail HTML Support', () => {
});
afterEach(() => {
jest.clearAllMocks();
mockSend.mockClear();
jest.restoreAllMocks();
});
it('should send multipart/alternative email with both text and HTML parts via Gmail', async () => {
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
import { google } from 'googleapis';
import MailComposer from 'nodemailer/lib/mail-composer';
import { ConnectedAccountProvider } from 'twenty-shared/types';
import { assertUnreachable, isDefined } from 'twenty-shared/utils';
@@ -47,12 +48,14 @@ export class MessagingSendMessageService {
connectedAccount,
);
const gmailClient = oAuth2Client.gmail({
const gmailClient = google.gmail({
version: 'v1',
auth: oAuth2Client,
});
const peopleClient = oAuth2Client.people({
const peopleClient = google.people({
version: 'v1',
auth: oAuth2Client,
});
const { data: gmailData } = await gmailClient.users.getProfile({