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
- Deprecated `SymbolProfile` in favor of `assetProfile` in the endpoint `POST api/v1/activities`
- Upgraded `Nx` from version `23.1.1` to `23.2.1`
### 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 { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.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 { DATA_GATHERING_QUEUE_PRIORITY_HIGH } from '@ghostfolio/common/config';
import { CreateOrderDto, UpdateOrderDto } from '@ghostfolio/common/dtos';
import { SubscriptionType } from '@ghostfolio/common/enums';
import {
ActivitiesResponse,
ActivityResponse
ActivityResponse,
CreateActivityResponse
} from '@ghostfolio/common/interfaces';
import { permissions } from '@ghostfolio/common/permissions';
import { scopes } from '@ghostfolio/common/scopes';
@ -33,7 +35,7 @@ import {
Query,
UseInterceptors
} from '@nestjs/common';
import { Order, Prisma } from '@prisma/client';
import { Order } from '@prisma/client';
import { parseISO } from 'date-fns';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
@ -47,7 +49,8 @@ export class ActivitiesController {
private readonly activitiesService: ActivitiesService,
private readonly apiService: ApiService,
private readonly dataProviderService: DataProviderService,
private readonly dataGatheringService: DataGatheringService
private readonly dataGatheringService: DataGatheringService,
private readonly symbolProfileService: SymbolProfileService
) {}
@Delete()
@ -209,6 +212,7 @@ export class ActivitiesController {
@RequiresScope(scopes.activityCreate)
@UseInterceptors(RedactValuesInResponseInterceptor)
@UseInterceptors(TransformDataSourceInRequestInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor)
public async createActivity(
@Body() data: CreateOrderDto,
@Impersonation()
@ -217,7 +221,7 @@ export class ActivitiesController {
userId,
userSubscription
}: ImpersonationContext
): Promise<Prisma.OrderGetPayload<{ include: { SymbolProfile: true } }>> {
): Promise<CreateActivityResponse> {
// Evaluate the more restrictive subscription of the authenticated user
// and the owner of the activity
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)

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
// relation to the symbol profile
it('should redact an activity with the relation to the symbol profile', () => {
// asset profile and the deprecated relation to the symbol profile
it('should redact an activity with the asset profile and the relation to the symbol profile', () => {
expect(
redactPaths({
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',
currency: 'USD',
fee: 19.9,
@ -3149,6 +3162,14 @@ describe('redactAttributes', () => {
paths: DEFAULT_REDACTED_PATHS
})
).toStrictEqual({
assetProfile: {
comment: null,
name: 'Apple Inc',
scraperConfiguration: null,
symbol: 'AAPL',
symbolMapping: null,
watchedByCount: null
},
comment: null,
currency: 'USD',
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',
'latestActivities[*].assetProfile.dataSource',
'settings["filters.dataSource"]',
/* @deprecated */
'SymbolProfile.dataSource',
'watchlist[*].dataSource'
]
});

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

@ -180,9 +180,16 @@ export const DEFAULT_REDACTED_PATHS = [
'settings.emergencyFund',
'settings.projectedTotalAmount',
'settings.savingsRate',
/* @deprecated */
'SymbolProfile.comment',
/* @deprecated */
'SymbolProfile.scraperConfiguration',
/* @deprecated */
'SymbolProfile.symbolMapping',
'totalBalanceInBaseCurrency',
'totalDividendInBaseCurrency',
'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 { BenchmarkMarketDataDetailsResponse } from './responses/benchmark-market-data-details-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 { DataEnhancerHealthResponse } from './responses/data-enhancer-health-response.interface';
import type { DataProviderGhostfolioAssetProfileResponse } from './responses/data-provider-ghostfolio-asset-profile-response.interface';
@ -133,6 +134,7 @@ export {
BenchmarkProperty,
BenchmarkResponse,
Coupon,
CreateActivityResponse,
CreateStripeCheckoutSessionResponse,
DataEnhancerHealthResponse,
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,
BenchmarkMarketDataDetailsResponse,
BenchmarkResponse,
CreateActivityResponse,
CreateStripeCheckoutSessionResponse,
DataProviderHealthResponse,
DataProviderHistoricalResponse,
@ -873,7 +874,7 @@ export class DataService {
}
public postActivity(aOrder: CreateOrderDto) {
return this.http.post<Order>('/api/v1/activities', aOrder);
return this.http.post<CreateActivityResponse>('/api/v1/activities', aOrder);
}
public postApiKey() {

Loading…
Cancel
Save