Browse Source

Fix filtering by holding

pull/7999/head
Thomas Kaul 2 weeks ago
parent
commit
b3ba1b5aab
  1. 16
      apps/api/src/app/endpoints/mcp/mcp.schemas.spec.ts
  2. 10
      apps/api/src/app/endpoints/mcp/mcp.schemas.ts
  3. 27
      apps/api/src/app/endpoints/mcp/mcp.service.spec.ts
  4. 28
      apps/api/src/app/endpoints/mcp/mcp.service.ts

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

@ -22,6 +22,14 @@ describe('GET_ACCOUNTS_PARAMETERS', () => {
}).success
).toBe(false);
});
it('Refuses a symbol of the holding that contains only spaces', () => {
expect(
GET_ACCOUNTS_PARAMETERS.safeParse({
holding: { dataSource: DataSource.YAHOO, symbol: ' ' }
}).success
).toBe(false);
});
});
describe('GET_ACTIVITIES_PARAMETERS', () => {
@ -32,6 +40,14 @@ describe('GET_ACTIVITIES_PARAMETERS', () => {
}).success
).toBe(false);
});
it('Refuses a symbol of the holding that contains only spaces', () => {
expect(
GET_ACTIVITIES_PARAMETERS.safeParse({
holding: { dataSource: DataSource.YAHOO, symbol: ' ' }
}).success
).toBe(false);
});
});
describe('IMPORT_ACTIVITIES_PARAMETERS', () => {

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

@ -4,7 +4,8 @@ import {
MCP_MAX_ACCOUNTS,
MCP_MAX_ACTIVITIES,
SEARCH_QUERY_MAXIMUM_LENGTH,
SEARCH_QUERY_MINIMUM_LENGTH
SEARCH_QUERY_MINIMUM_LENGTH,
SYMBOL_MAXIMUM_LENGTH
} from '@ghostfolio/common/config';
import {
isValidCurrencyCode,
@ -18,7 +19,12 @@ const HOLDING_PARAMETER = z.object({
dataSource: z
.enum(DataSource)
.describe('The data source of the asset profile'),
symbol: z.string().min(1).describe('The symbol of the asset profile')
symbol: z
.string()
.trim()
.min(1)
.max(SYMBOL_MAXIMUM_LENGTH)
.describe('The symbol of the asset profile')
});
export const GET_ACCOUNTS_PARAMETERS = z.object({

27
apps/api/src/app/endpoints/mcp/mcp.service.spec.ts

@ -127,6 +127,20 @@ describe('McpService', () => {
);
});
it('Keeps the data source if the subscription is not enabled', async () => {
configuration.DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER = [DataSource.YAHOO];
configuration.ENABLE_FEATURE_SUBSCRIPTION = false;
await mcpService.getAccounts({
userId,
holding: { dataSource: DataSource.GHOSTFOLIO, symbol: 'AAPL' }
});
expect(apiService.buildFiltersFromQueryParams).toHaveBeenCalledWith(
expect.objectContaining({ filterByDataSource: DataSource.GHOSTFOLIO })
);
});
it('Gives the table of the accounts of the filters', async () => {
expect(await mcpService.getAccounts({ userId })).toEqual({
content: [{ text: '## Accounts', type: 'text' }]
@ -177,6 +191,19 @@ describe('McpService', () => {
);
});
it('Keeps the data source if the subscription is not enabled', async () => {
configuration.DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER = [DataSource.YAHOO];
configuration.ENABLE_FEATURE_SUBSCRIPTION = false;
await getActivities({
holding: { dataSource: DataSource.GHOSTFOLIO, symbol: 'AAPL' }
});
expect(apiService.buildFiltersFromQueryParams).toHaveBeenCalledWith(
expect.objectContaining({ filterByDataSource: DataSource.GHOSTFOLIO })
);
});
it('Changes the range into the start date and the end date', async () => {
await getActivities({ range: '2024' });

28
apps/api/src/app/endpoints/mcp/mcp.service.ts

@ -41,13 +41,9 @@ export class McpService {
userId
}: z.infer<typeof GET_ACCOUNTS_PARAMETERS> & { userId: string }) {
const filters = this.apiService.buildFiltersFromQueryParams({
...this.getHoldingFilterParameters({ holding }),
filterByAccounts: accountIds,
filterByAssetClasses: assetClasses,
filterByDataSource: getUnmaskedGhostfolioDataSource({
dataSource: holding?.dataSource,
ghostfolioDataSources: this.getGhostfolioDataSources()
}),
filterBySymbol: holding?.symbol
filterByAssetClasses: assetClasses
});
const table = await this.portfolioTableService.getAccountsTable({
@ -81,12 +77,8 @@ export class McpService {
}
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAssetClasses: assetClasses,
filterByDataSource: getUnmaskedGhostfolioDataSource({
dataSource: holding?.dataSource,
ghostfolioDataSources: this.getGhostfolioDataSources()
}),
filterBySymbol: holding?.symbol
...this.getHoldingFilterParameters({ holding }),
filterByAssetClasses: assetClasses
});
const table = await this.portfolioTableService.getActivitiesTable({
@ -214,6 +206,18 @@ export class McpService {
: [];
}
private getHoldingFilterParameters({
holding
}: Pick<z.infer<typeof GET_ACCOUNTS_PARAMETERS>, 'holding'>) {
return {
filterByDataSource: getUnmaskedGhostfolioDataSource({
dataSource: holding?.dataSource,
ghostfolioDataSources: this.getGhostfolioDataSources()
}),
filterBySymbol: holding?.symbol
};
}
private getTextResult(text: string) {
return { content: [{ text, type: 'text' as const }] };
}

Loading…
Cancel
Save