Feature/copy logic of ghostfolio scraper api service to manual service (#1691)

* Copy logic of GhostfolioScraperApiService to ManualService

* Update changelog
pull/1700/head
Thomas Kaul 2 years ago committed by GitHub
parent d6b71e6314
commit e62989c981
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Copy logic of `GhostfolioScraperApiService` to `ManualService`
- Improved the content of the landing page - Improved the content of the landing page
- Improved the content of the Frequently Asked Questions (FAQ) page - Improved the content of the Frequently Asked Questions (FAQ) page
- Set the exposed port as an environment variable (`PORT`) in `Dockerfile` - Set the exposed port as an environment variable (`PORT`) in `Dockerfile`
@ -26,6 +27,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed an issue on the landing page caused by the global heat map of subscribers - Fixed an issue on the landing page caused by the global heat map of subscribers
- Fixed the links in the interstitial for the subscription - Fixed the links in the interstitial for the subscription
### Todo
- Rename the `dataSource` from `GHOSTFOLIO` to `MANUAL`
- Eliminate `GhostfolioScraperApiService`
## 1.233.0 - 2023-02-09 ## 1.233.0 - 2023-02-09
### Added ### Added

@ -65,7 +65,7 @@ export class GhostfolioScraperApiService implements DataProviderInterface {
const [symbolProfile] = const [symbolProfile] =
await this.symbolProfileService.getSymbolProfilesBySymbols([symbol]); await this.symbolProfileService.getSymbolProfilesBySymbols([symbol]);
const { defaultMarketPrice, selector, url } = const { defaultMarketPrice, selector, url } =
symbolProfile.scraperConfiguration; symbolProfile.scraperConfiguration ?? {};
if (defaultMarketPrice) { if (defaultMarketPrice) {
const historical: { const historical: {
@ -148,7 +148,7 @@ export class GhostfolioScraperApiService implements DataProviderInterface {
dataSource: this.getName(), dataSource: this.getName(),
marketPrice: marketData.find((marketDataItem) => { marketPrice: marketData.find((marketDataItem) => {
return marketDataItem.symbol === symbolProfile.symbol; return marketDataItem.symbol === symbolProfile.symbol;
}).marketPrice, })?.marketPrice,
marketState: 'delayed' marketState: 'delayed'
}; };
} }

@ -6,9 +6,17 @@ import {
} from '@ghostfolio/api/services/interfaces/interfaces'; } from '@ghostfolio/api/services/interfaces/interfaces';
import { PrismaService } from '@ghostfolio/api/services/prisma.service'; import { PrismaService } from '@ghostfolio/api/services/prisma.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service';
import {
DATE_FORMAT,
extractNumberFromString,
getYesterday
} from '@ghostfolio/common/helper';
import { Granularity } from '@ghostfolio/common/types'; import { Granularity } from '@ghostfolio/common/types';
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { DataSource, SymbolProfile } from '@prisma/client'; import { DataSource, SymbolProfile } from '@prisma/client';
import bent from 'bent';
import * as cheerio from 'cheerio';
import { addDays, format, isBefore } from 'date-fns';
@Injectable() @Injectable()
export class ManualService implements DataProviderInterface { export class ManualService implements DataProviderInterface {
@ -18,7 +26,7 @@ export class ManualService implements DataProviderInterface {
) {} ) {}
public canHandle(symbol: string) { public canHandle(symbol: string) {
return false; return true;
} }
public async getAssetProfile( public async getAssetProfile(
@ -51,7 +59,57 @@ export class ManualService implements DataProviderInterface {
): Promise<{ ): Promise<{
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; [symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
}> { }> {
return {}; try {
const symbol = aSymbol;
const [symbolProfile] =
await this.symbolProfileService.getSymbolProfilesBySymbols([symbol]);
const { defaultMarketPrice, selector, url } =
symbolProfile.scraperConfiguration ?? {};
if (defaultMarketPrice) {
const historical: {
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse };
} = {
[symbol]: {}
};
let date = from;
while (isBefore(date, to)) {
historical[symbol][format(date, DATE_FORMAT)] = {
marketPrice: defaultMarketPrice
};
date = addDays(date, 1);
}
return historical;
} else if (selector === undefined || url === undefined) {
return {};
}
const get = bent(url, 'GET', 'string', 200, {});
const html = await get();
const $ = cheerio.load(html);
const value = extractNumberFromString($(selector).text());
return {
[symbol]: {
[format(getYesterday(), DATE_FORMAT)]: {
marketPrice: value
}
}
};
} catch (error) {
throw new Error(
`Could not get historical market data for ${aSymbol} (${this.getName()}) from ${format(
from,
DATE_FORMAT
)} to ${format(to, DATE_FORMAT)}: [${error.name}] ${error.message}`
);
}
} }
public getName(): DataSource { public getName(): DataSource {
@ -88,10 +146,9 @@ export class ManualService implements DataProviderInterface {
response[symbolProfile.symbol] = { response[symbolProfile.symbol] = {
currency: symbolProfile.currency, currency: symbolProfile.currency,
dataSource: this.getName(), dataSource: this.getName(),
marketPrice: marketPrice: marketData.find((marketDataItem) => {
marketData.find((marketDataItem) => { return marketDataItem.symbol === symbolProfile.symbol;
return marketDataItem.symbol === symbolProfile.symbol; })?.marketPrice,
})?.marketPrice ?? 0,
marketState: 'delayed' marketState: 'delayed'
}; };
} }

Loading…
Cancel
Save