Refactor global datasource part 3 (#16447)
## Context Following https://github.com/twentyhq/twenty/pull/16399 Now using the new global orm manager everywhere and returning a GlobalDatasource/WorkspaceDatasource based on a feature flag. This means we now need to wrap all our ORM calls within executeInWorkspaceContext callback (at least for now) so the global datasource can dynamically hydrate its context via the new store (the global datasource does not store anything related to workspaces as it is now a unique singleton). If feature flag is off it still uses local data stored in the workspace datasource.
This commit is contained in:
+28
-20
@@ -3,7 +3,8 @@ import { Injectable } from '@nestjs/common';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import {
|
||||
CalendarChannelSyncStage,
|
||||
CalendarChannelSyncStatus,
|
||||
@@ -22,7 +23,7 @@ export type CreateCalendarChannelInput = {
|
||||
@Injectable()
|
||||
export class CreateCalendarChannelService {
|
||||
constructor(
|
||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
) {}
|
||||
|
||||
async createCalendarChannel(
|
||||
@@ -36,26 +37,33 @@ export class CreateCalendarChannelService {
|
||||
manager,
|
||||
} = input;
|
||||
|
||||
const calendarChannelRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<CalendarChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'calendarChannel',
|
||||
);
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
const newCalendarChannel = await calendarChannelRepository.save(
|
||||
{
|
||||
id: v4(),
|
||||
connectedAccountId,
|
||||
handle,
|
||||
visibility:
|
||||
calendarVisibility || CalendarChannelVisibility.SHARE_EVERYTHING,
|
||||
syncStatus: CalendarChannelSyncStatus.NOT_SYNCED,
|
||||
syncStage: CalendarChannelSyncStage.PENDING_CONFIGURATION,
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
authContext,
|
||||
async () => {
|
||||
const calendarChannelRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<CalendarChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'calendarChannel',
|
||||
);
|
||||
|
||||
const newCalendarChannel = await calendarChannelRepository.save(
|
||||
{
|
||||
id: v4(),
|
||||
connectedAccountId,
|
||||
handle,
|
||||
visibility:
|
||||
calendarVisibility || CalendarChannelVisibility.SHARE_EVERYTHING,
|
||||
syncStatus: CalendarChannelSyncStatus.NOT_SYNCED,
|
||||
syncStage: CalendarChannelSyncStage.PENDING_CONFIGURATION,
|
||||
},
|
||||
{},
|
||||
manager,
|
||||
);
|
||||
|
||||
return newCalendarChannel.id;
|
||||
},
|
||||
{},
|
||||
manager,
|
||||
);
|
||||
|
||||
return newCalendarChannel.id;
|
||||
}
|
||||
}
|
||||
|
||||
+26
-18
@@ -3,7 +3,8 @@ import { Injectable } from '@nestjs/common';
|
||||
import { type ConnectedAccountProvider } from 'twenty-shared/types';
|
||||
|
||||
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
|
||||
export type CreateConnectedAccountInput = {
|
||||
@@ -21,7 +22,7 @@ export type CreateConnectedAccountInput = {
|
||||
@Injectable()
|
||||
export class CreateConnectedAccountService {
|
||||
constructor(
|
||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
) {}
|
||||
|
||||
async createConnectedAccount(
|
||||
@@ -39,24 +40,31 @@ export class CreateConnectedAccountService {
|
||||
manager,
|
||||
} = input;
|
||||
|
||||
const connectedAccountRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ConnectedAccountWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'connectedAccount',
|
||||
);
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
await connectedAccountRepository.save(
|
||||
{
|
||||
id: connectedAccountId,
|
||||
handle,
|
||||
provider,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
accountOwnerId,
|
||||
scopes,
|
||||
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
authContext,
|
||||
async () => {
|
||||
const connectedAccountRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<ConnectedAccountWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'connectedAccount',
|
||||
);
|
||||
|
||||
await connectedAccountRepository.save(
|
||||
{
|
||||
id: connectedAccountId,
|
||||
handle,
|
||||
provider,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
accountOwnerId,
|
||||
scopes,
|
||||
},
|
||||
{},
|
||||
manager,
|
||||
);
|
||||
},
|
||||
{},
|
||||
manager,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+50
-41
@@ -4,7 +4,8 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
import {
|
||||
MessageChannelPendingGroupEmailsAction,
|
||||
@@ -27,7 +28,7 @@ export type CreateMessageChannelInput = {
|
||||
@Injectable()
|
||||
export class CreateMessageChannelService {
|
||||
constructor(
|
||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
private readonly syncMessageFoldersService: SyncMessageFoldersService,
|
||||
) {}
|
||||
|
||||
@@ -42,49 +43,57 @@ export class CreateMessageChannelService {
|
||||
manager,
|
||||
} = input;
|
||||
|
||||
const connectedAccountRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ConnectedAccountWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'connectedAccount',
|
||||
);
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
const connectedAccount = await connectedAccountRepository.findOne({
|
||||
where: { id: connectedAccountId },
|
||||
});
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
authContext,
|
||||
async () => {
|
||||
const connectedAccountRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<ConnectedAccountWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'connectedAccount',
|
||||
);
|
||||
|
||||
const messageChannelRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<MessageChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'messageChannel',
|
||||
);
|
||||
const connectedAccount = await connectedAccountRepository.findOne({
|
||||
where: { id: connectedAccountId },
|
||||
});
|
||||
|
||||
const newMessageChannel = await messageChannelRepository.save(
|
||||
{
|
||||
id: v4(),
|
||||
connectedAccountId,
|
||||
type: MessageChannelType.EMAIL,
|
||||
handle,
|
||||
visibility:
|
||||
messageVisibility || MessageChannelVisibility.SHARE_EVERYTHING,
|
||||
syncStatus: MessageChannelSyncStatus.NOT_SYNCED,
|
||||
syncStage: MessageChannelSyncStage.PENDING_CONFIGURATION,
|
||||
pendingGroupEmailsAction: MessageChannelPendingGroupEmailsAction.NONE,
|
||||
const messageChannelRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<MessageChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'messageChannel',
|
||||
);
|
||||
|
||||
const newMessageChannel = await messageChannelRepository.save(
|
||||
{
|
||||
id: v4(),
|
||||
connectedAccountId,
|
||||
type: MessageChannelType.EMAIL,
|
||||
handle,
|
||||
visibility:
|
||||
messageVisibility || MessageChannelVisibility.SHARE_EVERYTHING,
|
||||
syncStatus: MessageChannelSyncStatus.NOT_SYNCED,
|
||||
syncStage: MessageChannelSyncStage.PENDING_CONFIGURATION,
|
||||
pendingGroupEmailsAction:
|
||||
MessageChannelPendingGroupEmailsAction.NONE,
|
||||
},
|
||||
{},
|
||||
manager,
|
||||
);
|
||||
|
||||
if (isDefined(connectedAccount)) {
|
||||
await this.syncMessageFoldersService.syncMessageFolders({
|
||||
workspaceId,
|
||||
messageChannel: {
|
||||
...newMessageChannel,
|
||||
connectedAccount,
|
||||
},
|
||||
manager,
|
||||
});
|
||||
}
|
||||
|
||||
return newMessageChannel.id;
|
||||
},
|
||||
{},
|
||||
manager,
|
||||
);
|
||||
|
||||
if (isDefined(connectedAccount)) {
|
||||
await this.syncMessageFoldersService.syncMessageFolders({
|
||||
workspaceId,
|
||||
messageChannel: {
|
||||
...newMessageChannel,
|
||||
connectedAccount,
|
||||
},
|
||||
manager,
|
||||
});
|
||||
}
|
||||
|
||||
return newMessageChannel.id;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -13,7 +13,7 @@ import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queu
|
||||
import { getQueueToken } from 'src/engine/core-modules/message-queue/utils/get-queue-token.util';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { CalendarChannelSyncStatusService } from 'src/modules/calendar/common/services/calendar-channel-sync-status.service';
|
||||
import {
|
||||
CalendarChannelSyncStage,
|
||||
@@ -77,9 +77,9 @@ describe('GoogleAPIsService', () => {
|
||||
providers: [
|
||||
GoogleAPIsService,
|
||||
{
|
||||
provide: TwentyORMGlobalManager,
|
||||
provide: GlobalWorkspaceOrmManager,
|
||||
useValue: {
|
||||
getRepositoryForWorkspace: jest
|
||||
getRepository: jest
|
||||
.fn()
|
||||
.mockImplementation((_workspaceId, entity) => {
|
||||
if (entity === 'connectedAccount')
|
||||
@@ -96,6 +96,9 @@ describe('GoogleAPIsService', () => {
|
||||
getDataSourceForWorkspace: jest
|
||||
.fn()
|
||||
.mockImplementation(() => mockWorkspaceDataSource),
|
||||
executeInWorkspaceContext: jest
|
||||
.fn()
|
||||
.mockImplementation((_authContext: any, fn: () => any) => fn()),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
+157
-150
@@ -17,7 +17,8 @@ import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queu
|
||||
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import {
|
||||
CalendarEventListFetchJob,
|
||||
type CalendarEventListFetchJobData,
|
||||
@@ -45,7 +46,7 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta
|
||||
@Injectable()
|
||||
export class GoogleAPIsService {
|
||||
constructor(
|
||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
@InjectMessageQueue(MessageQueue.messagingQueue)
|
||||
private readonly messageQueueService: MessageQueueService,
|
||||
@InjectMessageQueue(MessageQueue.calendarQueue)
|
||||
@@ -82,36 +83,6 @@ export class GoogleAPIsService {
|
||||
'CALENDAR_PROVIDER_GOOGLE_ENABLED',
|
||||
);
|
||||
|
||||
const connectedAccountRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ConnectedAccountWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'connectedAccount',
|
||||
);
|
||||
|
||||
const connectedAccount = await connectedAccountRepository.findOne({
|
||||
where: { handle, accountOwnerId: workspaceMemberId },
|
||||
});
|
||||
|
||||
const existingAccountId = connectedAccount?.id;
|
||||
const newOrExistingConnectedAccountId = existingAccountId ?? v4();
|
||||
|
||||
const calendarChannelRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<CalendarChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'calendarChannel',
|
||||
);
|
||||
|
||||
const messageChannelRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<MessageChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'messageChannel',
|
||||
);
|
||||
|
||||
const workspaceDataSource =
|
||||
await this.twentyORMGlobalManager.getDataSourceForWorkspace({
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const { scopes, isValid } =
|
||||
await this.googleAPIScopesService.getScopesFromGoogleAccessTokenAndCheckIfExpectedScopesArePresent(
|
||||
input.accessToken,
|
||||
@@ -124,131 +95,167 @@ export class GoogleAPIsService {
|
||||
);
|
||||
}
|
||||
|
||||
await workspaceDataSource.transaction(
|
||||
async (manager: WorkspaceEntityManager) => {
|
||||
if (!existingAccountId) {
|
||||
await this.createConnectedAccountService.createConnectedAccount({
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
provider: ConnectedAccountProvider.GOOGLE,
|
||||
accessToken: input.accessToken,
|
||||
refreshToken: input.refreshToken,
|
||||
accountOwnerId: workspaceMemberId,
|
||||
scopes,
|
||||
manager,
|
||||
});
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
await this.createMessageChannelService.createMessageChannel({
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
authContext,
|
||||
async () => {
|
||||
const connectedAccountRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<ConnectedAccountWorkspaceEntity>(
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
messageVisibility,
|
||||
manager,
|
||||
});
|
||||
'connectedAccount',
|
||||
);
|
||||
|
||||
if (isCalendarEnabled) {
|
||||
await this.createCalendarChannelService.createCalendarChannel({
|
||||
workspaceId,
|
||||
const connectedAccount = await connectedAccountRepository.findOne({
|
||||
where: { handle, accountOwnerId: workspaceMemberId },
|
||||
});
|
||||
|
||||
const existingAccountId = connectedAccount?.id;
|
||||
const newOrExistingConnectedAccountId = existingAccountId ?? v4();
|
||||
|
||||
const calendarChannelRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<CalendarChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'calendarChannel',
|
||||
);
|
||||
|
||||
const messageChannelRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<MessageChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'messageChannel',
|
||||
);
|
||||
|
||||
const workspaceDataSource =
|
||||
await this.globalWorkspaceOrmManager.getDataSourceForWorkspace(
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
await workspaceDataSource.transaction(
|
||||
async (manager: WorkspaceEntityManager) => {
|
||||
if (!existingAccountId) {
|
||||
await this.createConnectedAccountService.createConnectedAccount({
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
provider: ConnectedAccountProvider.GOOGLE,
|
||||
accessToken: input.accessToken,
|
||||
refreshToken: input.refreshToken,
|
||||
accountOwnerId: workspaceMemberId,
|
||||
scopes,
|
||||
manager,
|
||||
});
|
||||
|
||||
await this.createMessageChannelService.createMessageChannel({
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
messageVisibility,
|
||||
manager,
|
||||
});
|
||||
|
||||
if (isCalendarEnabled) {
|
||||
await this.createCalendarChannelService.createCalendarChannel({
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
calendarVisibility,
|
||||
manager,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await this.updateConnectedAccountOnReconnectService.updateConnectedAccountOnReconnect(
|
||||
{
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
accessToken: input.accessToken,
|
||||
refreshToken: input.refreshToken,
|
||||
scopes,
|
||||
connectedAccount,
|
||||
manager,
|
||||
},
|
||||
);
|
||||
|
||||
const workspaceMemberRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<WorkspaceMemberWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'workspaceMember',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
const workspaceMember =
|
||||
await workspaceMemberRepository.findOneOrFail({
|
||||
where: { id: workspaceMemberId },
|
||||
});
|
||||
|
||||
const userId = workspaceMember.userId;
|
||||
|
||||
await this.accountsToReconnectService.removeAccountToReconnect(
|
||||
userId,
|
||||
workspaceId,
|
||||
newOrExistingConnectedAccountId,
|
||||
);
|
||||
|
||||
await this.messagingChannelSyncStatusService.resetAndMarkAsMessagesListFetchPending(
|
||||
[newOrExistingConnectedAccountId],
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
await this.calendarChannelSyncStatusService.resetAndMarkAsCalendarEventListFetchPending(
|
||||
[newOrExistingConnectedAccountId],
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (this.twentyConfigService.get('MESSAGING_PROVIDER_GMAIL_ENABLED')) {
|
||||
const messageChannels = await messageChannelRepository.find({
|
||||
where: {
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
calendarVisibility,
|
||||
manager,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
for (const messageChannel of messageChannels) {
|
||||
if (
|
||||
messageChannel.syncStage !==
|
||||
MessageChannelSyncStage.PENDING_CONFIGURATION
|
||||
) {
|
||||
await this.messageQueueService.add<MessagingMessageListFetchJobData>(
|
||||
MessagingMessageListFetchJob.name,
|
||||
{
|
||||
workspaceId,
|
||||
messageChannelId: messageChannel.id,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await this.updateConnectedAccountOnReconnectService.updateConnectedAccountOnReconnect(
|
||||
{
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
accessToken: input.accessToken,
|
||||
refreshToken: input.refreshToken,
|
||||
scopes,
|
||||
connectedAccount,
|
||||
manager,
|
||||
},
|
||||
);
|
||||
|
||||
const workspaceMemberRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'workspaceMember',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
const workspaceMember = await workspaceMemberRepository.findOneOrFail(
|
||||
{
|
||||
where: { id: workspaceMemberId },
|
||||
},
|
||||
);
|
||||
|
||||
const userId = workspaceMember.userId;
|
||||
|
||||
await this.accountsToReconnectService.removeAccountToReconnect(
|
||||
userId,
|
||||
workspaceId,
|
||||
newOrExistingConnectedAccountId,
|
||||
);
|
||||
|
||||
await this.messagingChannelSyncStatusService.resetAndMarkAsMessagesListFetchPending(
|
||||
[newOrExistingConnectedAccountId],
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
await this.calendarChannelSyncStatusService.resetAndMarkAsCalendarEventListFetchPending(
|
||||
[newOrExistingConnectedAccountId],
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
|
||||
if (isCalendarEnabled) {
|
||||
const calendarChannels = await calendarChannelRepository.find({
|
||||
where: {
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
},
|
||||
});
|
||||
|
||||
for (const calendarChannel of calendarChannels) {
|
||||
if (
|
||||
calendarChannel.syncStage !==
|
||||
CalendarChannelSyncStage.PENDING_CONFIGURATION
|
||||
) {
|
||||
await this.calendarQueueService.add<CalendarEventListFetchJobData>(
|
||||
CalendarEventListFetchJob.name,
|
||||
{
|
||||
calendarChannelId: calendarChannel.id,
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newOrExistingConnectedAccountId;
|
||||
},
|
||||
);
|
||||
|
||||
if (this.twentyConfigService.get('MESSAGING_PROVIDER_GMAIL_ENABLED')) {
|
||||
const messageChannels = await messageChannelRepository.find({
|
||||
where: {
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
},
|
||||
});
|
||||
|
||||
for (const messageChannel of messageChannels) {
|
||||
if (
|
||||
messageChannel.syncStage !==
|
||||
MessageChannelSyncStage.PENDING_CONFIGURATION
|
||||
) {
|
||||
await this.messageQueueService.add<MessagingMessageListFetchJobData>(
|
||||
MessagingMessageListFetchJob.name,
|
||||
{
|
||||
workspaceId,
|
||||
messageChannelId: messageChannel.id,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isCalendarEnabled) {
|
||||
const calendarChannels = await calendarChannelRepository.find({
|
||||
where: {
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
},
|
||||
});
|
||||
|
||||
for (const calendarChannel of calendarChannels) {
|
||||
if (
|
||||
calendarChannel.syncStage !==
|
||||
CalendarChannelSyncStage.PENDING_CONFIGURATION
|
||||
) {
|
||||
await this.calendarQueueService.add<CalendarEventListFetchJobData>(
|
||||
CalendarEventListFetchJob.name,
|
||||
{
|
||||
calendarChannelId: calendarChannel.id,
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newOrExistingConnectedAccountId;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -12,7 +12,7 @@ import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queu
|
||||
import { getQueueToken } from 'src/engine/core-modules/message-queue/utils/get-queue-token.util';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { CalendarChannelSyncStatusService } from 'src/modules/calendar/common/services/calendar-channel-sync-status.service';
|
||||
import {
|
||||
CalendarChannelSyncStage,
|
||||
@@ -76,9 +76,9 @@ describe('MicrosoftAPIsService', () => {
|
||||
providers: [
|
||||
MicrosoftAPIsService,
|
||||
{
|
||||
provide: TwentyORMGlobalManager,
|
||||
provide: GlobalWorkspaceOrmManager,
|
||||
useValue: {
|
||||
getRepositoryForWorkspace: jest
|
||||
getRepository: jest
|
||||
.fn()
|
||||
.mockImplementation((_workspaceId, entity) => {
|
||||
if (entity === 'connectedAccount')
|
||||
@@ -95,6 +95,9 @@ describe('MicrosoftAPIsService', () => {
|
||||
getDataSourceForWorkspace: jest
|
||||
.fn()
|
||||
.mockImplementation(() => mockWorkspaceDataSource),
|
||||
executeInWorkspaceContext: jest
|
||||
.fn()
|
||||
.mockImplementation((_authContext: any, fn: () => any) => fn()),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
+165
-157
@@ -13,7 +13,8 @@ import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queu
|
||||
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import {
|
||||
CalendarEventListFetchJob,
|
||||
type CalendarEventListFetchJobData,
|
||||
@@ -41,7 +42,7 @@ import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/sta
|
||||
@Injectable()
|
||||
export class MicrosoftAPIsService {
|
||||
constructor(
|
||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
@InjectMessageQueue(MessageQueue.messagingQueue)
|
||||
private readonly messageQueueService: MessageQueueService,
|
||||
@InjectMessageQueue(MessageQueue.calendarQueue)
|
||||
@@ -73,170 +74,177 @@ export class MicrosoftAPIsService {
|
||||
messageVisibility,
|
||||
} = input;
|
||||
|
||||
const connectedAccountRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ConnectedAccountWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'connectedAccount',
|
||||
);
|
||||
|
||||
const connectedAccount = await connectedAccountRepository.findOne({
|
||||
where: { handle, accountOwnerId: workspaceMemberId },
|
||||
});
|
||||
|
||||
const existingAccountId = connectedAccount?.id;
|
||||
const newOrExistingConnectedAccountId = existingAccountId ?? v4();
|
||||
|
||||
const calendarChannelRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<CalendarChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'calendarChannel',
|
||||
);
|
||||
|
||||
const messageChannelRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<MessageChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'messageChannel',
|
||||
);
|
||||
|
||||
const workspaceDataSource =
|
||||
await this.twentyORMGlobalManager.getDataSourceForWorkspace({
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const scopes = getMicrosoftApisOauthScopes();
|
||||
|
||||
await workspaceDataSource.transaction(
|
||||
async (manager: WorkspaceEntityManager) => {
|
||||
if (!existingAccountId) {
|
||||
await this.createConnectedAccountService.createConnectedAccount({
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
provider: ConnectedAccountProvider.MICROSOFT,
|
||||
accessToken: input.accessToken,
|
||||
refreshToken: input.refreshToken,
|
||||
accountOwnerId: workspaceMemberId,
|
||||
scopes,
|
||||
manager,
|
||||
});
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
await this.createMessageChannelService.createMessageChannel({
|
||||
return this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
authContext,
|
||||
async () => {
|
||||
const connectedAccountRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<ConnectedAccountWorkspaceEntity>(
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
messageVisibility,
|
||||
manager,
|
||||
});
|
||||
'connectedAccount',
|
||||
);
|
||||
|
||||
if (
|
||||
this.twentyConfigService.get('CALENDAR_PROVIDER_MICROSOFT_ENABLED')
|
||||
) {
|
||||
await this.createCalendarChannelService.createCalendarChannel({
|
||||
workspaceId,
|
||||
const connectedAccount = await connectedAccountRepository.findOne({
|
||||
where: { handle, accountOwnerId: workspaceMemberId },
|
||||
});
|
||||
|
||||
const existingAccountId = connectedAccount?.id;
|
||||
const newOrExistingConnectedAccountId = existingAccountId ?? v4();
|
||||
|
||||
const calendarChannelRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<CalendarChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'calendarChannel',
|
||||
);
|
||||
|
||||
const messageChannelRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<MessageChannelWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'messageChannel',
|
||||
);
|
||||
|
||||
const workspaceDataSource =
|
||||
await this.globalWorkspaceOrmManager.getDataSourceForWorkspace(
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
await workspaceDataSource.transaction(
|
||||
async (manager: WorkspaceEntityManager) => {
|
||||
if (!existingAccountId) {
|
||||
await this.createConnectedAccountService.createConnectedAccount({
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
provider: ConnectedAccountProvider.MICROSOFT,
|
||||
accessToken: input.accessToken,
|
||||
refreshToken: input.refreshToken,
|
||||
accountOwnerId: workspaceMemberId,
|
||||
scopes,
|
||||
manager,
|
||||
});
|
||||
|
||||
await this.createMessageChannelService.createMessageChannel({
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
messageVisibility,
|
||||
manager,
|
||||
});
|
||||
|
||||
if (
|
||||
this.twentyConfigService.get(
|
||||
'CALENDAR_PROVIDER_MICROSOFT_ENABLED',
|
||||
)
|
||||
) {
|
||||
await this.createCalendarChannelService.createCalendarChannel({
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
calendarVisibility,
|
||||
manager,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await this.updateConnectedAccountOnReconnectService.updateConnectedAccountOnReconnect(
|
||||
{
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
accessToken: input.accessToken,
|
||||
refreshToken: input.refreshToken,
|
||||
scopes,
|
||||
connectedAccount,
|
||||
manager,
|
||||
},
|
||||
);
|
||||
|
||||
const workspaceMemberRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<WorkspaceMemberWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'workspaceMember',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
const workspaceMember =
|
||||
await workspaceMemberRepository.findOneOrFail({
|
||||
where: { id: workspaceMemberId },
|
||||
});
|
||||
|
||||
const userId = workspaceMember.userId;
|
||||
|
||||
await this.accountsToReconnectService.removeAccountToReconnect(
|
||||
userId,
|
||||
workspaceId,
|
||||
newOrExistingConnectedAccountId,
|
||||
);
|
||||
|
||||
await this.messagingChannelSyncStatusService.resetAndMarkAsMessagesListFetchPending(
|
||||
[newOrExistingConnectedAccountId],
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
await this.calendarChannelSyncStatusService.resetAndMarkAsCalendarEventListFetchPending(
|
||||
[newOrExistingConnectedAccountId],
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (
|
||||
this.twentyConfigService.get('MESSAGING_PROVIDER_MICROSOFT_ENABLED')
|
||||
) {
|
||||
const messageChannels = await messageChannelRepository.find({
|
||||
where: {
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
handle,
|
||||
calendarVisibility,
|
||||
manager,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
for (const messageChannel of messageChannels) {
|
||||
if (
|
||||
messageChannel.syncStage !==
|
||||
MessageChannelSyncStage.PENDING_CONFIGURATION
|
||||
) {
|
||||
await this.messageQueueService.add<MessagingMessageListFetchJobData>(
|
||||
MessagingMessageListFetchJob.name,
|
||||
{
|
||||
workspaceId,
|
||||
messageChannelId: messageChannel.id,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await this.updateConnectedAccountOnReconnectService.updateConnectedAccountOnReconnect(
|
||||
{
|
||||
workspaceId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
accessToken: input.accessToken,
|
||||
refreshToken: input.refreshToken,
|
||||
scopes,
|
||||
connectedAccount,
|
||||
manager,
|
||||
},
|
||||
);
|
||||
|
||||
const workspaceMemberRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'workspaceMember',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
const workspaceMember = await workspaceMemberRepository.findOneOrFail(
|
||||
{
|
||||
where: { id: workspaceMemberId },
|
||||
},
|
||||
);
|
||||
|
||||
const userId = workspaceMember.userId;
|
||||
|
||||
await this.accountsToReconnectService.removeAccountToReconnect(
|
||||
userId,
|
||||
workspaceId,
|
||||
newOrExistingConnectedAccountId,
|
||||
);
|
||||
|
||||
await this.messagingChannelSyncStatusService.resetAndMarkAsMessagesListFetchPending(
|
||||
[newOrExistingConnectedAccountId],
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
await this.calendarChannelSyncStatusService.resetAndMarkAsCalendarEventListFetchPending(
|
||||
[newOrExistingConnectedAccountId],
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
await this.calendarChannelSyncStatusService.resetAndMarkAsCalendarEventListFetchPending(
|
||||
[newOrExistingConnectedAccountId],
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
this.twentyConfigService.get('CALENDAR_PROVIDER_MICROSOFT_ENABLED')
|
||||
) {
|
||||
const calendarChannels = await calendarChannelRepository.find({
|
||||
where: {
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
},
|
||||
});
|
||||
|
||||
for (const calendarChannel of calendarChannels) {
|
||||
if (
|
||||
calendarChannel.syncStage !==
|
||||
CalendarChannelSyncStage.PENDING_CONFIGURATION
|
||||
) {
|
||||
await this.calendarQueueService.add<CalendarEventListFetchJobData>(
|
||||
CalendarEventListFetchJob.name,
|
||||
{
|
||||
calendarChannelId: calendarChannel.id,
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newOrExistingConnectedAccountId;
|
||||
},
|
||||
);
|
||||
|
||||
if (this.twentyConfigService.get('MESSAGING_PROVIDER_MICROSOFT_ENABLED')) {
|
||||
const messageChannels = await messageChannelRepository.find({
|
||||
where: {
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
},
|
||||
});
|
||||
|
||||
for (const messageChannel of messageChannels) {
|
||||
if (
|
||||
messageChannel.syncStage !==
|
||||
MessageChannelSyncStage.PENDING_CONFIGURATION
|
||||
) {
|
||||
await this.messageQueueService.add<MessagingMessageListFetchJobData>(
|
||||
MessagingMessageListFetchJob.name,
|
||||
{
|
||||
workspaceId,
|
||||
messageChannelId: messageChannel.id,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.twentyConfigService.get('CALENDAR_PROVIDER_MICROSOFT_ENABLED')) {
|
||||
const calendarChannels = await calendarChannelRepository.find({
|
||||
where: {
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
},
|
||||
});
|
||||
|
||||
for (const calendarChannel of calendarChannels) {
|
||||
if (
|
||||
calendarChannel.syncStage !==
|
||||
CalendarChannelSyncStage.PENDING_CONFIGURATION
|
||||
) {
|
||||
await this.calendarQueueService.add<CalendarEventListFetchJobData>(
|
||||
CalendarEventListFetchJob.name,
|
||||
{
|
||||
calendarChannelId: calendarChannel.id,
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newOrExistingConnectedAccountId;
|
||||
}
|
||||
}
|
||||
|
||||
+25
-17
@@ -1,7 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { type WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import { type ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||
|
||||
export type UpdateConnectedAccountOnReconnectInput = {
|
||||
@@ -17,7 +18,7 @@ export type UpdateConnectedAccountOnReconnectInput = {
|
||||
@Injectable()
|
||||
export class UpdateConnectedAccountOnReconnectService {
|
||||
constructor(
|
||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
) {}
|
||||
|
||||
async updateConnectedAccountOnReconnect(
|
||||
@@ -32,23 +33,30 @@ export class UpdateConnectedAccountOnReconnectService {
|
||||
manager,
|
||||
} = input;
|
||||
|
||||
const connectedAccountRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ConnectedAccountWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'connectedAccount',
|
||||
);
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
await connectedAccountRepository.update(
|
||||
{
|
||||
id: connectedAccountId,
|
||||
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
authContext,
|
||||
async () => {
|
||||
const connectedAccountRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<ConnectedAccountWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'connectedAccount',
|
||||
);
|
||||
|
||||
await connectedAccountRepository.update(
|
||||
{
|
||||
id: connectedAccountId,
|
||||
},
|
||||
{
|
||||
accessToken,
|
||||
refreshToken,
|
||||
scopes,
|
||||
authFailedAt: null,
|
||||
},
|
||||
manager,
|
||||
);
|
||||
},
|
||||
{
|
||||
accessToken,
|
||||
refreshToken,
|
||||
scopes,
|
||||
authFailedAt: null,
|
||||
},
|
||||
manager,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+15
-16
@@ -17,7 +17,7 @@ import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user
|
||||
import { UserEntity } from 'src/engine/core-modules/user/user.entity';
|
||||
import { AuthProviderEnum } from 'src/engine/core-modules/workspace/types/workspace.type';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
|
||||
import { AccessTokenService } from './access-token.service';
|
||||
|
||||
@@ -27,7 +27,7 @@ describe('AccessTokenService', () => {
|
||||
let twentyConfigService: TwentyConfigService;
|
||||
let userRepository: Repository<UserEntity>;
|
||||
let workspaceRepository: Repository<WorkspaceEntity>;
|
||||
let twentyORMGlobalManager: TwentyORMGlobalManager;
|
||||
let globalWorkspaceOrmManager: GlobalWorkspaceOrmManager;
|
||||
let userWorkspaceRepository: Repository<UserWorkspaceEntity>;
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -77,9 +77,12 @@ describe('AccessTokenService', () => {
|
||||
useValue: {},
|
||||
},
|
||||
{
|
||||
provide: TwentyORMGlobalManager,
|
||||
provide: GlobalWorkspaceOrmManager,
|
||||
useValue: {
|
||||
getRepositoryForWorkspace: jest.fn(),
|
||||
getRepository: jest.fn(),
|
||||
executeInWorkspaceContext: jest
|
||||
.fn()
|
||||
.mockImplementation((_authContext: any, fn: () => any) => fn()),
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -94,8 +97,8 @@ describe('AccessTokenService', () => {
|
||||
workspaceRepository = module.get<Repository<WorkspaceEntity>>(
|
||||
getRepositoryToken(WorkspaceEntity),
|
||||
);
|
||||
twentyORMGlobalManager = module.get<TwentyORMGlobalManager>(
|
||||
TwentyORMGlobalManager,
|
||||
globalWorkspaceOrmManager = module.get<GlobalWorkspaceOrmManager>(
|
||||
GlobalWorkspaceOrmManager,
|
||||
);
|
||||
userWorkspaceRepository = module.get<Repository<UserWorkspaceEntity>>(
|
||||
getRepositoryToken(UserWorkspaceEntity),
|
||||
@@ -131,11 +134,9 @@ describe('AccessTokenService', () => {
|
||||
jest
|
||||
.spyOn(userWorkspaceRepository, 'findOne')
|
||||
.mockResolvedValue(mockUserWorkspace as UserWorkspaceEntity);
|
||||
jest
|
||||
.spyOn(twentyORMGlobalManager, 'getRepositoryForWorkspace')
|
||||
.mockResolvedValue({
|
||||
findOne: jest.fn().mockResolvedValue(mockWorkspaceMember),
|
||||
} as any);
|
||||
jest.spyOn(globalWorkspaceOrmManager, 'getRepository').mockResolvedValue({
|
||||
findOne: jest.fn().mockResolvedValue(mockWorkspaceMember),
|
||||
} as any);
|
||||
jest.spyOn(jwtWrapperService, 'sign').mockReturnValue(mockToken);
|
||||
|
||||
const result = await service.generateAccessToken({
|
||||
@@ -192,11 +193,9 @@ describe('AccessTokenService', () => {
|
||||
id: impersonatedUserWorkspaceId,
|
||||
workspaceId,
|
||||
} as UserWorkspaceEntity);
|
||||
jest
|
||||
.spyOn(twentyORMGlobalManager, 'getRepositoryForWorkspace')
|
||||
.mockResolvedValue({
|
||||
findOne: jest.fn().mockResolvedValue(mockWorkspaceMember),
|
||||
} as any);
|
||||
jest.spyOn(globalWorkspaceOrmManager, 'getRepository').mockResolvedValue({
|
||||
findOne: jest.fn().mockResolvedValue(mockWorkspaceMember),
|
||||
} as any);
|
||||
const signSpy = jest
|
||||
.spyOn(jwtWrapperService, 'sign')
|
||||
.mockReturnValue(mockToken);
|
||||
|
||||
+33
-24
@@ -28,7 +28,8 @@ import { UserEntity } from 'src/engine/core-modules/user/user.entity';
|
||||
import { userValidator } from 'src/engine/core-modules/user/user.validate';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
|
||||
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||
|
||||
@Injectable()
|
||||
@@ -41,7 +42,7 @@ export class AccessTokenService {
|
||||
private readonly userRepository: Repository<UserEntity>,
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
private readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
private readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
@InjectRepository(UserWorkspaceEntity)
|
||||
private readonly userWorkspaceRepository: Repository<UserWorkspaceEntity>,
|
||||
) {}
|
||||
@@ -79,31 +80,39 @@ export class AccessTokenService {
|
||||
assertIsDefinedOrThrow(workspace, WorkspaceNotFoundDefaultError);
|
||||
|
||||
if (isWorkspaceActiveOrSuspended(workspace)) {
|
||||
const workspaceMemberRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'workspaceMember',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
const authContext = buildSystemAuthContext(workspaceId);
|
||||
|
||||
const workspaceMember = await workspaceMemberRepository.findOne({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
tokenWorkspaceMemberId =
|
||||
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
authContext,
|
||||
async () => {
|
||||
const workspaceMemberRepository =
|
||||
await this.globalWorkspaceOrmManager.getRepository<WorkspaceMemberWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'workspaceMember',
|
||||
{ shouldBypassPermissionChecks: true },
|
||||
);
|
||||
|
||||
assertIsDefinedOrThrow(
|
||||
workspaceMember,
|
||||
new AuthException(
|
||||
'User is not a member of the workspace',
|
||||
AuthExceptionCode.FORBIDDEN_EXCEPTION,
|
||||
{
|
||||
userFriendlyMessage: msg`User is not a member of the workspace.`,
|
||||
const workspaceMember = await workspaceMemberRepository.findOne({
|
||||
where: {
|
||||
userId: user.id,
|
||||
},
|
||||
});
|
||||
|
||||
assertIsDefinedOrThrow(
|
||||
workspaceMember,
|
||||
new AuthException(
|
||||
'User is not a member of the workspace',
|
||||
AuthExceptionCode.FORBIDDEN_EXCEPTION,
|
||||
{
|
||||
userFriendlyMessage: msg`User is not a member of the workspace.`,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
return workspaceMember.id;
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
tokenWorkspaceMemberId = workspaceMember.id;
|
||||
);
|
||||
}
|
||||
const userWorkspace = await this.userWorkspaceRepository.findOne({
|
||||
where: {
|
||||
|
||||
Reference in New Issue
Block a user