Browse Source

Task/deprecate symbol profile in create activity endpoint (#8026)

* Deprecate SymbolProfile in favor of assetProfile

* Update changelog
pull/8059/head
Thomas Kaul 4 days ago
committed by GitHub
parent
commit
e8f7c34a46
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 21
      apps/api/src/app/activities/activities.controller.ts
  3. 25
      apps/api/src/helper/object.helper.spec.ts
  4. 4
      apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts
  5. 7
      libs/common/src/lib/config.ts
  6. 2
      libs/common/src/lib/interfaces/index.ts
  7. 12
      libs/common/src/lib/interfaces/responses/create-activity-response.interface.ts
  8. 3
      libs/ui/src/lib/services/data.service.ts

1
CHANGELOG.md

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Deprecated `SymbolProfile` in favor of `assetProfile` in the endpoint `POST api/v1/activities`
- Upgraded `Nx` from version `23.1.1` to `23.2.1` - Upgraded `Nx` from version `23.1.1` to `23.2.1`
### Fixed ### Fixed

21
apps/api/src/app/activities/activities.controller.ts

@ -9,13 +9,15 @@ import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interc
import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { ApiService } from '@ghostfolio/api/services/api/api.service';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper';
import { DATA_GATHERING_QUEUE_PRIORITY_HIGH } from '@ghostfolio/common/config'; import { DATA_GATHERING_QUEUE_PRIORITY_HIGH } from '@ghostfolio/common/config';
import { CreateOrderDto, UpdateOrderDto } from '@ghostfolio/common/dtos'; import { CreateOrderDto, UpdateOrderDto } from '@ghostfolio/common/dtos';
import { SubscriptionType } from '@ghostfolio/common/enums'; import { SubscriptionType } from '@ghostfolio/common/enums';
import { import {
ActivitiesResponse, ActivitiesResponse,
ActivityResponse ActivityResponse,
CreateActivityResponse
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions'; import { permissions } from '@ghostfolio/common/permissions';
import { scopes } from '@ghostfolio/common/scopes'; import { scopes } from '@ghostfolio/common/scopes';
@ -33,7 +35,7 @@ import {
Query, Query,
UseInterceptors UseInterceptors
} from '@nestjs/common'; } from '@nestjs/common';
import { Order, Prisma } from '@prisma/client'; import { Order } from '@prisma/client';
import { parseISO } from 'date-fns'; import { parseISO } from 'date-fns';
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { StatusCodes, getReasonPhrase } from 'http-status-codes';
@ -47,7 +49,8 @@ export class ActivitiesController {
private readonly activitiesService: ActivitiesService, private readonly activitiesService: ActivitiesService,
private readonly apiService: ApiService, private readonly apiService: ApiService,
private readonly dataProviderService: DataProviderService, private readonly dataProviderService: DataProviderService,
private readonly dataGatheringService: DataGatheringService private readonly dataGatheringService: DataGatheringService,
private readonly symbolProfileService: SymbolProfileService
) {} ) {}
@Delete() @Delete()
@ -209,6 +212,7 @@ export class ActivitiesController {
@RequiresScope(scopes.activityCreate) @RequiresScope(scopes.activityCreate)
@UseInterceptors(RedactValuesInResponseInterceptor) @UseInterceptors(RedactValuesInResponseInterceptor)
@UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInRequestInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor)
public async createActivity( public async createActivity(
@Body() data: CreateOrderDto, @Body() data: CreateOrderDto,
@Impersonation() @Impersonation()
@ -217,7 +221,7 @@ export class ActivitiesController {
userId, userId,
userSubscription userSubscription
}: ImpersonationContext }: ImpersonationContext
): Promise<Prisma.OrderGetPayload<{ include: { SymbolProfile: true } }>> { ): Promise<CreateActivityResponse> {
// Evaluate the more restrictive subscription of the authenticated user // Evaluate the more restrictive subscription of the authenticated user
// and the owner of the activity // and the owner of the activity
const subscription = const subscription =
@ -303,7 +307,14 @@ export class ActivitiesController {
}); });
} }
return activity; const [assetProfile] = await this.symbolProfileService.getSymbolProfiles([
{
dataSource: activity.SymbolProfile.dataSource,
symbol: activity.SymbolProfile.symbol
}
]);
return { ...activity, assetProfile };
} }
@HasPermission(permissions.updateActivity) @HasPermission(permissions.updateActivity)

25
apps/api/src/helper/object.helper.spec.ts

