Browse Source

Provide data provider info in search

pull/2958/head
Thomas Kaul 2 years ago
parent
commit
97386fdafb
  1. 2
      apps/api/src/app/symbol/interfaces/lookup-item.interface.ts
  2. 10
      apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts
  3. 15
      apps/api/src/services/data-provider/coingecko/coingecko.service.ts
  4. 35
      apps/api/src/services/data-provider/data-provider.service.ts
  5. 10
      apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts
  6. 15
      apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts
  7. 17
      apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts
  8. 3
      apps/api/src/services/data-provider/interfaces/data-provider.interface.ts
  9. 17
      apps/api/src/services/data-provider/manual/manual.service.ts
  10. 7
      apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts
  11. 8
      apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts
  12. 5
      libs/common/src/lib/interfaces/data-provider-info.interface.ts
  13. 11
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html
  14. 2
      libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.module.ts

2
apps/api/src/app/symbol/interfaces/lookup-item.interface.ts

@ -1,9 +1,11 @@
import { DataProviderInfo } from '@ghostfolio/common/interfaces';
import { AssetClass, AssetSubClass, DataSource } from '@prisma/client'; import { AssetClass, AssetSubClass, DataSource } from '@prisma/client';
export interface LookupItem { export interface LookupItem {
assetClass: AssetClass; assetClass: AssetClass;
assetSubClass: AssetSubClass; assetSubClass: AssetSubClass;
currency: string; currency: string;
dataProviderInfo: DataProviderInfo;
dataSource: DataSource; dataSource: DataSource;
name: string; name: string;
symbol: string; symbol: string;

10
apps/api/src/services/data-provider/alpha-vantage/alpha-vantage.service.ts

@ -12,6 +12,7 @@ import {
IDataProviderResponse IDataProviderResponse
} from '@ghostfolio/api/services/interfaces/interfaces'; } from '@ghostfolio/api/services/interfaces/interfaces';
import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { DataProviderInfo } from '@ghostfolio/common/interfaces';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSource, SymbolProfile } from '@prisma/client'; import { DataSource, SymbolProfile } from '@prisma/client';
import * as Alphavantage from 'alphavantage'; import * as Alphavantage from 'alphavantage';
@ -35,6 +36,12 @@ export class AlphaVantageService implements DataProviderInterface {
return !!this.configurationService.get('ALPHA_VANTAGE_API_KEY'); return !!this.configurationService.get('ALPHA_VANTAGE_API_KEY');
} }
public getDataProviderInfo(): DataProviderInfo {
return {
isPremium: false
};
}
public async getAssetProfile( public async getAssetProfile(
aSymbol: string aSymbol: string
): Promise<Partial<SymbolProfile>> { ): Promise<Partial<SymbolProfile>> {
@ -114,10 +121,11 @@ export class AlphaVantageService implements DataProviderInterface {
return { return {
items: result?.bestMatches?.map((bestMatch) => { items: result?.bestMatches?.map((bestMatch) => {
return { return <LookupItem>{
assetClass: undefined, assetClass: undefined,
assetSubClass: undefined, assetSubClass: undefined,
currency: bestMatch['8. currency'], currency: bestMatch['8. currency'],
dataProviderInfo: this.getDataProviderInfo(),
dataSource: this.getName(), dataSource: this.getName(),
name: bestMatch['2. name'], name: bestMatch['2. name'],
symbol: bestMatch['1. symbol'] symbol: bestMatch['1. symbol']

15
apps/api/src/services/data-provider/coingecko/coingecko.service.ts

@ -91,6 +91,14 @@ export class CoinGeckoService implements DataProviderInterface {
return response; return response;
} }
public getDataProviderInfo(): DataProviderInfo {
return {
isPremium: false,
name: 'CoinGecko',
url: 'https://coingecko.com'
};
}
public async getDividends({}: GetDividendsParams) { public async getDividends({}: GetDividendsParams) {
return {}; return {};
} }
@ -252,11 +260,4 @@ export class CoinGeckoService implements DataProviderInterface {
return { items }; return { items };
} }
private getDataProviderInfo(): DataProviderInfo {
return {
name: 'CoinGecko',
url: 'https://coingecko.com'
};
}
} }

35
apps/api/src/services/data-provider/data-provider.service.ts

@ -520,20 +520,15 @@ export class DataProviderService {
return { items: lookupItems }; return { items: lookupItems };
} }
let dataSources = this.configurationService.get('DATA_SOURCES'); let dataProviderServices = this.configurationService
.get('DATA_SOURCES')
if ( .map((dataSource) => {
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && return this.getDataProvider(DataSource[dataSource]);
user.subscription.type === 'Basic'
) {
dataSources = dataSources.filter((dataSource) => {
return !this.isPremiumDataSource(DataSource[dataSource]);
}); });
}
for (const dataSource of dataSources) { for (const dataProviderService of dataProviderServices) {
promises.push( promises.push(
this.getDataProvider(DataSource[dataSource]).search({ dataProviderService.search({
includeIndices, includeIndices,
query query
}) })
@ -555,6 +550,16 @@ export class DataProviderService {
}) })
.sort(({ name: name1 }, { name: name2 }) => { .sort(({ name: name1 }, { name: name2 }) => {
return name1?.toLowerCase().localeCompare(name2?.toLowerCase()); return name1?.toLowerCase().localeCompare(name2?.toLowerCase());
})
.map((lookupItem) => {
if (
!this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') ||
user.subscription.type === 'Premium'
) {
lookupItem.dataProviderInfo.isPremium = false;
}
return lookupItem;
}); });
return { return {
@ -602,14 +607,6 @@ export class DataProviderService {
}); });
} }
private isPremiumDataSource(aDataSource: DataSource) {
const premiumDataSources: DataSource[] = [
DataSource.EOD_HISTORICAL_DATA,
DataSource.FINANCIAL_MODELING_PREP
];
return premiumDataSources.includes(aDataSource);
}
private transformHistoricalData({ private transformHistoricalData({
allData, allData,
currency, currency,

10
apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts

@ -16,6 +16,7 @@ import {
REPLACE_NAME_PARTS REPLACE_NAME_PARTS
} from '@ghostfolio/common/config'; } from '@ghostfolio/common/config';
import { DATE_FORMAT, isCurrency } from '@ghostfolio/common/helper'; import { DATE_FORMAT, isCurrency } from '@ghostfolio/common/helper';
import { DataProviderInfo } from '@ghostfolio/common/interfaces';
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { import {
AssetClass, AssetClass,
@ -58,6 +59,12 @@ export class EodHistoricalDataService implements DataProviderInterface {
}; };
} }
public getDataProviderInfo(): DataProviderInfo {
return {
isPremium: true
};
}
public async getDividends({ public async getDividends({
from, from,
requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'), requestTimeout = this.configurationService.get('REQUEST_TIMEOUT'),
@ -312,7 +319,8 @@ export class EodHistoricalDataService implements DataProviderInterface {
dataSource, dataSource,
name, name,
symbol, symbol,
currency: this.convertCurrency(currency) currency: this.convertCurrency(currency),
dataProviderInfo: this.getDataProviderInfo()
}; };
} }
) )

15
apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts

@ -45,6 +45,14 @@ export class FinancialModelingPrepService implements DataProviderInterface {
}; };
} }
public getDataProviderInfo(): DataProviderInfo {
return {
isPremium: true,
name: 'Financial Modeling Prep',
url: 'https://financialmodelingprep.com/developer/docs'
};
}
public async getDividends({}: GetDividendsParams) { public async getDividends({}: GetDividendsParams) {
return {}; return {};
} }
@ -202,11 +210,4 @@ export class FinancialModelingPrepService implements DataProviderInterface {
return { items }; return { items };
} }
private getDataProviderInfo(): DataProviderInfo {
return {
name: 'Financial Modeling Prep',
url: 'https://financialmodelingprep.com/developer/docs'
};
}
} }

