From 5eff8402db5683d3d229f08e20e535a553f21d5b Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 20 Apr 2023 09:07:22 +0200 Subject: [PATCH] Release/1.258.0 (#1878) * Release 1.258.0 * Introduce data source mapping * Update changelog --- CHANGELOG.md | 6 ++++ .../portfolio/current-rate.service.spec.ts | 21 +++++++++++- .../data-provider/data-provider.module.ts | 2 ++ .../data-provider/data-provider.service.ts | 33 +++++++++++++++++-- .../eod-historical-data.service.ts | 20 +++++++---- .../services/exchange-rate-data.service.ts | 17 ++++++---- libs/common/src/lib/config.ts | 1 + package.json | 2 +- 8 files changed, 85 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dee20fc78..a4e4d1811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.258.0 - 2023-04-20 + +### Added + +- Introduced a data source mapping + ## 1.257.0 - 2023-04-18 ### Added diff --git a/apps/api/src/app/portfolio/current-rate.service.spec.ts b/apps/api/src/app/portfolio/current-rate.service.spec.ts index 9171e5fa3..226d9e7db 100644 --- a/apps/api/src/app/portfolio/current-rate.service.spec.ts +++ b/apps/api/src/app/portfolio/current-rate.service.spec.ts @@ -6,6 +6,7 @@ import { DataSource, MarketData } from '@prisma/client'; import { CurrentRateService } from './current-rate.service'; import { GetValueObject } from './interfaces/get-value-object.interface'; +import { PropertyService } from '@ghostfolio/api/services/property/property.service'; jest.mock('@ghostfolio/api/services/market-data.service', () => { return { @@ -67,14 +68,32 @@ jest.mock('@ghostfolio/api/services/exchange-rate-data.service', () => { }; }); +jest.mock('@ghostfolio/api/services/property/property.service', () => { + return { + PropertyService: jest.fn().mockImplementation(() => { + return { + getByKey: (key: string) => Promise.resolve({}) + }; + }) + }; +}); + describe('CurrentRateService', () => { let currentRateService: CurrentRateService; let dataProviderService: DataProviderService; let exchangeRateDataService: ExchangeRateDataService; let marketDataService: MarketDataService; + let propertyService: PropertyService; beforeAll(async () => { - dataProviderService = new DataProviderService(null, [], null); + propertyService = new PropertyService(null); + + dataProviderService = new DataProviderService( + null, + [], + null, + propertyService + ); exchangeRateDataService = new ExchangeRateDataService( null, null, diff --git a/apps/api/src/services/data-provider/data-provider.module.ts b/apps/api/src/services/data-provider/data-provider.module.ts index e0ff98dda..cfcd70d6b 100644 --- a/apps/api/src/services/data-provider/data-provider.module.ts +++ b/apps/api/src/services/data-provider/data-provider.module.ts @@ -14,6 +14,7 @@ import { Module } from '@nestjs/common'; import { DataEnhancerModule } from './data-enhancer/data-enhancer.module'; import { YahooFinanceDataEnhancerService } from './data-enhancer/yahoo-finance/yahoo-finance.service'; import { DataProviderService } from './data-provider.service'; +import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; @Module({ imports: [ @@ -21,6 +22,7 @@ import { DataProviderService } from './data-provider.service'; CryptocurrencyModule, DataEnhancerModule, PrismaModule, + PropertyModule, SymbolProfileModule ], providers: [ diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index 39bb2e19b..d35e01b6e 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -14,15 +14,29 @@ import { Inject, Injectable, Logger } from '@nestjs/common'; import { DataSource, MarketData, SymbolProfile } from '@prisma/client'; import { format, isValid } from 'date-fns'; import { groupBy, isEmpty } from 'lodash'; +import { PropertyService } from '@ghostfolio/api/services/property/property.service'; +import { PROPERTY_DATA_SOURCE_MAPPING } from '@ghostfolio/common/config'; @Injectable() export class DataProviderService { + private dataProviderMapping: { [dataProviderName: string]: string }; + public constructor( private readonly configurationService: ConfigurationService, @Inject('DataProviderInterfaces') private readonly dataProviderInterfaces: DataProviderInterface[], - private readonly prismaService: PrismaService - ) {} + private readonly prismaService: PrismaService, + private readonly propertyService: PropertyService + ) { + this.initialize(); + } + + public async initialize() { + this.dataProviderMapping = + ((await this.propertyService.getByKey(PROPERTY_DATA_SOURCE_MAPPING)) as { + [dataProviderName: string]: string; + }) ?? {}; + } public async getDividends({ dataSource, @@ -314,6 +328,21 @@ export class DataProviderService { private getDataProvider(providerName: DataSource) { for (const dataProviderInterface of this.dataProviderInterfaces) { + if (this.dataProviderMapping[dataProviderInterface.getName()]) { + const mappedDataProviderInterface = this.dataProviderInterfaces.find( + (currentDataProviderInterface) => { + return ( + currentDataProviderInterface.getName() === + this.dataProviderMapping[dataProviderInterface.getName()] + ); + } + ); + + if (mappedDataProviderInterface) { + return mappedDataProviderInterface; + } + } + if (dataProviderInterface.getName() === providerName) { return dataProviderInterface; } diff --git a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts index 4f1113d3f..910039654 100644 --- a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts +++ b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts @@ -146,12 +146,20 @@ export class EodHistoricalDataService implements DataProviderInterface { result: { [symbol: string]: IDataProviderResponse }, { close, code, timestamp } ) => { - result[code] = { - currency: this.convertCurrency(searchResponse?.items[0]?.currency), - dataSource: DataSource.EOD_HISTORICAL_DATA, - marketPrice: close, - marketState: isToday(new Date(timestamp * 1000)) ? 'open' : 'closed' - }; + const currency = this.convertCurrency( + searchResponse?.items[0]?.currency + ); + + if (currency) { + result[code] = { + currency, + dataSource: DataSource.EOD_HISTORICAL_DATA, + marketPrice: close, + marketState: isToday(new Date(timestamp * 1000)) + ? 'open' + : 'closed' + }; + } return result; }, diff --git a/apps/api/src/services/exchange-rate-data.service.ts b/apps/api/src/services/exchange-rate-data.service.ts index 6f5d215c8..1523c9024 100644 --- a/apps/api/src/services/exchange-rate-data.service.ts +++ b/apps/api/src/services/exchange-rate-data.service.ts @@ -62,7 +62,8 @@ export class ExchangeRateDataService { getYesterday() ); - if (Object.keys(result).length !== this.currencyPairs.length) { + // TODO: add fallback + /*if (Object.keys(result).length !== this.currencyPairs.length) { // Load currencies directly from data provider as a fallback // if historical data is not fully available const historicalData = await this.dataProviderService.getQuotes( @@ -72,13 +73,15 @@ export class ExchangeRateDataService { ); Object.keys(historicalData).forEach((key) => { - result[key] = { - [format(getYesterday(), DATE_FORMAT)]: { - marketPrice: historicalData[key].marketPrice - } - }; + if (isNumber(historicalData[key].marketPrice)) { + result[key] = { + [format(getYesterday(), DATE_FORMAT)]: { + marketPrice: historicalData[key].marketPrice + } + }; + } }); - } + }*/ const resultExtended = result; diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 171ce50d3..4b8a6d083 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -73,6 +73,7 @@ export const PROPERTY_BENCHMARKS = 'BENCHMARKS'; export const PROPERTY_COUNTRIES_OF_SUBSCRIBERS = 'COUNTRIES_OF_SUBSCRIBERS'; export const PROPERTY_COUPONS = 'COUPONS'; export const PROPERTY_CURRENCIES = 'CURRENCIES'; +export const PROPERTY_DATA_SOURCE_MAPPING = 'DATA_SOURCE_MAPPING'; export const PROPERTY_DEMO_USER_ID = 'DEMO_USER_ID'; export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE'; export const PROPERTY_IS_USER_SIGNUP_ENABLED = 'IS_USER_SIGNUP_ENABLED'; diff --git a/package.json b/package.json index 114923b26..66e4fe47e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "1.257.0", + "version": "1.258.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "scripts": {