From 9c1e014190fbb3dfaa368c4ba9bc841b8dd47933 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 3 Oct 2026 15:03:33 +0200 Subject: [PATCH] Task/select required symbol profile fields in activities (#7998) * Select required symbol profile fields * Remove symbol profile relation from activities * Update changelog --- CHANGELOG.md | 1 + .../src/app/activities/activities.service.ts | 12 ++- apps/api/src/app/import/import.service.ts | 2 +- apps/api/src/helper/object.helper.spec.ts | 85 ++++++++++--------- ...orm-data-source-in-response.interceptor.ts | 2 - libs/common/src/lib/config.ts | 3 - 6 files changed, 57 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6207c1c202..43cd5a98eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the label of the cash positions in the holdings charts and table - Excluded the cash position in the base currency from the holdings table on the overview tab of the home page (experimental) - Extended the tools to get the activities, the portfolio and the watchlist in the server of the Model Context Protocol (MCP) to include the data source (experimental) +- Removed the deprecated `SymbolProfile` field from the endpoints `GET api/v1/activities`, `GET api/v1/activities/:id` and `POST api/v1/import` - Upgraded `@openrouter/ai-sdk-provider` from version `3.0.0` to `3.1.0` - Upgraded `ai` from version `7.0.37` to `7.0.114` - Upgraded `dotenv` from version `17.4.2` to `18.0.3` diff --git a/apps/api/src/app/activities/activities.service.ts b/apps/api/src/app/activities/activities.service.ts index 75adcbc5d3..9e1a1b8d4c 100644 --- a/apps/api/src/app/activities/activities.service.ts +++ b/apps/api/src/app/activities/activities.service.ts @@ -60,7 +60,7 @@ import { Type as ActivityType } from '@prisma/client'; import { Big } from 'big.js'; -import { groupBy, uniqBy } from 'lodash-es'; +import { groupBy, omit, uniqBy } from 'lodash-es'; import { randomUUID } from 'node:crypto'; @Injectable() @@ -655,7 +655,13 @@ export class ActivitiesService { } }, // eslint-disable-next-line @typescript-eslint/naming-convention - SymbolProfile: true, + SymbolProfile: { + select: { + currency: true, + dataSource: true, + symbol: true + } + }, tags: true }, orderBy: [...orderBy, { id: sortDirection }] @@ -736,7 +742,7 @@ export class ActivitiesService { ]); return { - ...order, + ...omit(order, ['SymbolProfile']), assetProfile, feeInAssetProfileCurrency, feeInBaseCurrency, diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 5afa4c33dd..705066441f 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -1004,7 +1004,7 @@ export class ImportService { )) ?? 0; activities.push({ - ...order, + ...omit(order, ['SymbolProfile']), // @ts-ignore assetProfile, error, diff --git a/apps/api/src/helper/object.helper.spec.ts b/apps/api/src/helper/object.helper.spec.ts index 9776232a0b..5543441dbc 100644 --- a/apps/api/src/helper/object.helper.spec.ts +++ b/apps/api/src/helper/object.helper.spec.ts @@ -3082,20 +3082,6 @@ describe('redactAttributes', () => { feeInBaseCurrency: 18.2, id: '8c623328-6035-4b5f-b6d5-702cc1c9c56b', quantity: 50, - // The relation of the database is part of the response next to the - // asset profile - SymbolProfile: { - comment: 'Reviewed by the administrator', - name: 'Apple Inc', - scraperConfiguration: { - headers: { Authorization: 'Bearer TOKEN' }, - mode: 'lazy', - selector: '.price', - url: 'https://example.org/get_price' - }, - symbol: 'AAPL', - symbolMapping: { YAHOO: 'AAPL' } - }, type: 'BUY', unitPrice: 220.79, value: 11039.5, @@ -3125,6 +3111,49 @@ describe('redactAttributes', () => { feeInBaseCurrency: null, id: '8c623328-6035-4b5f-b6d5-702cc1c9c56b', quantity: null, + type: 'BUY', + // A price per unit stays visible, like the average price and the market + // price of a holding + unitPrice: 220.79, + value: null, + valueInBaseCurrency: null + }); + }); + + // The endpoint POST api/v1/activities returns a row of the database with the + // relation to the symbol profile + it('should redact an activity with the relation to the symbol profile', () => { + expect( + redactPaths({ + object: { + comment: 'Bought on a dip', + currency: 'USD', + fee: 19.9, + id: '8c623328-6035-4b5f-b6d5-702cc1c9c56b', + quantity: 50, + SymbolProfile: { + comment: 'Reviewed by the administrator', + name: 'Apple Inc', + scraperConfiguration: { + headers: { Authorization: 'Bearer TOKEN' }, + mode: 'lazy', + selector: '.price', + url: 'https://example.org/get_price' + }, + symbol: 'AAPL', + symbolMapping: { YAHOO: 'AAPL' } + }, + type: 'BUY', + unitPrice: 220.79 + }, + paths: DEFAULT_REDACTED_PATHS + }) + ).toStrictEqual({ + comment: null, + currency: 'USD', + fee: null, + id: '8c623328-6035-4b5f-b6d5-702cc1c9c56b', + quantity: null, SymbolProfile: { comment: null, name: 'Apple Inc', @@ -3133,15 +3162,12 @@ describe('redactAttributes', () => { symbolMapping: null }, type: 'BUY', - // A price per unit stays visible, like the average price and the market - // price of a holding - unitPrice: 220.79, - value: null, - valueInBaseCurrency: null + unitPrice: 220.79 }); }); - // The write endpoints return a row of the database, which has no relation + // The endpoints PUT and DELETE api/v1/activities/:id return a row of the + // database without the relations it('should redact an activity without the relations', () => { expect( redactPaths({ @@ -3190,18 +3216,6 @@ describe('redactAttributes', () => { currency: 'USD', fee: 19.9, quantity: 50, - SymbolProfile: { - comment: 'Reviewed by the administrator', - name: 'Apple Inc', - scraperConfiguration: { - headers: { Authorization: 'Bearer TOKEN' }, - mode: 'lazy', - selector: '.price', - url: 'https://example.org/get_price' - }, - symbol: 'AAPL', - symbolMapping: { YAHOO: 'AAPL' } - }, type: 'BUY', unitPrice: 220.79, value: 11039.5, @@ -3227,13 +3241,6 @@ describe('redactAttributes', () => { currency: 'USD', fee: null, quantity: null, - SymbolProfile: { - comment: null, - name: 'Apple Inc', - scraperConfiguration: null, - symbol: 'AAPL', - symbolMapping: null - }, type: 'BUY', unitPrice: 220.79, value: null, diff --git a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts index 968159cbac..eedc808772 100644 --- a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts +++ b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts @@ -84,7 +84,6 @@ export class TransformDataSourceInResponseInterceptor< '["filters.dataSource"]', 'activities[*].assetProfile.dataSource', 'activities[*].dataSource', - 'activities[*].SymbolProfile.dataSource', 'assetProfile.dataSource', 'benchmarks[*].dataSource', 'errors[*].dataSource', @@ -95,7 +94,6 @@ export class TransformDataSourceInResponseInterceptor< 'items[*].dataSource', 'latestActivities[*].assetProfile.dataSource', 'settings["filters.dataSource"]', - 'SymbolProfile.dataSource', 'watchlist[*].dataSource' ] }); diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 5a8aecff36..dbf873df2a 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -138,9 +138,6 @@ export const DEFAULT_REDACTED_PATHS = [ 'activities[*].feeInAssetProfileCurrency', 'activities[*].feeInBaseCurrency', 'activities[*].quantity', - 'activities[*].SymbolProfile.comment', - 'activities[*].SymbolProfile.scraperConfiguration', - 'activities[*].SymbolProfile.symbolMapping', 'activities[*].value', 'activities[*].valueInBaseCurrency', 'assetProfile.comment',