17
apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts

@ -14,6 +14,7 @@ import {
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service';
import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper'; import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper';
import { DataProviderInfo } from '@ghostfolio/common/interfaces';
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 { format } from 'date-fns'; import { format } from 'date-fns';
@ -40,6 +41,12 @@ export class GoogleSheetsService implements DataProviderInterface {
}; };
} }
public getDataProviderInfo(): DataProviderInfo {
return {
isPremium: false
};
}
public async getDividends({}: GetDividendsParams) { public async getDividends({}: GetDividendsParams) {
return {}; return {};
} }
@ -145,6 +152,10 @@ export class GoogleSheetsService implements DataProviderInterface {
return 'INDEXSP:.INX'; return 'INDEXSP:.INX';
} }
public isPremium() {
return false;
}
public async search({ public async search({
query query
}: GetSearchParams): Promise<{ items: LookupItem[] }> { }: GetSearchParams): Promise<{ items: LookupItem[] }> {
@ -177,7 +188,11 @@ export class GoogleSheetsService implements DataProviderInterface {
} }
}); });
return { items }; return {
items: items.map((item) => {
return { ...item, dataProviderInfo: this.getDataProviderInfo() };
})
};
} }
private async getSheet({ private async getSheet({

3
apps/api/src/services/data-provider/interfaces/data-provider.interface.ts

@ -3,6 +3,7 @@ import {
IDataProviderHistoricalResponse, IDataProviderHistoricalResponse,
IDataProviderResponse IDataProviderResponse
} from '@ghostfolio/api/services/interfaces/interfaces'; } from '@ghostfolio/api/services/interfaces/interfaces';
import { DataProviderInfo } from '@ghostfolio/common/interfaces';
import { Granularity } from '@ghostfolio/common/types'; import { Granularity } from '@ghostfolio/common/types';
import { DataSource, SymbolProfile } from '@prisma/client'; import { DataSource, SymbolProfile } from '@prisma/client';
@ -11,6 +12,8 @@ export interface DataProviderInterface {
getAssetProfile(aSymbol: string): Promise<Partial<SymbolProfile>>; getAssetProfile(aSymbol: string): Promise<Partial<SymbolProfile>>;
getDataProviderInfo(): DataProviderInfo;
getDividends({ from, granularity, symbol, to }: GetDividendsParams): Promise<{ getDividends({ from, granularity, symbol, to }: GetDividendsParams): Promise<{
[date: string]: IDataProviderHistoricalResponse; [date: string]: IDataProviderHistoricalResponse;
}>; }>;

17
apps/api/src/services/data-provider/manual/manual.service.ts

@ -18,7 +18,10 @@ import {
extractNumberFromString, extractNumberFromString,
getYesterday getYesterday
} from '@ghostfolio/common/helper'; } from '@ghostfolio/common/helper';
import { ScraperConfiguration } from '@ghostfolio/common/interfaces'; import {
DataProviderInfo,
ScraperConfiguration
} from '@ghostfolio/common/interfaces';
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 * as cheerio from 'cheerio'; import * as cheerio from 'cheerio';
@ -59,6 +62,12 @@ export class ManualService implements DataProviderInterface {
return assetProfile; return assetProfile;
} }
public getDataProviderInfo(): DataProviderInfo {
return {
isPremium: false
};
}
public async getDividends({}: GetDividendsParams) { public async getDividends({}: GetDividendsParams) {
return {}; return {};
} }
@ -214,7 +223,11 @@ export class ManualService implements DataProviderInterface {
return !isUUID(symbol); return !isUUID(symbol);
}); });
return { items }; return {
items: items.map((item) => {
return { ...item, dataProviderInfo: this.getDataProviderInfo() };
})
};
} }
public async test(scraperConfiguration: ScraperConfiguration) { public async test(scraperConfiguration: ScraperConfiguration) {

7
apps/api/src/services/data-provider/rapid-api/rapid-api.service.ts

@ -13,6 +13,7 @@ import {
} from '@ghostfolio/api/services/interfaces/interfaces'; } from '@ghostfolio/api/services/interfaces/interfaces';
import { ghostfolioFearAndGreedIndexSymbol } from '@ghostfolio/common/config'; import { ghostfolioFearAndGreedIndexSymbol } from '@ghostfolio/common/config';
import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper'; import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper';
import { DataProviderInfo } from '@ghostfolio/common/interfaces';
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 { format } from 'date-fns'; import { format } from 'date-fns';
@ -37,6 +38,12 @@ export class RapidApiService implements DataProviderInterface {
}; };
} }
public getDataProviderInfo(): DataProviderInfo {
return {
isPremium: false
};
}
public async getDividends({}: GetDividendsParams) { public async getDividends({}: GetDividendsParams) {
return {}; return {};
} }

