[CONNECTED_ACCOUNT_BREAKING_CHANGE] Unify connected account permissions (#20732)

# Introduction
This PR is a followup of https://github.com/twentyhq/twenty/pull/20673

It aims to unify the authentication/permissions layer with all the
connectedAccount interactions across the application

## Deprecate
- findAll
- findById

## Email sync
An user can only sync the message of his own connected account

## Workflow email
- Related https://github.com/twentyhq/private-issues/issues/478
- Only reauthorize owned account
This commit is contained in:
Paul Rastoin
2026-05-20 13:36:58 +02:00
committed by GitHub
parent b454ad2aea
commit 3d49c17e34
21 changed files with 258 additions and 297 deletions
@@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CalendarChannelEntity } from 'src/engine/metadata-modules/calendar-channel/entities/calendar-channel.entity';
import { ConnectedAccountMetadataModule } from 'src/engine/metadata-modules/connected-account/connected-account-metadata.module';
import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity';
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
@@ -12,6 +13,7 @@ import { MessagingCommonModule } from 'src/modules/messaging/common/messaging-co
@Module({
imports: [
TypeOrmModule.forFeature([CalendarChannelEntity, MessageChannelEntity]),
ConnectedAccountMetadataModule,
PermissionsModule,
WorkspaceDataSourceModule,
MessagingCommonModule,
@@ -8,9 +8,11 @@ import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorato
import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthUserWorkspaceId } from 'src/engine/decorators/auth/auth-user-workspace-id.decorator';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { ConnectedAccountMetadataService } from 'src/engine/metadata-modules/connected-account/connected-account-metadata.service';
import { ChannelSyncSuccessDTO } from 'src/modules/connected-account/channel-sync/dtos/channel-sync-success.dto';
import { ChannelSyncService } from 'src/modules/connected-account/channel-sync/services/channel-sync.service';
@@ -19,7 +21,10 @@ import { ChannelSyncService } from 'src/modules/connected-account/channel-sync/s
@UseFilters(AuthGraphqlApiExceptionFilter)
@UseGuards(WorkspaceAuthGuard)
export class ChannelSyncResolver {
constructor(private readonly channelSyncService: ChannelSyncService) {}
constructor(
private readonly channelSyncService: ChannelSyncService,
private readonly connectedAccountMetadataService: ConnectedAccountMetadataService,
) {}
@Mutation(() => ChannelSyncSuccessDTO)
@UseGuards(SettingsPermissionGuard(PermissionFlagType.CONNECTED_ACCOUNTS))
@@ -27,7 +32,14 @@ export class ChannelSyncResolver {
@Args('connectedAccountId', { type: () => UUIDScalarType })
connectedAccountId: string,
@AuthWorkspace() workspace: WorkspaceEntity,
@AuthUserWorkspaceId() userWorkspaceId: string,
): Promise<ChannelSyncSuccessDTO> {
await this.connectedAccountMetadataService.verifyOwnership({
id: connectedAccountId,
userWorkspaceId,
workspaceId: workspace.id,
});
await this.channelSyncService.startChannelSync({
connectedAccountId,
workspaceId: workspace.id,