Browse Source

Merge a9c3f0c8e0 into 90c90e179e

pull/8281/merge
Thomas Kaul 17 hours ago
committed by GitHub
parent
commit
dc28c705b6
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      CHANGELOG.md
  2. 57
      apps/api/src/app/endpoints/import/import.controller.spec.ts
  3. 7
      apps/api/src/app/endpoints/import/import.controller.ts

4
CHANGELOG.md

@ -19,6 +19,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improved the language localization for German (`de`) - Improved the language localization for German (`de`)
- Upgraded `prettier` from version `3.9.9` to `3.9.10` - Upgraded `prettier` from version `3.9.9` to `3.9.10`
### Fixed
- Fixed the exposure of internal error messages in the `POST api/v1/import` endpoint
## 3.90.0 - 2026-10-21 ## 3.90.0 - 2026-10-21
### Changed ### Changed

57
apps/api/src/app/endpoints/import/import.controller.spec.ts

@ -0,0 +1,57 @@
import { ImportValidationError } from '@ghostfolio/api/services/import/errors/import-validation.error';
import { ImportDataDto } from '@ghostfolio/api/services/import/import-data.dto';
import { ImportService } from '@ghostfolio/api/services/import/import.service';
import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
import { Logger } from '@nestjs/common';
import { getReasonPhrase, StatusCodes } from 'http-status-codes';
import { ImportController } from './import.controller';
describe('ImportController', () => {
const importData = { activities: [] } as ImportDataDto;
let importController: ImportController;
let importService: ImportService;
beforeEach(() => {
jest.spyOn(Logger.prototype, 'error').mockImplementation();
importService = {
import: jest.fn()
} as unknown as ImportService;
importController = new ImportController(importService, {
user: { permissions: [permissions.createAccount] }
} as unknown as RequestWithUser);
});
describe('import', () => {
it('Gives the status 400 with the message of an error for the caller', async () => {
jest
.mocked(importService.import)
.mockRejectedValueOnce(
new ImportValidationError('activities.0.accountId ("1") is not valid')
);
await expect(importController.import(importData)).rejects.toMatchObject({
response: { message: ['activities.0.accountId ("1") is not valid'] },
status: StatusCodes.BAD_REQUEST
});
});
it('Gives the status 400 without the message of every other error', async () => {
jest
.mocked(importService.import)
.mockRejectedValueOnce(
new Error('Invalid `prisma.order.create()` invocation')
);
await expect(importController.import(importData)).rejects.toMatchObject({
response: { message: [getReasonPhrase(StatusCodes.BAD_REQUEST)] },
status: StatusCodes.BAD_REQUEST
});
});
});
});

7
apps/api/src/app/endpoints/import/import.controller.ts

@ -1,4 +1,5 @@
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { CallerFacingError } from '@ghostfolio/api/errors/caller-facing.error';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor';
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor';
@ -73,7 +74,11 @@ export class ImportController {
throw new HttpException( throw new HttpException(
{ {
error: getReasonPhrase(StatusCodes.BAD_REQUEST), error: getReasonPhrase(StatusCodes.BAD_REQUEST),
message: [error.message] message: [
error instanceof CallerFacingError
? error.message
: getReasonPhrase(StatusCodes.BAD_REQUEST)
]
}, },
StatusCodes.BAD_REQUEST StatusCodes.BAD_REQUEST
); );

Loading…
Cancel
Save