8
apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts

@ -14,6 +14,7 @@ import {
} from '@ghostfolio/api/services/interfaces/interfaces'; } from '@ghostfolio/api/services/interfaces/interfaces';
import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; import { DEFAULT_CURRENCY } from '@ghostfolio/common/config';
import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { DataProviderInfo } from '@ghostfolio/common/interfaces';
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 { addDays, format, isSameDay } from 'date-fns'; import { addDays, format, isSameDay } from 'date-fns';
@ -47,6 +48,12 @@ export class YahooFinanceService implements DataProviderInterface {
}; };
} }
public getDataProviderInfo(): DataProviderInfo {
return {
isPremium: false
};
}
public async getDividends({ public async getDividends({
from, from,
granularity = 'day', granularity = 'day',
@ -283,6 +290,7 @@ export class YahooFinanceService implements DataProviderInterface {
assetSubClass, assetSubClass,
symbol, symbol,
currency: marketDataItem.currency, currency: marketDataItem.currency,
dataProviderInfo: this.getDataProviderInfo(),
dataSource: this.getName(), dataSource: this.getName(),
name: this.yahooFinanceDataEnhancerService.formatName({ name: this.yahooFinanceDataEnhancerService.formatName({
longName: quote.longname, longName: quote.longname,

5
libs/common/src/lib/interfaces/data-provider-info.interface.ts

@ -1,4 +1,5 @@
export interface DataProviderInfo { export interface DataProviderInfo {
name: string; isPremium: boolean;
url: string; name?: string;
url?: string;
} }

11
libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html

@ -15,12 +15,15 @@
<mat-option <mat-option
*ngFor="let lookupItem of filteredLookupItems" *ngFor="let lookupItem of filteredLookupItems"
class="line-height-1" class="line-height-1"
[disabled]="lookupItem.dataProviderInfo.isPremium"
[value]="lookupItem" [value]="lookupItem"
> >
<span <span class="align-items-center d-flex"
><b>{{ lookupItem.name }}</b></span ><b>{{ lookupItem.name }}</b>
> @if (lookupItem.dataProviderInfo.isPremium) {
<br /> <gf-premium-indicator class="ml-1" [enableLink]="false" />
}
</span>
<small class="text-muted" <small class="text-muted"
>{{ lookupItem.symbol | gfSymbol }} · {{ lookupItem.currency >{{ lookupItem.symbol | gfSymbol }} · {{ lookupItem.currency
}}<ng-container *ngIf="lookupItem.assetSubClass"> }}<ng-container *ngIf="lookupItem.assetSubClass">

2
libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.module.ts

@ -7,6 +7,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module'; import { GfSymbolModule } from '@ghostfolio/client/pipes/symbol/symbol.module';
import { SymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplete/symbol-autocomplete.component'; import { SymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplete/symbol-autocomplete.component';
import { GfPremiumIndicatorModule } from '@ghostfolio/ui/premium-indicator';
@NgModule({ @NgModule({
declarations: [SymbolAutocompleteComponent], declarations: [SymbolAutocompleteComponent],
@ -14,6 +15,7 @@ import { SymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplete/
imports: [ imports: [
CommonModule, CommonModule,
FormsModule, FormsModule,
GfPremiumIndicatorModule,
GfSymbolModule, GfSymbolModule,
MatAutocompleteModule, MatAutocompleteModule,
MatFormFieldModule, MatFormFieldModule,

Loading…
Cancel
Save