BREAKING CHANGE: Fix graphql errors (#12775)

We were using a global ValidationPipe in main.ts. This is an issue as
@Controllers should return HttpExecption and @Resolvers should return
GraphqlErrors

Removing the global pipe and creating a ResolverValidationPipe able to
generate GraphqlError. We also need to handle the exception in a filter
to avoid nest to think it's unhandled and make it flow to logs


Next step:
- it would be nice to have both @UsePipes(ResolverValidationPipe) +
@UseFilters(GraphqlValidationExceptionFilter) come together. This should
be possible if we create a @GraphQLResolver annotation
This commit is contained in:
Charles Bochet
2025-06-23 11:23:16 +02:00
committed by GitHub
parent 8e30da99e9
commit b76dac2ca1
36 changed files with 263 additions and 146 deletions

View File

@ -19,7 +19,7 @@ const StyledTbody = styled.tbody`
tr:not(:last-child) td:nth-of-type(3) {
// Last row is aggregate footer
position: sticky;
left: 43px;
left: 39px;
z-index: ${TABLE_Z_INDEX.cell.sticky};
transition: transform 0.3s ease;

View File

@ -40,7 +40,7 @@ const StyledTableHead = styled.thead`
th:nth-of-type(3) {
position: sticky;
left: 43px;
left: 39px;
z-index: ${TABLE_Z_INDEX.header.default};
transition: 0.3s ease;

View File

@ -1,4 +1,4 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import GraphQLJSON from 'graphql-type-json';
@ -18,6 +18,8 @@ import { QueueMetricsTimeRange } from 'src/engine/core-modules/admin-panel/enums
import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter';
import { FeatureFlagException } from 'src/engine/core-modules/feature-flag/feature-flag.exception';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { UserInputError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
import { HealthIndicatorId } from 'src/engine/core-modules/health/enums/health-indicator-id.enum';
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
@ -32,9 +34,11 @@ import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { AdminPanelHealthServiceData } from './dtos/admin-panel-health-service-data.dto';
import { QueueMetricsData } from './dtos/queue-metrics-data.dto';
@UsePipes(ResolverValidationPipe)
@Resolver()
@UseFilters(
AuthGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
ConfigVariableGraphqlApiExceptionFilter,
)
export class AdminPanelResolver {

View File

@ -1,4 +1,4 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { ApprovedAccessDomainExceptionFilter } from 'src/engine/core-modules/approved-access-domain/approved-access-domain-exception-filter';
@ -7,16 +7,22 @@ import { CreateApprovedAccessDomainInput } from 'src/engine/core-modules/approve
import { DeleteApprovedAccessDomainInput } from 'src/engine/core-modules/approved-access-domain/dtos/delete-approved-access-domain.input';
import { ValidateApprovedAccessDomainInput } from 'src/engine/core-modules/approved-access-domain/dtos/validate-approved-access-domain.input';
import { ApprovedAccessDomainService } from 'src/engine/core-modules/approved-access-domain/services/approved-access-domain.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { User } from 'src/engine/core-modules/user/user.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
@UseGuards(WorkspaceAuthGuard)
@UseFilters(ApprovedAccessDomainExceptionFilter)
@UsePipes(ResolverValidationPipe)
@UseFilters(
ApprovedAccessDomainExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
@Resolver()
export class ApprovedAccessDomainResolver {
constructor(

View File

@ -1,4 +1,4 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { AuditExceptionFilter } from 'src/engine/core-modules/audit/audit-exception-filter';
@ -7,6 +7,8 @@ import {
AuditExceptionCode,
} from 'src/engine/core-modules/audit/audit.exception';
import { CreateObjectEventInput } from 'src/engine/core-modules/audit/dtos/create-object-event.input';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { User } from 'src/engine/core-modules/user/user.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
@ -23,7 +25,8 @@ import { Analytics } from './entities/analytics.entity';
import { AuditService } from './services/audit.service';
@Resolver(() => Analytics)
@UseFilters(AuditExceptionFilter)
@UsePipes(ResolverValidationPipe)
@UseFilters(AuditExceptionFilter, PreventNestToAutoLogGraphqlErrorsFilter)
export class AuditResolver {
constructor(private readonly auditService: AuditService) {}

View File

@ -1,4 +1,4 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Context, Mutation, Query, Resolver } from '@nestjs/graphql';
import { InjectRepository } from '@nestjs/typeorm';
@ -44,6 +44,8 @@ import { CaptchaGuard } from 'src/engine/core-modules/captcha/captcha.guard';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { EmailVerificationExceptionFilter } from 'src/engine/core-modules/email-verification/email-verification-exception-filter.util';
import { EmailVerificationService } from 'src/engine/core-modules/email-verification/services/email-verification.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.type';
import { SSOService } from 'src/engine/core-modules/sso/services/sso.service';
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
@ -73,11 +75,13 @@ import { WorkspaceInviteHashValid } from './dto/workspace-invite-hash-valid.enti
import { WorkspaceInviteHashValidInput } from './dto/workspace-invite-hash.input';
import { AuthService } from './services/auth.service';
@UsePipes(ResolverValidationPipe)
@Resolver()
@UseFilters(
AuthGraphqlApiExceptionFilter,
PermissionsGraphqlApiExceptionFilter,
EmailVerificationExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
export class AuthResolver {
constructor(

View File

@ -1,6 +1,6 @@
/* @license Enterprise */
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { isDefined } from 'twenty-shared/utils';
@ -21,6 +21,8 @@ import { BillingUsageService } from 'src/engine/core-modules/billing/services/bi
import { BillingService } from 'src/engine/core-modules/billing/services/billing.service';
import { BillingPortalCheckoutSessionParameters } from 'src/engine/core-modules/billing/types/billing-portal-checkout-session-parameters.type';
import { formatBillingDatabaseProductToGraphqlDTO } from 'src/engine/core-modules/billing/utils/format-database-product-to-graphql-dto.util';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { User } from 'src/engine/core-modules/user/user.entity';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthApiKey } from 'src/engine/decorators/auth/auth-api-key.decorator';
@ -40,7 +42,11 @@ import { PermissionsService } from 'src/engine/metadata-modules/permissions/perm
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
@Resolver()
@UseFilters(PermissionsGraphqlApiExceptionFilter)
@UsePipes(ResolverValidationPipe)
@UseFilters(
PermissionsGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
export class BillingResolver {
constructor(
private readonly billingSubscriptionService: BillingSubscriptionService,

View File

@ -3,13 +3,12 @@ import { Module } from '@nestjs/common';
import { DomainManagerModule } from 'src/engine/core-modules/domain-manager/domain-manager.module';
import { ClientConfigController } from './client-config.controller';
import { ClientConfigResolver } from './client-config.resolver';
import { ClientConfigService } from './services/client-config.service';
@Module({
imports: [DomainManagerModule],
controllers: [ClientConfigController],
providers: [ClientConfigResolver, ClientConfigService],
providers: [ClientConfigService],
})
export class ClientConfigModule {}

View File

@ -1,29 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ClientConfigService } from 'src/engine/core-modules/client-config/services/client-config.service';
import { ClientConfigResolver } from './client-config.resolver';
describe('ClientConfigResolver', () => {
let resolver: ClientConfigResolver;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ClientConfigResolver,
{
provide: ClientConfigService,
useValue: {
getClientConfig: jest.fn(),
},
},
],
}).compile();
resolver = module.get<ClientConfigResolver>(ClientConfigResolver);
});
it('should be defined', () => {
expect(resolver).toBeDefined();
});
});

View File

@ -1,18 +0,0 @@
import { UseGuards } from '@nestjs/common';
import { Query, Resolver } from '@nestjs/graphql';
import { ClientConfigService } from 'src/engine/core-modules/client-config/services/client-config.service';
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
import { ClientConfig } from './client-config.entity';
@Resolver()
export class ClientConfigResolver {
constructor(private clientConfigService: ClientConfigService) {}
@Query(() => ClientConfig)
@UseGuards(PublicEndpointGuard)
async clientConfig(): Promise<ClientConfig> {
return this.clientConfigService.getClientConfig();
}
}

View File

@ -1,4 +1,4 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Context, Mutation, Resolver } from '@nestjs/graphql';
import { SOURCE_LOCALE } from 'twenty-shared/translations';
@ -8,11 +8,17 @@ import { ResendEmailVerificationTokenInput } from 'src/engine/core-modules/email
import { ResendEmailVerificationTokenOutput } from 'src/engine/core-modules/email-verification/dtos/resend-email-verification-token.output';
import { EmailVerificationExceptionFilter } from 'src/engine/core-modules/email-verification/email-verification-exception-filter.util';
import { EmailVerificationService } from 'src/engine/core-modules/email-verification/services/email-verification.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.type';
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
@Resolver()
@UseFilters(EmailVerificationExceptionFilter)
@UsePipes(ResolverValidationPipe)
@UseFilters(
EmailVerificationExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
export class EmailVerificationResolver {
constructor(
private readonly emailVerificationService: EmailVerificationService,

View File

@ -1,18 +1,22 @@
import { UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { FileUpload, GraphQLUpload } from 'graphql-upload';
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
import { SignedFileDTO } from 'src/engine/core-modules/file/file-upload/dtos/signed-file.dto';
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { streamToBuffer } from 'src/utils/stream-to-buffer';
import { SignedFileDTO } from 'src/engine/core-modules/file/file-upload/dtos/signed-file.dto';
@UseGuards(WorkspaceAuthGuard)
@UsePipes(ResolverValidationPipe)
@UseFilters(PreventNestToAutoLogGraphqlErrorsFilter)
@Resolver()
export class FileUploadResolver {
constructor(private readonly fileUploadService: FileUploadService) {}

View File

@ -1,11 +1,12 @@
import { Module } from '@nestjs/common';
import { useGraphQLErrorHandlerHook } from 'src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook';
import { ExceptionHandlerModule } from 'src/engine/core-modules/exception-handler/exception-handler.module';
import { useGraphQLErrorHandlerHook } from 'src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
@Module({
imports: [ExceptionHandlerModule],
exports: [useGraphQLErrorHandlerHook],
providers: [],
exports: [useGraphQLErrorHandlerHook, ResolverValidationPipe],
providers: [ResolverValidationPipe],
})
export class EngineGraphQLModule {}

View File

@ -0,0 +1,17 @@
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
import { GraphQLError } from 'graphql';
/**
* In NestJS, if an exception is not handled, it will shown in the logs
* This filter is used to prevent NestJS from auto-logging GraphQL errors
* and leave it to the GraphQL layer to handle the error.
*/
@Catch(GraphQLError)
export class PreventNestToAutoLogGraphqlErrorsFilter
implements ExceptionFilter
{
catch(exception: GraphQLError, _host: ArgumentsHost) {
return exception;
}
}

View File

@ -0,0 +1,58 @@
import {
ArgumentMetadata,
Injectable,
PipeTransform,
Type,
} from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { ValidationError, validate } from 'class-validator';
import { UserInputError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
@Injectable()
export class ResolverValidationPipe implements PipeTransform {
async transform(value: unknown, metadata: ArgumentMetadata) {
const { metatype } = metadata;
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToInstance(metatype, value);
try {
const errors = await validate(object);
if (errors.length > 0) {
const errorMessage = this.formatErrorMessage(errors);
throw new UserInputError(errorMessage);
}
} catch (error) {
// If the element is not a class, we can't validate it
return value;
}
return value;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private toValidate(metatype: Type<any>): boolean {
const types: unknown[] = [String, Boolean, Number, Array, Object];
return !types.includes(metatype);
}
private formatErrorMessage(errors: ValidationError[]): string {
const messages = errors.flatMap((error) => {
if (error.constraints) {
return Object.values(error.constraints);
}
return [];
});
return messages.join(', ');
}
}

View File

@ -1,10 +1,12 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter';
import { FeatureFlagDTO } from 'src/engine/core-modules/feature-flag/dtos/feature-flag-dto';
import { FeatureFlagException } from 'src/engine/core-modules/feature-flag/feature-flag.exception';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { UserInputError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
import { UpdateLabPublicFeatureFlagInput } from 'src/engine/core-modules/lab/dtos/update-lab-public-feature-flag.input';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
@ -15,7 +17,12 @@ import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/c
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
@Resolver()
@UseFilters(AuthGraphqlApiExceptionFilter, PermissionsGraphqlApiExceptionFilter)
@UsePipes(ResolverValidationPipe)
@UseFilters(
AuthGraphqlApiExceptionFilter,
PermissionsGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
@UseGuards(SettingsPermissionsGuard(SettingPermissionType.WORKSPACE))
export class LabResolver {
constructor(private featureFlagService: FeatureFlagService) {}

View File

@ -1,6 +1,8 @@
import { UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Mutation, Resolver } from '@nestjs/graphql';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { OnboardingStepSuccess } from 'src/engine/core-modules/onboarding/dtos/onboarding-step-success.dto';
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
import { User } from 'src/engine/core-modules/user/user.entity';
@ -11,6 +13,8 @@ import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
@UseGuards(WorkspaceAuthGuard, UserAuthGuard)
@UsePipes(ResolverValidationPipe)
@UseFilters(PreventNestToAutoLogGraphqlErrorsFilter)
@Resolver()
export class OnboardingResolver {
constructor(private readonly onboardingService: OnboardingService) {}

View File

@ -1,6 +1,8 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Query, Resolver } from '@nestjs/graphql';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { SearchArgs } from 'src/engine/core-modules/search/dtos/search-args';
import { SearchResultConnectionDTO } from 'src/engine/core-modules/search/dtos/search-result-connection.dto';
import { SearchApiExceptionFilter } from 'src/engine/core-modules/search/filters/search-api-exception.filter';
@ -10,7 +12,8 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
@Resolver()
@UseFilters(SearchApiExceptionFilter)
@UseFilters(SearchApiExceptionFilter, PreventNestToAutoLogGraphqlErrorsFilter)
@UsePipes(ResolverValidationPipe)
export class SearchResolver {
constructor(private readonly searchService: SearchService) {}

View File

@ -1,9 +1,11 @@
/* @license Enterprise */
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { EnterpriseFeaturesEnabledGuard } from 'src/engine/core-modules/auth/guards/enterprise-features-enabled.guard';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { DeleteSsoInput } from 'src/engine/core-modules/sso/dtos/delete-sso.input';
import { DeleteSsoOutput } from 'src/engine/core-modules/sso/dtos/delete-sso.output';
import { EditSsoInput } from 'src/engine/core-modules/sso/dtos/edit-sso.input';
@ -24,7 +26,11 @@ import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/c
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
@Resolver()
@UseFilters(PermissionsGraphqlApiExceptionFilter)
@UseFilters(
PermissionsGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
@UsePipes(ResolverValidationPipe)
@UseGuards(SettingsPermissionsGuard(SettingPermissionType.SECURITY))
export class SSOResolver {
constructor(private readonly sSOService: SSOService) {}

View File

@ -1,17 +1,21 @@
import { UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Resolver } from '@nestjs/graphql';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service';
@UseGuards(WorkspaceAuthGuard)
@Resolver(() => UserWorkspace)
@UsePipes(ResolverValidationPipe)
@UseFilters(PreventNestToAutoLogGraphqlErrorsFilter)
export class UserWorkspaceResolver {
constructor(
@InjectRepository(Workspace, 'core')

View File

@ -1,8 +1,10 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import graphqlTypeJson from 'graphql-type-json';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { ComputeStepOutputSchemaInput } from 'src/engine/core-modules/workflow/dtos/compute-step-output-schema-input.dto';
import { WorkflowTriggerGraphqlApiExceptionFilter } from 'src/engine/core-modules/workflow/filters/workflow-trigger-graphql-api-exception.filter';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
@ -21,9 +23,11 @@ import { WorkflowSchemaWorkspaceService } from 'src/modules/workflow/workflow-bu
UserAuthGuard,
SettingsPermissionsGuard(SettingPermissionType.WORKFLOWS),
)
@UsePipes(ResolverValidationPipe)
@UseFilters(
WorkflowTriggerGraphqlApiExceptionFilter,
PermissionsGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
export class WorkflowBuilderResolver {
constructor(

View File

@ -1,8 +1,10 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { CreateWorkflowVersionStepInput } from 'src/engine/core-modules/workflow/dtos/create-workflow-version-step-input.dto';
import { DeleteWorkflowVersionStepInput } from 'src/engine/core-modules/workflow/dtos/delete-workflow-version-step-input.dto';
import { SubmitFormStepInput } from 'src/engine/core-modules/workflow/dtos/submit-form-step-input.dto';
@ -21,12 +23,16 @@ import { WorkflowActionType } from 'src/modules/workflow/workflow-executor/workf
import { WorkflowRunWorkspaceService } from 'src/modules/workflow/workflow-runner/workflow-run/workflow-run.workspace-service';
@Resolver()
@UsePipes(ResolverValidationPipe)
@UseGuards(
WorkspaceAuthGuard,
UserAuthGuard,
SettingsPermissionsGuard(SettingPermissionType.WORKFLOWS),
)
@UseFilters(PermissionsGraphqlApiExceptionFilter)
@UseFilters(
PermissionsGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
export class WorkflowStepResolver {
constructor(
private readonly workflowVersionStepWorkspaceService: WorkflowVersionStepWorkspaceService,

View File

@ -1,22 +1,24 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { buildCreatedByFromFullNameMetadata } from 'src/engine/core-modules/actor/utils/build-created-by-from-full-name-metadata.util';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { User } from 'src/engine/core-modules/user/user.entity';
import { RunWorkflowVersionInput } from 'src/engine/core-modules/workflow/dtos/run-workflow-version-input.dto';
import { WorkflowRunDTO } from 'src/engine/core-modules/workflow/dtos/workflow-run.dto';
import { WorkflowTriggerGraphqlApiExceptionFilter } from 'src/engine/core-modules/workflow/filters/workflow-trigger-graphql-api-exception.filter';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { WorkflowTriggerWorkspaceService } from 'src/modules/workflow/workflow-trigger/workspace-services/workflow-trigger.workspace-service';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
@Resolver()
@UseGuards(
@ -24,9 +26,11 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
UserAuthGuard,
SettingsPermissionsGuard(SettingPermissionType.WORKFLOWS),
)
@UsePipes(ResolverValidationPipe)
@UseFilters(
WorkflowTriggerGraphqlApiExceptionFilter,
PermissionsGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
export class WorkflowTriggerResolver {
constructor(

View File

@ -1,6 +1,8 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Resolver } from '@nestjs/graphql';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { CreateDraftFromWorkflowVersionInput } from 'src/engine/core-modules/workflow/dtos/create-draft-from-workflow-version-input';
import { WorkflowVersionDTO } from 'src/engine/core-modules/workflow/dtos/workflow-version.dto';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
@ -13,12 +15,16 @@ import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-module
import { WorkflowVersionWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version/workflow-version.workspace-service';
@Resolver()
@UsePipes(ResolverValidationPipe)
@UseGuards(
WorkspaceAuthGuard,
UserAuthGuard,
SettingsPermissionsGuard(SettingPermissionType.WORKFLOWS),
)
@UseFilters(PermissionsGraphqlApiExceptionFilter)
@UseFilters(
PermissionsGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
export class WorkflowVersionResolver {
constructor(
private readonly workflowVersionWorkspaceService: WorkflowVersionWorkspaceService,

View File

@ -1,7 +1,9 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { FileService } from 'src/engine/core-modules/file/services/file.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { User } from 'src/engine/core-modules/user/user.entity';
import { SendInvitationsOutput } from 'src/engine/core-modules/workspace-invitation/dtos/send-invitations.output';
import { WorkspaceInvitation } from 'src/engine/core-modules/workspace-invitation/dtos/workspace-invitation.dto';
@ -14,8 +16,8 @@ import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { SendInvitationsInput } from './dtos/send-invitations.input';
@ -23,7 +25,11 @@ import { SendInvitationsInput } from './dtos/send-invitations.input';
WorkspaceAuthGuard,
SettingsPermissionsGuard(SettingPermissionType.WORKSPACE_MEMBERS),
)
@UseFilters(PermissionsGraphqlApiExceptionFilter)
@UsePipes(ResolverValidationPipe)
@UseFilters(
PermissionsGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
@Resolver()
export class WorkspaceInvitationResolver {
constructor(

View File

@ -2,6 +2,7 @@ import {
ExecutionContext,
UseFilters,
UseGuards,
UsePipes,
createParamDecorator,
} from '@nestjs/common';
import {
@ -32,6 +33,8 @@ import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/service
import { SignedFileDTO } from 'src/engine/core-modules/file/file-upload/dtos/signed-file.dto';
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
import { FileService } from 'src/engine/core-modules/file/services/file.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
import { User } from 'src/engine/core-modules/user/user.entity';
@ -57,7 +60,6 @@ import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/c
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto';
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
import { GraphqlValidationExceptionFilter } from 'src/filters/graphql-validation-exception.filter';
import { getRequest } from 'src/utils/extract-request';
import { streamToBuffer } from 'src/utils/stream-to-buffer';
@ -74,8 +76,9 @@ const OriginHeader = createParamDecorator(
);
@Resolver(() => Workspace)
@UsePipes(ResolverValidationPipe)
@UseFilters(
GraphqlValidationExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
PermissionsGraphqlApiExceptionFilter,
)
export class WorkspaceResolver {

View File

@ -21,7 +21,6 @@ import {
IsOptional,
IsString,
IsUUID,
Validate,
} from 'class-validator';
import { GraphQLJSON } from 'graphql-type-json';
import { FieldMetadataType } from 'twenty-shared/types';
@ -34,8 +33,6 @@ import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/
import { IsValidMetadataName } from 'src/engine/decorators/metadata/is-valid-metadata-name.decorator';
import { FieldStandardOverridesDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-standard-overrides.dto';
import { FieldMetadataDefaultOption } from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
import { IsFieldMetadataDefaultValue } from 'src/engine/metadata-modules/field-metadata/validators/is-field-metadata-default-value.validator';
import { IsFieldMetadataOptions } from 'src/engine/metadata-modules/field-metadata/validators/is-field-metadata-options.validator';
import { ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
import { transformEnumValue } from 'src/engine/utils/transform-enum-value';
@ -120,7 +117,9 @@ export class FieldMetadataDTO<T extends FieldMetadataType = FieldMetadataType> {
@Field({ nullable: true })
isUnique?: boolean;
@Validate(IsFieldMetadataDefaultValue)
// TODO: This validator was not used anymore, and it is since graphql error hadling refactoring
// it is adding extra load on the database, we are still validing inputs on field update and create
// @Validate(IsFieldMetadataDefaultValue)
@IsOptional()
@Field(() => GraphQLJSON, { nullable: true })
defaultValue?: FieldMetadataDefaultValue<T>;
@ -128,7 +127,9 @@ export class FieldMetadataDTO<T extends FieldMetadataType = FieldMetadataType> {
@Transform(({ value }) =>
transformEnumValue(value as FieldMetadataDefaultOption[]),
)
@Validate(IsFieldMetadataOptions)
// TODO: This validator was not used anymore, and it is since graphql error hadling refactoring
// it is adding extra load on the database, we are still validing inputs on field update and create
// @Validate(IsFieldMetadataOptions)
@IsOptional()
@Field(() => GraphQLJSON, { nullable: true })
options?: FieldMetadataOptions<T>;

View File

@ -1,4 +1,4 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import {
Args,
Context,
@ -10,6 +10,8 @@ import {
import { FieldMetadataType } from 'twenty-shared/types';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import {
ForbiddenError,
ValidationError,
@ -41,8 +43,12 @@ import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-module
import { isRelationFieldMetadataType } from 'src/engine/utils/is-relation-field-metadata-type.util';
@UseGuards(WorkspaceAuthGuard)
@UsePipes(ResolverValidationPipe)
@Resolver(() => FieldMetadataDTO)
@UseFilters(PermissionsGraphqlApiExceptionFilter)
@UseFilters(
PermissionsGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
export class FieldMetadataResolver {
constructor(
private readonly fieldMetadataService: FieldMetadataService,

View File

@ -1,4 +1,4 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import {
Args,
Context,
@ -8,6 +8,8 @@ import {
Resolver,
} from '@nestjs/graphql';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.type';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { IDataloaders } from 'src/engine/dataloaders/dataloader.interface';
@ -29,7 +31,11 @@ import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-module
@UseGuards(WorkspaceAuthGuard)
@Resolver(() => ObjectMetadataDTO)
@UseFilters(PermissionsGraphqlApiExceptionFilter)
@UsePipes(ResolverValidationPipe)
@UseFilters(
PreventNestToAutoLogGraphqlErrorsFilter,
PermissionsGraphqlApiExceptionFilter,
)
export class ObjectMetadataResolver {
constructor(
private readonly objectMetadataService: ObjectMetadataService,

View File

@ -1,6 +1,8 @@
import { UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
@ -14,6 +16,8 @@ import { RemoteServerService } from 'src/engine/metadata-modules/remote-server/r
import { remoteServerGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/remote-server/utils/remote-server-graphql-api-exception-handler.util';
@UseGuards(WorkspaceAuthGuard)
@UsePipes(ResolverValidationPipe)
@UseFilters(PreventNestToAutoLogGraphqlErrorsFilter)
@Resolver()
export class RemoteServerResolver {
constructor(

View File

@ -1,6 +1,8 @@
import { UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
@ -11,6 +13,8 @@ import { RemoteTableService } from 'src/engine/metadata-modules/remote-server/re
import { remoteTableGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/remote-server/remote-table/utils/remote-table-graphql-api-exception-handler.util';
@UseGuards(WorkspaceAuthGuard)
@UsePipes(ResolverValidationPipe)
@UseFilters(PreventNestToAutoLogGraphqlErrorsFilter)
@Resolver()
export class RemoteTableResolver {
constructor(private readonly remoteTableService: RemoteTableService) {}

View File

@ -1,4 +1,4 @@
import { UseFilters, UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import {
Args,
Mutation,
@ -11,6 +11,8 @@ import {
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { FileService } from 'src/engine/core-modules/file/services/file.service';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
@ -40,9 +42,15 @@ import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
@Resolver(() => RoleDTO)
@UseGuards(WorkspaceAuthGuard)
@UseGuards(SettingsPermissionsGuard(SettingPermissionType.ROLES))
@UseFilters(PermissionsGraphqlApiExceptionFilter)
@UsePipes(ResolverValidationPipe)
@UseGuards(
WorkspaceAuthGuard,
SettingsPermissionsGuard(SettingPermissionType.ROLES),
)
@UseFilters(
PermissionsGraphqlApiExceptionFilter,
PreventNestToAutoLogGraphqlErrorsFilter,
)
export class RoleResolver {
constructor(
private readonly userRoleService: UserRoleService,

View File

@ -1,10 +1,12 @@
import { UseGuards } from '@nestjs/common';
import { UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { InjectRepository } from '@nestjs/typeorm';
import graphqlTypeJson from 'graphql-type-json';
import { Repository } from 'typeorm';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
import { FeatureFlagGuard } from 'src/engine/guards/feature-flag.guard';
@ -23,6 +25,8 @@ import { serverlessFunctionGraphQLApiExceptionHandler } from 'src/engine/metadat
@UseGuards(WorkspaceAuthGuard, FeatureFlagGuard)
@Resolver()
@UsePipes(ResolverValidationPipe)
@UseFilters(PreventNestToAutoLogGraphqlErrorsFilter)
export class ServerlessFunctionResolver {
constructor(
private readonly serverlessFunctionService: ServerlessFunctionService,

View File

@ -1,16 +1,20 @@
import { Inject, UseFilters, UseGuards, UsePipes } from '@nestjs/common';
import { Args, Resolver, Subscription } from '@nestjs/graphql';
import { Inject, UseGuards } from '@nestjs/common';
import { RedisPubSub } from 'graphql-redis-subscriptions';
import { isDefined } from 'twenty-shared/utils';
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { OnDbEventDTO } from 'src/engine/subscriptions/dtos/on-db-event.dto';
import { OnDbEventInput } from 'src/engine/subscriptions/dtos/on-db-event.input';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
@Resolver()
@UseGuards(WorkspaceAuthGuard, UserAuthGuard)
@UsePipes(ResolverValidationPipe)
@UseFilters(PreventNestToAutoLogGraphqlErrorsFilter)
export class SubscriptionsResolver {
constructor(@Inject('PUB_SUB') private readonly pubSub: RedisPubSub) {}

View File

@ -1,17 +0,0 @@
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
import { ValidationError } from 'class-validator';
import { UserInputError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util';
@Catch(ValidationError)
export class GraphqlValidationExceptionFilter implements ExceptionFilter {
catch(exception: ValidationError, _host: ArgumentsHost) {
const errors = Object.values(exception.constraints || {}).map((error) => ({
message: error,
path: exception.property,
}));
return new UserInputError(errors.map((error) => error.message).join(', '));
}
}

View File

@ -1,11 +1,10 @@
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import fs from 'fs';
import bytes from 'bytes';
import { useContainer, ValidationError } from 'class-validator';
import { useContainer } from 'class-validator';
import session from 'express-session';
import { graphqlUploadExpress } from 'graphql-upload';
@ -50,22 +49,6 @@ const bootstrap = async () => {
app.useGlobalFilters(new UnhandledExceptionFilter());
// Apply validation pipes globally
app.useGlobalPipes(
new ValidationPipe({
transform: true,
exceptionFactory: (errors) => {
const error = new ValidationError();
error.constraints = Object.assign(
{},
...errors.map((error) => error.constraints),
);
return error;
},
}),
);
app.useBodyParser('json', { limit: settings.storage.maxFileSize });
app.useBodyParser('urlencoded', {
limit: settings.storage.maxFileSize,