Browse Source

Task/improve symbol validation of MCP import tool (#8000)

Improve symbol validation
pull/8006/head
Thomas Kaul 6 days ago
committed by GitHub
parent
commit
452674ecee
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 35
      apps/api/src/app/endpoints/mcp/mcp.schemas.spec.ts
  2. 16
      apps/api/src/app/endpoints/mcp/mcp.schemas.ts

35
apps/api/src/app/endpoints/mcp/mcp.schemas.spec.ts

@ -2,7 +2,8 @@ import {
DEFAULT_DATE_RANGE, DEFAULT_DATE_RANGE,
MCP_MAX_ACTIVITIES, MCP_MAX_ACTIVITIES,
SEARCH_QUERY_MAXIMUM_LENGTH, SEARCH_QUERY_MAXIMUM_LENGTH,
SEARCH_QUERY_MINIMUM_LENGTH SEARCH_QUERY_MINIMUM_LENGTH,
SYMBOL_MAXIMUM_LENGTH
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { DataSource } from '@prisma/client'; import { DataSource } from '@prisma/client';
@ -107,6 +108,38 @@ describe('IMPORT_ACTIVITIES_PARAMETERS', () => {
expect(parse([createActivity({ symbol: '' })])).toBe(false); expect(parse([createActivity({ symbol: '' })])).toBe(false);
}); });
it('Refuses a symbol that contains only spaces', () => {
expect(parse([createActivity({ symbol: ' ' })])).toBe(false);
});
it(`Accepts a symbol of ${SYMBOL_MAXIMUM_LENGTH} characters`, () => {
expect(
parse([createActivity({ symbol: 'A'.repeat(SYMBOL_MAXIMUM_LENGTH) })])
).toBe(true);
});
it(`Accepts a symbol of ${SYMBOL_MAXIMUM_LENGTH} characters with spaces at the start and the end`, () => {
expect(
parse([
createActivity({ symbol: ` ${'A'.repeat(SYMBOL_MAXIMUM_LENGTH)} ` })
])
).toBe(true);
});
it(`Refuses a symbol longer than ${SYMBOL_MAXIMUM_LENGTH} characters`, () => {
expect(
parse([createActivity({ symbol: 'A'.repeat(SYMBOL_MAXIMUM_LENGTH + 1) })])
).toBe(false);
});
it('Removes spaces at the start and the end of a symbol', () => {
expect(
IMPORT_ACTIVITIES_PARAMETERS.parse({
activities: [createActivity({ symbol: ' AAPL ' })]
}).activities[0].symbol
).toBe('AAPL');
});
it('Refuses an empty identifier of an account', () => { it('Refuses an empty identifier of an account', () => {
expect(parse([createActivity({ accountId: '' })])).toBe(false); expect(parse([createActivity({ accountId: '' })])).toBe(false);
}); });

16
apps/api/src/app/endpoints/mcp/mcp.schemas.ts

@ -16,16 +16,18 @@ import {
import { AssetClass, DataSource, Type as ActivityType } from '@prisma/client'; import { AssetClass, DataSource, Type as ActivityType } from '@prisma/client';
import { z } from 'zod'; import { z } from 'zod';
const SYMBOL_PARAMETER = z
.string()
.trim()
.min(1)
.max(SYMBOL_MAXIMUM_LENGTH)
.describe('The symbol of the asset profile');
const HOLDING_PARAMETER = z.object({ const HOLDING_PARAMETER = z.object({
dataSource: z dataSource: z
.enum(DataSource) .enum(DataSource)
.describe('The data source of the asset profile'), .describe('The data source of the asset profile'),
symbol: z symbol: SYMBOL_PARAMETER
.string()
.trim()
.min(1)
.max(SYMBOL_MAXIMUM_LENGTH)
.describe('The symbol of the asset profile')
}); });
export const GET_ACCOUNTS_PARAMETERS = z.object({ export const GET_ACCOUNTS_PARAMETERS = z.object({
@ -141,7 +143,7 @@ export const IMPORT_ACTIVITIES_PARAMETERS = z.object({
), ),
fee: z.number().min(0).describe('The fee of the activity'), fee: z.number().min(0).describe('The fee of the activity'),
quantity: z.number().min(0).describe('The quantity of the activity'), quantity: z.number().min(0).describe('The quantity of the activity'),
symbol: z.string().min(1).describe('The symbol of the asset profile'), symbol: SYMBOL_PARAMETER,
type: z.enum(ActivityType).describe('The type of the activity'), type: z.enum(ActivityType).describe('The type of the activity'),
unitPrice: z.number().min(0).describe('The unit price of the activity') unitPrice: z.number().min(0).describe('The unit price of the activity')
}) })

Loading…
Cancel
Save