@ -3121,11 +3121,24 @@ describe('redactAttributes', () => {
}); });
// The endpoint POST api/v1/activities returns a row of the database with the // The endpoint POST api/v1/activities returns a row of the database with the
// relation to the symbol profile // asset profile and the deprecated relation to the symbol profile
it('should redact an activity with the relation to the symbol profile', () => { it('should redact an activity with the asset profile and the relation to the symbol profile', () => {
expect( expect(
redactPaths({ redactPaths({
object: { object: {
assetProfile: {
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' },
watchedByCount: 7
},
comment: 'Bought on a dip', comment: 'Bought on a dip',
currency: 'USD', currency: 'USD',
fee: 19.9, fee: 19.9,
@ -3149,6 +3162,14 @@ describe('redactAttributes', () => {
paths: DEFAULT_REDACTED_PATHS paths: DEFAULT_REDACTED_PATHS
}) })
).toStrictEqual({ ).toStrictEqual({
assetProfile: {
comment: null,
name: 'Apple Inc',
scraperConfiguration: null,
symbol: 'AAPL',
symbolMapping: null,
watchedByCount: null
},
comment: null, comment: null,
currency: 'USD', currency: 'USD',
fee: null, fee: null,

4
apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts

@ -94,6 +94,10 @@ export class TransformDataSourceInResponseInterceptor<
'items[*].dataSource', 'items[*].dataSource',
'latestActivities[*].assetProfile.dataSource', 'latestActivities[*].assetProfile.dataSource',
'settings["filters.dataSource"]', 'settings["filters.dataSource"]',
/* @deprecated */
'SymbolProfile.dataSource',
'watchlist[*].dataSource' 'watchlist[*].dataSource'
] ]
}); });

7
libs/common/src/lib/config.ts

@ -180,9 +180,16 @@ export const DEFAULT_REDACTED_PATHS = [
'settings.emergencyFund', 'settings.emergencyFund',
'settings.projectedTotalAmount', 'settings.projectedTotalAmount',
'settings.savingsRate', 'settings.savingsRate',
/* @deprecated */
'SymbolProfile.comment', 'SymbolProfile.comment',
/* @deprecated */
'SymbolProfile.scraperConfiguration', 'SymbolProfile.scraperConfiguration',
/* @deprecated */
'SymbolProfile.symbolMapping', 'SymbolProfile.symbolMapping',
'totalBalanceInBaseCurrency', 'totalBalanceInBaseCurrency',
'totalDividendInBaseCurrency', 'totalDividendInBaseCurrency',
'totalInterestInBaseCurrency', 'totalInterestInBaseCurrency',

2
libs/common/src/lib/interfaces/index.ts

@ -53,6 +53,7 @@ import type { AssetProfilesResponse } from './responses/asset-profiles-response.
import type { AssetResponse } from './responses/asset-response.interface'; import type { AssetResponse } from './responses/asset-response.interface';
import type { BenchmarkMarketDataDetailsResponse } from './responses/benchmark-market-data-details-response.interface'; import type { BenchmarkMarketDataDetailsResponse } from './responses/benchmark-market-data-details-response.interface';
import type { BenchmarkResponse } from './responses/benchmark-response.interface'; import type { BenchmarkResponse } from './responses/benchmark-response.interface';
import type { CreateActivityResponse } from './responses/create-activity-response.interface';
import type { CreateStripeCheckoutSessionResponse } from './responses/create-stripe-checkout-session-response.interface'; import type { CreateStripeCheckoutSessionResponse } from './responses/create-stripe-checkout-session-response.interface';
import type { DataEnhancerHealthResponse } from './responses/data-enhancer-health-response.interface'; import type { DataEnhancerHealthResponse } from './responses/data-enhancer-health-response.interface';
import type { DataProviderGhostfolioAssetProfileResponse } from './responses/data-provider-ghostfolio-asset-profile-response.interface'; import type { DataProviderGhostfolioAssetProfileResponse } from './responses/data-provider-ghostfolio-asset-profile-response.interface';
@ -133,6 +134,7 @@ export {
BenchmarkProperty, BenchmarkProperty,
BenchmarkResponse, BenchmarkResponse,
Coupon, Coupon,
CreateActivityResponse,
CreateStripeCheckoutSessionResponse, CreateStripeCheckoutSessionResponse,
DataEnhancerHealthResponse, DataEnhancerHealthResponse,
DataProviderGhostfolioAssetProfileResponse, DataProviderGhostfolioAssetProfileResponse,

12
libs/common/src/lib/interfaces/responses/create-activity-response.interface.ts

@ -0,0 +1,12 @@
import type { Order, SymbolProfile } from '@ghostfolio/prisma/browser';
import { EnhancedAssetProfile } from '../enhanced-asset-profile.interface';
export interface CreateActivityResponse extends Order {
assetProfile: EnhancedAssetProfile;
/**
* @deprecated Use `assetProfile` instead
*/
SymbolProfile: SymbolProfile;
}

3
libs/ui/src/lib/services/data.service.ts

@ -34,6 +34,7 @@ import {
AssetResponse, AssetResponse,
BenchmarkMarketDataDetailsResponse, BenchmarkMarketDataDetailsResponse,
BenchmarkResponse, BenchmarkResponse,
CreateActivityResponse,
CreateStripeCheckoutSessionResponse, CreateStripeCheckoutSessionResponse,
DataProviderHealthResponse, DataProviderHealthResponse,
DataProviderHistoricalResponse, DataProviderHistoricalResponse,
@ -873,7 +874,7 @@ export class DataService {
} }
public postActivity(aOrder: CreateOrderDto) { public postActivity(aOrder: CreateOrderDto) {
return this.http.post<Order>('/api/v1/activities', aOrder); return this.http.post<CreateActivityResponse>('/api/v1/activities', aOrder);
} }
public postApiKey() { public postApiKey() {

Loading…
Cancel
Save