From 408bdbd187d89518f1f52ac437d17bfbb4a1f295 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 3 Sep 2022 10:06:16 +0200 Subject: [PATCH] Bugfix/fix GitHub contributors count (#1219) * Fix GitHub contributors count * Update changelog --- CHANGELOG.md | 1 + apps/api/src/app/info/info.service.ts | 26 ++++++++++++------- .../ghostfolio-scraper-api.service.ts | 21 +++++---------- libs/common/src/lib/helper.ts | 11 ++++++++ 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5da67db5..df5d60af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Made the environment variables `REDIS_HOST` and `REDIS_PORT` mandatory - Handled errors in the portfolio calculation if there is no internet connection +- Fixed the _GitHub_ contributors count on the about page ## 1.185.0 - 30.08.2022 diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index e1f1e56c..74369b9c 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -1,6 +1,5 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; -import { DataGatheringService } from '@ghostfolio/api/services/data-gathering.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service'; import { PrismaService } from '@ghostfolio/api/services/prisma.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; @@ -13,7 +12,10 @@ import { PROPERTY_SYSTEM_MESSAGE, ghostfolioFearAndGreedIndexDataSource } from '@ghostfolio/common/config'; -import { encodeDataSource } from '@ghostfolio/common/helper'; +import { + encodeDataSource, + extractNumberFromString +} from '@ghostfolio/common/helper'; import { InfoItem } from '@ghostfolio/common/interfaces'; import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface'; import { Subscription } from '@ghostfolio/common/interfaces/subscription.interface'; @@ -21,6 +23,7 @@ import { permissions } from '@ghostfolio/common/permissions'; import { Injectable, Logger } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as bent from 'bent'; +import * as cheerio from 'cheerio'; import { subDays } from 'date-fns'; @Injectable() @@ -30,7 +33,6 @@ export class InfoService { public constructor( private readonly configurationService: ConfigurationService, private readonly exchangeRateDataService: ExchangeRateDataService, - private readonly dataGatheringService: DataGatheringService, private readonly jwtService: JwtService, private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, @@ -143,17 +145,21 @@ export class InfoService { private async countGitHubContributors(): Promise { try { const get = bent( - `https://api.github.com/repos/ghostfolio/ghostfolio/contributors`, + 'https://github.com/ghostfolio/ghostfolio', 'GET', - 'json', + 'string', 200, - { - 'User-Agent': 'request' - } + {} ); - const contributors = await get(); - return contributors?.length; + const html = await get(); + const $ = cheerio.load(html); + + return extractNumberFromString( + $( + `a[href="/ghostfolio/ghostfolio/graphs/contributors"] .Counter` + ).text() + ); } catch (error) { Logger.error(error, 'InfoService'); diff --git a/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts b/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts index 373922fe..8da34410 100644 --- a/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts +++ b/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts @@ -6,7 +6,11 @@ import { } from '@ghostfolio/api/services/interfaces/interfaces'; import { PrismaService } from '@ghostfolio/api/services/prisma.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service'; -import { DATE_FORMAT, getYesterday } from '@ghostfolio/common/helper'; +import { + DATE_FORMAT, + extractNumberFromString, + getYesterday +} from '@ghostfolio/common/helper'; import { Granularity } from '@ghostfolio/common/types'; import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; @@ -16,8 +20,6 @@ import { addDays, format, isBefore } from 'date-fns'; @Injectable() export class GhostfolioScraperApiService implements DataProviderInterface { - private static NUMERIC_REGEXP = /[-]{0,1}[\d]*[.,]{0,1}[\d]+/g; - public constructor( private readonly prismaService: PrismaService, private readonly symbolProfileService: SymbolProfileService @@ -77,7 +79,7 @@ export class GhostfolioScraperApiService implements DataProviderInterface { const html = await get(); const $ = cheerio.load(html); - const value = this.extractNumberFromString($(selector).text()); + const value = extractNumberFromString($(selector).text()); return { [symbol]: { @@ -175,15 +177,4 @@ export class GhostfolioScraperApiService implements DataProviderInterface { return { items }; } - - private extractNumberFromString(aString: string): number { - try { - const [numberString] = aString.match( - GhostfolioScraperApiService.NUMERIC_REGEXP - ); - return parseFloat(numberString.trim()); - } catch { - return undefined; - } - } } diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index dfb20034..cc104b27 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -6,6 +6,8 @@ import { de } from 'date-fns/locale'; import { ghostfolioScraperApiSymbolPrefix, locale } from './config'; import { Benchmark } from './interfaces'; +const NUMERIC_REGEXP = /[-]{0,1}[\d]*[.,]{0,1}[\d]+/g; + export function capitalize(aString: string) { return aString.charAt(0).toUpperCase() + aString.slice(1).toLowerCase(); } @@ -43,6 +45,15 @@ export function encodeDataSource(aDataSource: DataSource) { return Buffer.from(aDataSource, 'utf-8').toString('hex'); } +export function extractNumberFromString(aString: string): number { + try { + const [numberString] = aString.match(NUMERIC_REGEXP); + return parseFloat(numberString.trim()); + } catch { + return undefined; + } +} + export function getBackgroundColor() { return getCssVariable( window.matchMedia('(prefers-color-scheme: dark)').matches