fix(server): map PermissionsException to proper HTTP status on REST API (#20739)

## Summary

`PermissionsException` thrown by `SettingsPermissionGuard` (and other
permission code paths) was bubbling up through every typed REST
exception filter and landing in the global `UnhandledExceptionFilter`,
which falls back to **500** for anything that isn't an `HttpException`.
So a forbidden user (e.g. an API key whose role doesn't have
`DATA_MODEL`) calling `GET /rest/metadata/objects` got:
```
HTTP/1.1 500 Internal Server Error "Entity performing the request does not have permission"
```


GraphQL already had the right plumbing via
`permissionGraphqlApiExceptionHandler` (`ForbiddenError` → 403,
`UserInputError` → 400, `NotFoundError` → 404). This PR mirrors it on
the REST side.

## What

- New util `permissionRestApiExceptionCodeToHttpStatus` mapping every
`PermissionsExceptionCode` → HTTP status, with `assertUnreachable` to
force explicit handling of future codes.
- New filter `PermissionsRestApiExceptionFilter`
(`@Catch(PermissionsException)`) that delegates to
`HttpExceptionHandlerService.handleError(...)` with the resolved status.
- Wired `PermissionsRestApiExceptionFilter` (placed first, so the typed
filter wins over any sibling catch-all) into `@UseFilters(...)` of every
REST controller that uses `SettingsPermissionGuard` or whose service can
throw `PermissionsException`:
  - `object-metadata`, `field-metadata`, `webhook`, `api-key`
- `view`, `view-sort`, `view-group`, `view-filter`, `view-filter-group`,
`view-field`
  - `page-layout`, `page-layout-widget`, `page-layout-tab`
  - `front-component`, `ai-generate-text`
- Unit tests covering 403 / 400 / 404 / 500 mappings.

## Mapping

| Code | Status |
|------|--------|
| `PERMISSION_DENIED`, `NO_AUTHENTICATION_CONTEXT`,
`ROLE_LABEL_ALREADY_EXISTS`, `CANNOT_UNASSIGN_LAST_ADMIN`,
`CANNOT_UPDATE_SELF_ROLE`, `CANNOT_DELETE_LAST_ADMIN_USER`,
`ROLE_NOT_EDITABLE`, `CANNOT_ADD_OBJECT_PERMISSION_ON_SYSTEM_OBJECT`,
`CANNOT_ADD_FIELD_PERMISSION_ON_SYSTEM_OBJECT` | **403** |
| `INVALID_ARG`, `INVALID_SETTING`,
`CANNOT_GIVE_WRITING_PERMISSION_ON_NON_READABLE_OBJECT`,
`CANNOT_GIVE_WRITING_PERMISSION_WITHOUT_READING_PERMISSION`,
`ONLY_FIELD_RESTRICTION_ALLOWED`,
`FIELD_RESTRICTION_ONLY_ALLOWED_ON_READABLE_OBJECT`,
`FIELD_RESTRICTION_ON_UPDATE_ONLY_ALLOWED_ON_UPDATABLE_OBJECT`,
`EMPTY_FIELD_PERMISSION_NOT_ALLOWED`,
`ROLE_MUST_HAVE_AT_LEAST_ONE_TARGET`, `ROLE_CANNOT_BE_ASSIGNED_TO_USERS`
| **400** |
| `ROLE_NOT_FOUND`, `OBJECT_METADATA_NOT_FOUND`,
`FIELD_METADATA_NOT_FOUND`, `FIELD_PERMISSION_NOT_FOUND`,
`PERMISSION_NOT_FOUND` | **404** |
| All remaining "internal" codes (rethrown as-is in GraphQL) | **500** |

## Before
<img width="507" height="216" alt="Screenshot 2026-05-19 at 19 26 07"
src="https://github.com/user-attachments/assets/21d633aa-7ee8-4923-94e4-7ad57258a29e"
/>

## After
<img width="610" height="385" alt="Screenshot 2026-05-19 at 19 26 01"
src="https://github.com/user-attachments/assets/0103b7ee-7df7-4aef-999a-73c22901afd2"
/>
This commit is contained in:
Weiko
2026-05-20 15:02:58 +02:00
committed by GitHub
parent a2acf88a57
commit 6e5e7963b5
18 changed files with 208 additions and 4 deletions
@@ -23,6 +23,7 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { JwtAuthGuard } from 'src/engine/guards/jwt-auth.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
/**
* rest/apiKeys is deprecated, use rest/metadata/apiKeys instead
@@ -34,7 +35,7 @@ import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
WorkspaceAuthGuard,
SettingsPermissionGuard(PermissionFlagType.API_KEYS_AND_WEBHOOKS),
)
@UseFilters(RestApiExceptionFilter)
@UseFilters(PermissionsRestApiExceptionFilter, RestApiExceptionFilter)
export class ApiKeyController {
constructor(private readonly apiKeyService: ApiKeyService) {}
@@ -20,10 +20,15 @@ import { AiBillingService } from 'src/engine/metadata-modules/ai/ai-billing/serv
import { AiRestApiExceptionFilter } from 'src/engine/metadata-modules/ai/filters/ai-api-exception.filter';
import { GenerateTextInput } from 'src/engine/metadata-modules/ai/ai-generate-text/dtos/generate-text.input';
import { AiModelRegistryService } from 'src/engine/metadata-modules/ai/ai-models/services/ai-model-registry.service';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
@Controller('rest/ai')
@UseGuards(JwtAuthGuard, WorkspaceAuthGuard)
@UseFilters(AiRestApiExceptionFilter, RestApiExceptionFilter)
@UseFilters(
PermissionsRestApiExceptionFilter,
AiRestApiExceptionFilter,
RestApiExceptionFilter,
)
export class AiGenerateTextController {
constructor(
private readonly aiModelRegistryService: AiModelRegistryService,
@@ -53,6 +53,7 @@ import {
toLegacyFieldMetadataUpdateResponse,
} from 'src/engine/metadata-modules/field-metadata/utils/to-legacy-field-metadata-response.util';
import { fromFlatFieldMetadataToFieldMetadataDto } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-flat-field-metadata-to-field-metadata-dto.util';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
@Controller('rest/metadata/fields')
@UseGuards(
@@ -60,7 +61,10 @@ import { fromFlatFieldMetadataToFieldMetadataDto } from 'src/engine/metadata-mod
WorkspaceAuthGuard,
SettingsPermissionGuard(PermissionFlagType.DATA_MODEL),
)
@UseFilters(FieldMetadataRestApiExceptionFilter)
@UseFilters(
PermissionsRestApiExceptionFilter,
FieldMetadataRestApiExceptionFilter,
)
@UsePipes(new ValidationPipe())
export class FieldMetadataController {
constructor(
@@ -27,11 +27,13 @@ import {
FrontComponentExceptionCode,
} from 'src/engine/metadata-modules/front-component/front-component.exception';
import { FrontComponentService } from 'src/engine/metadata-modules/front-component/front-component.service';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { WorkspaceMigrationRunnerRestApiExceptionFilter } from 'src/engine/workspace-manager/workspace-migration/filters/workspace-migration-runner-rest-api-exception.filter';
@Controller('rest/front-components')
@UseGuards(WorkspaceAuthGuard)
@UseFilters(
PermissionsRestApiExceptionFilter,
FrontComponentRestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,
@@ -55,6 +55,7 @@ import {
toLegacyObjectMetadataListResponse,
toLegacyObjectMetadataUpdateResponse,
} from 'src/engine/metadata-modules/object-metadata/utils/to-legacy-object-metadata-response.util';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
@Controller('rest/metadata/objects')
@UseGuards(
@@ -62,7 +63,10 @@ import {
WorkspaceAuthGuard,
SettingsPermissionGuard(PermissionFlagType.DATA_MODEL),
)
@UseFilters(ObjectMetadataRestApiExceptionFilter)
@UseFilters(
PermissionsRestApiExceptionFilter,
ObjectMetadataRestApiExceptionFilter,
)
@UsePipes(new ValidationPipe())
export class ObjectMetadataController {
constructor(
@@ -31,11 +31,13 @@ import {
} from 'src/engine/metadata-modules/page-layout-tab/exceptions/page-layout-tab.exception';
import { PageLayoutTabRestApiExceptionFilter } from 'src/engine/metadata-modules/page-layout-tab/filters/page-layout-tab-rest-api-exception.filter';
import { PageLayoutTabService } from 'src/engine/metadata-modules/page-layout-tab/services/page-layout-tab.service';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { WorkspaceMigrationRunnerRestApiExceptionFilter } from 'src/engine/workspace-manager/workspace-migration/filters/workspace-migration-runner-rest-api-exception.filter';
@Controller('rest/metadata/pageLayoutTabs')
@UseGuards(WorkspaceAuthGuard)
@UseFilters(
PermissionsRestApiExceptionFilter,
PageLayoutTabRestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,
@@ -31,11 +31,13 @@ import {
} from 'src/engine/metadata-modules/page-layout-widget/exceptions/page-layout-widget.exception';
import { PageLayoutWidgetRestApiExceptionFilter } from 'src/engine/metadata-modules/page-layout-widget/filters/page-layout-widget-rest-api-exception.filter';
import { PageLayoutWidgetService } from 'src/engine/metadata-modules/page-layout-widget/services/page-layout-widget.service';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { WorkspaceMigrationRunnerRestApiExceptionFilter } from 'src/engine/workspace-manager/workspace-migration/filters/workspace-migration-runner-rest-api-exception.filter';
@Controller('rest/metadata/pageLayoutWidgets')
@UseGuards(WorkspaceAuthGuard)
@UseFilters(
PermissionsRestApiExceptionFilter,
PageLayoutWidgetRestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,
@@ -26,11 +26,13 @@ import { type PageLayoutDTO } from 'src/engine/metadata-modules/page-layout/dtos
import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum';
import { PageLayoutRestApiExceptionFilter } from 'src/engine/metadata-modules/page-layout/filters/page-layout-rest-api-exception.filter';
import { PageLayoutService } from 'src/engine/metadata-modules/page-layout/services/page-layout.service';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { WorkspaceMigrationRunnerRestApiExceptionFilter } from 'src/engine/workspace-manager/workspace-migration/filters/workspace-migration-runner-rest-api-exception.filter';
@Controller('rest/metadata/pageLayouts')
@UseGuards(WorkspaceAuthGuard)
@UseFilters(
PermissionsRestApiExceptionFilter,
PageLayoutRestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,
@@ -0,0 +1,76 @@
import { PermissionsExceptionCode } from 'src/engine/metadata-modules/permissions/permissions.exception';
import { permissionRestApiExceptionCodeToHttpStatus } from 'src/engine/metadata-modules/permissions/utils/permission-rest-api-exception-code-to-http-status.util';
describe('permissionRestApiExceptionCodeToHttpStatus', () => {
it('should return 403 for PERMISSION_DENIED', () => {
expect(
permissionRestApiExceptionCodeToHttpStatus(
PermissionsExceptionCode.PERMISSION_DENIED,
),
).toBe(403);
});
it('should return 403 for role-related forbidden cases', () => {
expect(
permissionRestApiExceptionCodeToHttpStatus(
PermissionsExceptionCode.CANNOT_UPDATE_SELF_ROLE,
),
).toBe(403);
});
it('should return 403 for NO_AUTHENTICATION_CONTEXT', () => {
expect(
permissionRestApiExceptionCodeToHttpStatus(
PermissionsExceptionCode.NO_AUTHENTICATION_CONTEXT,
),
).toBe(403);
});
it('should return 400 for INVALID_ARG', () => {
expect(
permissionRestApiExceptionCodeToHttpStatus(
PermissionsExceptionCode.INVALID_ARG,
),
).toBe(400);
});
it('should return 400 for permission validation errors', () => {
expect(
permissionRestApiExceptionCodeToHttpStatus(
PermissionsExceptionCode.EMPTY_FIELD_PERMISSION_NOT_ALLOWED,
),
).toBe(400);
});
it('should return 404 for ROLE_NOT_FOUND', () => {
expect(
permissionRestApiExceptionCodeToHttpStatus(
PermissionsExceptionCode.ROLE_NOT_FOUND,
),
).toBe(404);
});
it('should return 404 for metadata not found cases', () => {
expect(
permissionRestApiExceptionCodeToHttpStatus(
PermissionsExceptionCode.OBJECT_METADATA_NOT_FOUND,
),
).toBe(404);
});
it('should return 500 for METHOD_NOT_ALLOWED', () => {
expect(
permissionRestApiExceptionCodeToHttpStatus(
PermissionsExceptionCode.METHOD_NOT_ALLOWED,
),
).toBe(500);
});
it('should return 500 for internal error codes', () => {
expect(
permissionRestApiExceptionCodeToHttpStatus(
PermissionsExceptionCode.DEFAULT_ROLE_NOT_FOUND,
),
).toBe(500);
});
});
@@ -0,0 +1,61 @@
import { assertUnreachable } from 'twenty-shared/utils';
import { PermissionsExceptionCode } from 'src/engine/metadata-modules/permissions/permissions.exception';
export const permissionRestApiExceptionCodeToHttpStatus = (
code: PermissionsExceptionCode,
): number => {
switch (code) {
case PermissionsExceptionCode.PERMISSION_DENIED:
case PermissionsExceptionCode.NO_AUTHENTICATION_CONTEXT:
case PermissionsExceptionCode.ROLE_LABEL_ALREADY_EXISTS:
case PermissionsExceptionCode.CANNOT_UNASSIGN_LAST_ADMIN:
case PermissionsExceptionCode.CANNOT_UPDATE_SELF_ROLE:
case PermissionsExceptionCode.CANNOT_DELETE_LAST_ADMIN_USER:
case PermissionsExceptionCode.ROLE_NOT_EDITABLE:
case PermissionsExceptionCode.CANNOT_ADD_OBJECT_PERMISSION_ON_SYSTEM_OBJECT:
case PermissionsExceptionCode.CANNOT_ADD_FIELD_PERMISSION_ON_SYSTEM_OBJECT:
return 403;
case PermissionsExceptionCode.INVALID_ARG:
case PermissionsExceptionCode.INVALID_SETTING:
case PermissionsExceptionCode.CANNOT_GIVE_WRITING_PERMISSION_ON_NON_READABLE_OBJECT:
case PermissionsExceptionCode.CANNOT_GIVE_WRITING_PERMISSION_WITHOUT_READING_PERMISSION:
case PermissionsExceptionCode.ONLY_FIELD_RESTRICTION_ALLOWED:
case PermissionsExceptionCode.FIELD_RESTRICTION_ONLY_ALLOWED_ON_READABLE_OBJECT:
case PermissionsExceptionCode.FIELD_RESTRICTION_ON_UPDATE_ONLY_ALLOWED_ON_UPDATABLE_OBJECT:
case PermissionsExceptionCode.EMPTY_FIELD_PERMISSION_NOT_ALLOWED:
case PermissionsExceptionCode.ROLE_MUST_HAVE_AT_LEAST_ONE_TARGET:
case PermissionsExceptionCode.ROLE_CANNOT_BE_ASSIGNED_TO_USERS:
return 400;
case PermissionsExceptionCode.ROLE_NOT_FOUND:
case PermissionsExceptionCode.OBJECT_METADATA_NOT_FOUND:
case PermissionsExceptionCode.FIELD_METADATA_NOT_FOUND:
case PermissionsExceptionCode.FIELD_PERMISSION_NOT_FOUND:
case PermissionsExceptionCode.PERMISSION_NOT_FOUND:
return 404;
case PermissionsExceptionCode.UPSERT_FIELD_PERMISSION_FAILED:
case PermissionsExceptionCode.DEFAULT_ROLE_NOT_FOUND:
case PermissionsExceptionCode.WORKSPACE_ID_ROLE_USER_WORKSPACE_MISMATCH:
case PermissionsExceptionCode.TOO_MANY_ADMIN_CANDIDATES:
case PermissionsExceptionCode.USER_WORKSPACE_ALREADY_HAS_ROLE:
case PermissionsExceptionCode.ADMIN_ROLE_NOT_FOUND:
case PermissionsExceptionCode.DEFAULT_ROLE_CANNOT_BE_DELETED:
case PermissionsExceptionCode.WORKSPACE_MEMBER_NOT_FOUND:
case PermissionsExceptionCode.UNKNOWN_OPERATION_NAME:
case PermissionsExceptionCode.UNKNOWN_REQUIRED_PERMISSION:
case PermissionsExceptionCode.NO_ROLE_FOUND_FOR_USER_WORKSPACE:
case PermissionsExceptionCode.NO_PERMISSIONS_FOUND_IN_DATASOURCE:
case PermissionsExceptionCode.METHOD_NOT_ALLOWED:
case PermissionsExceptionCode.RAW_SQL_NOT_ALLOWED:
case PermissionsExceptionCode.OBJECT_PERMISSION_NOT_FOUND:
case PermissionsExceptionCode.API_KEY_ROLE_NOT_FOUND:
case PermissionsExceptionCode.JOIN_COLUMN_NAME_REQUIRED:
case PermissionsExceptionCode.COMPOSITE_TYPE_NOT_FOUND:
case PermissionsExceptionCode.USER_WORKSPACE_NOT_FOUND:
case PermissionsExceptionCode.APPLICATION_ROLE_NOT_FOUND:
case PermissionsExceptionCode.ROLE_BELONGS_TO_ANOTHER_APPLICATION:
return 500;
default:
return assertUnreachable(code);
}
};
@@ -0,0 +1,31 @@
import {
type ArgumentsHost,
Catch,
type ExceptionFilter,
Injectable,
} from '@nestjs/common';
import { type Response } from 'express';
import { HttpExceptionHandlerService } from 'src/engine/core-modules/exception-handler/http-exception-handler.service';
import { PermissionsException } from 'src/engine/metadata-modules/permissions/permissions.exception';
import { permissionRestApiExceptionCodeToHttpStatus } from 'src/engine/metadata-modules/permissions/utils/permission-rest-api-exception-code-to-http-status.util';
import { type CustomException } from 'src/utils/custom-exception';
@Injectable()
@Catch(PermissionsException)
export class PermissionsRestApiExceptionFilter implements ExceptionFilter {
constructor(
private readonly httpExceptionHandlerService: HttpExceptionHandlerService,
) {}
catch(exception: PermissionsException, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse<Response>();
return this.httpExceptionHandlerService.handleError(
exception as CustomException,
response,
permissionRestApiExceptionCodeToHttpStatus(exception.code),
);
}
}
@@ -18,6 +18,7 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { FlatEntityMapsRestApiExceptionFilter } from 'src/engine/metadata-modules/flat-entity/filters/flat-entity-maps-rest-api-exception.filter';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { CreateViewFieldInput } from 'src/engine/metadata-modules/view-field/dtos/inputs/create-view-field.input';
import { UpdateViewFieldInput } from 'src/engine/metadata-modules/view-field/dtos/inputs/update-view-field.input';
import { ViewFieldDTO } from 'src/engine/metadata-modules/view-field/dtos/view-field.dto';
@@ -38,6 +39,7 @@ import { WorkspaceMigrationRunnerRestApiExceptionFilter } from 'src/engine/works
@Controller('rest/metadata/viewFields')
@UseGuards(WorkspaceAuthGuard)
@UseFilters(
PermissionsRestApiExceptionFilter,
ViewFieldRestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,
@@ -18,6 +18,7 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { FlatEntityMapsRestApiExceptionFilter } from 'src/engine/metadata-modules/flat-entity/filters/flat-entity-maps-rest-api-exception.filter';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { type CreateViewFilterGroupInput } from 'src/engine/metadata-modules/view-filter-group/dtos/inputs/create-view-filter-group.input';
import { type UpdateViewFilterGroupInput } from 'src/engine/metadata-modules/view-filter-group/dtos/inputs/update-view-filter-group.input';
import { type ViewFilterGroupDTO } from 'src/engine/metadata-modules/view-filter-group/dtos/view-filter-group.dto';
@@ -38,6 +39,7 @@ import { WorkspaceMigrationRunnerRestApiExceptionFilter } from 'src/engine/works
@Controller('rest/metadata/viewFilterGroups')
@UseGuards(WorkspaceAuthGuard)
@UseFilters(
PermissionsRestApiExceptionFilter,
ViewFilterGroupRestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,
@@ -18,6 +18,7 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { FlatEntityMapsRestApiExceptionFilter } from 'src/engine/metadata-modules/flat-entity/filters/flat-entity-maps-rest-api-exception.filter';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { CreateViewFilterInput } from 'src/engine/metadata-modules/view-filter/dtos/inputs/create-view-filter.input';
import { UpdateViewFilterInput } from 'src/engine/metadata-modules/view-filter/dtos/inputs/update-view-filter.input';
import { ViewFilterDTO } from 'src/engine/metadata-modules/view-filter/dtos/view-filter.dto';
@@ -38,6 +39,7 @@ import { WorkspaceMigrationRunnerRestApiExceptionFilter } from 'src/engine/works
@Controller('rest/metadata/viewFilters')
@UseGuards(WorkspaceAuthGuard)
@UseFilters(
PermissionsRestApiExceptionFilter,
ViewFilterRestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,
@@ -18,6 +18,7 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { FlatEntityMapsRestApiExceptionFilter } from 'src/engine/metadata-modules/flat-entity/filters/flat-entity-maps-rest-api-exception.filter';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { CreateViewGroupInput } from 'src/engine/metadata-modules/view-group/dtos/inputs/create-view-group.input';
import { UpdateViewGroupInput } from 'src/engine/metadata-modules/view-group/dtos/inputs/update-view-group.input';
import { type ViewGroupDTO } from 'src/engine/metadata-modules/view-group/dtos/view-group.dto';
@@ -38,6 +39,7 @@ import { WorkspaceMigrationRunnerRestApiExceptionFilter } from 'src/engine/works
@Controller('rest/metadata/viewGroups')
@UseGuards(WorkspaceAuthGuard)
@UseFilters(
PermissionsRestApiExceptionFilter,
ViewGroupRestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,
@@ -18,6 +18,7 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { FlatEntityMapsRestApiExceptionFilter } from 'src/engine/metadata-modules/flat-entity/filters/flat-entity-maps-rest-api-exception.filter';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { CreateViewSortPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/create-view-sort-permission.guard';
import { DeleteViewSortPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/delete-view-sort-permission.guard';
import { UpdateViewSortPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/update-view-sort-permission.guard';
@@ -38,6 +39,7 @@ import { ViewSortDirection } from 'twenty-shared/types';
@Controller('rest/metadata/viewSorts')
@UseGuards(WorkspaceAuthGuard)
@UseFilters(
PermissionsRestApiExceptionFilter,
ViewSortRestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,
@@ -41,11 +41,13 @@ import {
import { ViewRestApiExceptionFilter } from 'src/engine/metadata-modules/view/filters/view-rest-api-exception.filter';
import { ViewService } from 'src/engine/metadata-modules/view/services/view.service';
import { FlatEntityMapsRestApiExceptionFilter } from 'src/engine/metadata-modules/flat-entity/filters/flat-entity-maps-rest-api-exception.filter';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { WorkspaceMigrationRunnerRestApiExceptionFilter } from 'src/engine/workspace-manager/workspace-migration/filters/workspace-migration-runner-rest-api-exception.filter';
@Controller('rest/metadata/views')
@UseGuards(WorkspaceAuthGuard)
@UseFilters(
PermissionsRestApiExceptionFilter,
ViewRestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,
@@ -19,6 +19,7 @@ import { JwtAuthGuard } from 'src/engine/guards/jwt-auth.guard';
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { FlatEntityMapsRestApiExceptionFilter } from 'src/engine/metadata-modules/flat-entity/filters/flat-entity-maps-rest-api-exception.filter';
import { PermissionsRestApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-rest-api-exception.filter';
import { CreateWebhookInput } from 'src/engine/metadata-modules/webhook/dtos/create-webhook.input';
import { UpdateWebhookInput } from 'src/engine/metadata-modules/webhook/dtos/update-webhook.input';
import { type WebhookDTO } from 'src/engine/metadata-modules/webhook/dtos/webhook.dto';
@@ -32,6 +33,7 @@ import { WorkspaceMigrationRunnerRestApiExceptionFilter } from 'src/engine/works
SettingsPermissionGuard(PermissionFlagType.API_KEYS_AND_WEBHOOKS),
)
@UseFilters(
PermissionsRestApiExceptionFilter,
RestApiExceptionFilter,
FlatEntityMapsRestApiExceptionFilter,
WorkspaceMigrationRunnerRestApiExceptionFilter,