Fix REST API Delete and Destroy (#15806)

Fixes https://github.com/twentyhq/twenty/issues/15801
This commit is contained in:
Raphaël Bosi
2025-11-13 18:14:32 +01:00
committed by GitHub
parent 9bc5486d0d
commit 56b3a0e8a5
3 changed files with 58 additions and 4 deletions
@@ -1,10 +1,11 @@
import { Injectable } from '@nestjs/common';
import { BadRequestException, Injectable } from '@nestjs/common';
import isEmpty from 'lodash.isempty';
import { ObjectRecord } from 'twenty-shared/types';
import { capitalize } from 'twenty-shared/utils';
import { RestApiBaseHandler } from 'src/engine/api/rest/core/handlers/rest-api-base.handler';
import { CommonDeleteManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-delete-many-query-runner.service';
import { RestApiBaseHandler } from 'src/engine/api/rest/core/handlers/rest-api-base.handler';
import { parseFilterRestRequest } from 'src/engine/api/rest/input-request-parsers/filter-parser-utils/parse-filter-rest-request.util';
import { AuthenticatedRequest } from 'src/engine/api/rest/types/authenticated-request';
import { workspaceQueryRunnerRestApiExceptionHandler } from 'src/engine/api/rest/utils/workspace-query-runner-rest-api-exception-handler.util';
@@ -23,6 +24,13 @@ export class RestApiDeleteManyHandler extends RestApiBaseHandler {
};
}> {
const { filter } = this.parseRequestArgs(request);
if (isEmpty(filter)) {
throw new BadRequestException(
'Filters are mandatory for bulk delete operations. Please provide at least one filter to prevent accidental deletion of all records.',
);
}
const { authContext, objectMetadataItemWithFieldMaps, objectMetadataMaps } =
await this.buildCommonOptions(request);
@@ -1,10 +1,11 @@
import { Injectable } from '@nestjs/common';
import { BadRequestException, Injectable } from '@nestjs/common';
import isEmpty from 'lodash.isempty';
import { ObjectRecord } from 'twenty-shared/types';
import { capitalize } from 'twenty-shared/utils';
import { RestApiBaseHandler } from 'src/engine/api/rest/core/handlers/rest-api-base.handler';
import { CommonDestroyManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-destroy-many-query-runner.service';
import { RestApiBaseHandler } from 'src/engine/api/rest/core/handlers/rest-api-base.handler';
import { parseFilterRestRequest } from 'src/engine/api/rest/input-request-parsers/filter-parser-utils/parse-filter-rest-request.util';
import { AuthenticatedRequest } from 'src/engine/api/rest/types/authenticated-request';
import { workspaceQueryRunnerRestApiExceptionHandler } from 'src/engine/api/rest/utils/workspace-query-runner-rest-api-exception-handler.util';
@@ -23,6 +24,13 @@ export class RestApiDestroyManyHandler extends RestApiBaseHandler {
};
}> {
const { filter } = this.parseRequestArgs(request);
if (isEmpty(filter)) {
throw new BadRequestException(
'Filters are mandatory for bulk destroy operations. Please provide at least one filter to prevent accidental deletion of all records.',
);
}
const { authContext, objectMetadataItemWithFieldMaps, objectMetadataMaps } =
await this.buildCommonOptions(request);
@@ -61,3 +61,41 @@ describe('Core REST API Delete One endpoint', () => {
expect(response.body.messages[0]).toBe('Record not found');
});
});
describe('Core REST API Delete Many endpoint', () => {
beforeAll(async () => {
await deleteAllRecords('person');
});
it('should require filters for bulk delete operations', async () => {
const response = await makeRestAPIRequest({
method: 'delete',
path: `/people?soft_delete=true`,
});
expect(response.status).toBe(400);
expect(response.body.error).toBe('BadRequestException');
expect(response.body.messages[0]).toContain(
'Filters are mandatory for bulk delete operations',
);
});
});
describe('Core REST API Destroy Many endpoint', () => {
beforeAll(async () => {
await deleteAllRecords('person');
});
it('should require filters for bulk destroy operations', async () => {
const response = await makeRestAPIRequest({
method: 'delete',
path: `/people?soft_delete=false`,
});
expect(response.status).toBe(400);
expect(response.body.error).toBe('BadRequestException');
expect(response.body.messages[0]).toContain(
'Filters are mandatory for bulk destroy operations',
);
});
});