diff --git a/CHANGELOG.md b/CHANGELOG.md index 809bd804b..3070744ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Added a _Storybook_ story for the entity logo image component + ### Changed +- Improved the search in the _Yahoo Finance_ service - Moved the holdings table into the holdings section on the public page - Migrated to the _Prisma Configuration File_ approach (`prisma.config.ts`) - Refactored the login with access token dialog component to standalone +- Prefixed the `crypto`, `fs` and `path` imports with `node:` ## 2.198.0 - 2025-09-11 diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 1c48b9702..8596aa0eb 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -21,7 +21,7 @@ import { EventEmitterModule } from '@nestjs/event-emitter'; import { ScheduleModule } from '@nestjs/schedule'; import { ServeStaticModule } from '@nestjs/serve-static'; import { StatusCodes } from 'http-status-codes'; -import { join } from 'path'; +import { join } from 'node:path'; import { AccessModule } from './access/access.module'; import { AccountModule } from './account/account.module'; diff --git a/apps/api/src/app/endpoints/assets/assets.controller.ts b/apps/api/src/app/endpoints/assets/assets.controller.ts index 1735cc594..a314b3f19 100644 --- a/apps/api/src/app/endpoints/assets/assets.controller.ts +++ b/apps/api/src/app/endpoints/assets/assets.controller.ts @@ -10,8 +10,8 @@ import { VERSION_NEUTRAL } from '@nestjs/common'; import { Response } from 'express'; -import { readFileSync } from 'fs'; -import { join } from 'path'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; @Controller('assets') export class AssetsController { diff --git a/apps/api/src/app/endpoints/sitemap/sitemap.controller.ts b/apps/api/src/app/endpoints/sitemap/sitemap.controller.ts index f10f0bfd8..fb581c72e 100644 --- a/apps/api/src/app/endpoints/sitemap/sitemap.controller.ts +++ b/apps/api/src/app/endpoints/sitemap/sitemap.controller.ts @@ -8,8 +8,8 @@ import { import { Controller, Get, Res, VERSION_NEUTRAL, Version } from '@nestjs/common'; import { format } from 'date-fns'; import { Response } from 'express'; -import { readFileSync } from 'fs'; -import { join } from 'path'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; import { SitemapService } from './sitemap.service'; diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts index 6208eb7d7..8850a6874 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts @@ -1,4 +1,4 @@ -import { readFileSync } from 'fs'; +import { readFileSync } from 'node:fs'; export const activityDummyData = { accountId: undefined, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts index ad64cb383..1f6f9dc2a 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts @@ -20,7 +20,7 @@ import { PerformanceCalculationType } from '@ghostfolio/common/types/performance import { Tag } from '@prisma/client'; import { Big } from 'big.js'; -import { join } from 'path'; +import { join } from 'node:path'; jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { return { diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-short.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-short.spec.ts index ce1cf3681..a2d7e60d3 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-short.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-short.spec.ts @@ -20,7 +20,7 @@ import { PerformanceCalculationType } from '@ghostfolio/common/types/performance import { Tag } from '@prisma/client'; import { Big } from 'big.js'; -import { join } from 'path'; +import { join } from 'node:path'; jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { return { diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts index d17fd028a..bdccb23e0 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts @@ -20,7 +20,7 @@ import { PerformanceCalculationType } from '@ghostfolio/common/types/performance import { Tag } from '@prisma/client'; import { Big } from 'big.js'; -import { join } from 'path'; +import { join } from 'node:path'; jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { return { diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts index 18455477e..4872a1004 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts @@ -20,7 +20,7 @@ import { PerformanceCalculationType } from '@ghostfolio/common/types/performance import { Tag } from '@prisma/client'; import { Big } from 'big.js'; -import { join } from 'path'; +import { join } from 'node:path'; jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { return { diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts index e20400cb7..e6c71230b 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts @@ -20,7 +20,7 @@ import { PerformanceCalculationType } from '@ghostfolio/common/types/performance import { Tag } from '@prisma/client'; import { Big } from 'big.js'; -import { join } from 'path'; +import { join } from 'node:path'; jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { return { diff --git a/apps/api/src/app/redis-cache/redis-cache.service.ts b/apps/api/src/app/redis-cache/redis-cache.service.ts index 621199cc9..1ea0a6137 100644 --- a/apps/api/src/app/redis-cache/redis-cache.service.ts +++ b/apps/api/src/app/redis-cache/redis-cache.service.ts @@ -4,9 +4,9 @@ import { AssetProfileIdentifier, Filter } from '@ghostfolio/common/interfaces'; import { CACHE_MANAGER, Cache } from '@nestjs/cache-manager'; import { Inject, Injectable, Logger } from '@nestjs/common'; -import { createHash } from 'crypto'; import Keyv from 'keyv'; import ms from 'ms'; +import { createHash } from 'node:crypto'; @Injectable() export class RedisCacheService { diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 10f8d3744..6512fbbc2 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -48,9 +48,9 @@ import { PerformanceCalculationType } from '@ghostfolio/common/types/performance import { Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { Prisma, Role, User } from '@prisma/client'; -import { createHmac } from 'crypto'; import { differenceInDays, subDays } from 'date-fns'; import { sortBy, without } from 'lodash'; +import { createHmac } from 'node:crypto'; @Injectable() export class UserService { diff --git a/apps/api/src/helper/string.helper.ts b/apps/api/src/helper/string.helper.ts index 38bac79f1..75f9d00fd 100644 --- a/apps/api/src/helper/string.helper.ts +++ b/apps/api/src/helper/string.helper.ts @@ -1,4 +1,4 @@ -import { randomBytes } from 'crypto'; +import { randomBytes } from 'node:crypto'; export function getRandomString(length: number) { const bytes = randomBytes(length); diff --git a/apps/api/src/middlewares/html-template.middleware.ts b/apps/api/src/middlewares/html-template.middleware.ts index 75ec37480..665b93354 100644 --- a/apps/api/src/middlewares/html-template.middleware.ts +++ b/apps/api/src/middlewares/html-template.middleware.ts @@ -10,8 +10,8 @@ import { DATE_FORMAT, interpolate } from '@ghostfolio/common/helper'; import { Injectable, Logger, NestMiddleware } from '@nestjs/common'; import { format } from 'date-fns'; import { NextFunction, Request, Response } from 'express'; -import * as fs from 'fs'; -import { join } from 'path'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; const title = 'Ghostfolio'; @@ -87,7 +87,7 @@ export class HtmlTemplateMiddleware implements NestMiddleware { this.indexHtmlMap = SUPPORTED_LANGUAGE_CODES.reduce( (map, languageCode) => ({ ...map, - [languageCode]: fs.readFileSync( + [languageCode]: readFileSync( join(__dirname, '..', 'client', languageCode, 'index.html'), 'utf8' ) diff --git a/apps/api/src/services/api-key/api-key.service.ts b/apps/api/src/services/api-key/api-key.service.ts index f70e5330c..b911191dc 100644 --- a/apps/api/src/services/api-key/api-key.service.ts +++ b/apps/api/src/services/api-key/api-key.service.ts @@ -3,7 +3,7 @@ import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { ApiKeyResponse } from '@ghostfolio/common/interfaces'; import { Injectable } from '@nestjs/common'; -import { pbkdf2Sync } from 'crypto'; +import { pbkdf2Sync } from 'node:crypto'; @Injectable() export class ApiKeyService { diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index eb6f85d73..40298de15 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -24,6 +24,7 @@ import { import { Injectable, Logger } from '@nestjs/common'; import { DataSource, SymbolProfile } from '@prisma/client'; import { addDays, format, isSameDay } from 'date-fns'; +import { uniqBy } from 'lodash'; import YahooFinance from 'yahoo-finance2'; import { ChartResultArray } from 'yahoo-finance2/esm/src/modules/chart'; import { @@ -290,7 +291,9 @@ export class YahooFinanceService implements DataProviderInterface { try { marketData = await this.yahooFinance.quote( - quotes.map(({ symbol }) => { + uniqBy(quotes, ({ symbol }) => { + return symbol; + }).map(({ symbol }) => { return symbol; }) ); @@ -300,35 +303,35 @@ export class YahooFinanceService implements DataProviderInterface { } } - for (const marketDataItem of marketData) { - const quote = quotes.find((currentQuote) => { - return currentQuote.symbol === marketDataItem.symbol; - }); - - const symbol = - this.yahooFinanceDataEnhancerService.convertFromYahooFinanceSymbol( - marketDataItem.symbol - ); - + for (const { + currency, + longName, + quoteType, + shortName, + symbol + } of marketData) { const { assetClass, assetSubClass } = this.yahooFinanceDataEnhancerService.parseAssetClass({ - quoteType: quote.quoteType, - shortName: quote.shortname + quoteType, + shortName }); items.push({ assetClass, assetSubClass, - symbol, - currency: marketDataItem.currency, + currency, dataProviderInfo: this.getDataProviderInfo(), dataSource: this.getName(), name: this.yahooFinanceDataEnhancerService.formatName({ - longName: quote.longname, - quoteType: quote.quoteType, - shortName: quote.shortname, - symbol: quote.symbol - }) + longName, + quoteType, + shortName, + symbol + }), + symbol: + this.yahooFinanceDataEnhancerService.convertFromYahooFinanceSymbol( + symbol + ) }); } } catch (error) { diff --git a/apps/api/src/services/i18n/i18n.service.ts b/apps/api/src/services/i18n/i18n.service.ts index a0389ab36..0f1f6239d 100644 --- a/apps/api/src/services/i18n/i18n.service.ts +++ b/apps/api/src/services/i18n/i18n.service.ts @@ -2,8 +2,8 @@ import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; import { Injectable, Logger } from '@nestjs/common'; import * as cheerio from 'cheerio'; -import { readFileSync, readdirSync } from 'fs'; -import { join } from 'path'; +import { readFileSync, readdirSync } from 'node:fs'; +import { join } from 'node:path'; @Injectable() export class I18nService { diff --git a/libs/ui/src/lib/entity-logo/entity-logo-image-source.service.ts b/libs/ui/src/lib/entity-logo/entity-logo-image-source.service.ts new file mode 100644 index 000000000..9cbea529b --- /dev/null +++ b/libs/ui/src/lib/entity-logo/entity-logo-image-source.service.ts @@ -0,0 +1,20 @@ +import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; + +import { Injectable } from '@angular/core'; + +@Injectable({ + // Required to allow mocking in Storybook + providedIn: 'root' +}) +export class EntityLogoImageSourceService { + public getLogoUrlByAssetProfileIdentifier({ + dataSource, + symbol + }: AssetProfileIdentifier) { + return `../api/v1/logo/${dataSource}/${symbol}`; + } + + public getLogoUrlByUrl(url: string) { + return `../api/v1/logo?url=${url}`; + } +} diff --git a/libs/ui/src/lib/entity-logo/entity-logo.component.stories.ts b/libs/ui/src/lib/entity-logo/entity-logo.component.stories.ts new file mode 100644 index 000000000..6c89718bd --- /dev/null +++ b/libs/ui/src/lib/entity-logo/entity-logo.component.stories.ts @@ -0,0 +1,44 @@ +import { CommonModule } from '@angular/common'; +import { importProvidersFrom } from '@angular/core'; +import { provideNoopAnimations } from '@angular/platform-browser/animations'; +import { applicationConfig, Meta, StoryObj } from '@storybook/angular'; + +import { EntityLogoImageSourceServiceMock } from '../mocks/entity-logo-image-source.service.mock'; +import { EntityLogoImageSourceService } from './entity-logo-image-source.service'; +import { GfEntityLogoComponent } from './entity-logo.component'; + +export default { + title: 'Entity Logo', + component: GfEntityLogoComponent, + decorators: [ + applicationConfig({ + providers: [ + provideNoopAnimations(), + importProvidersFrom(CommonModule), + { + provide: EntityLogoImageSourceService, + useValue: new EntityLogoImageSourceServiceMock() + } + ] + }) + ] +} as Meta; + +type Story = StoryObj; + +export const LogoByAssetProfileIdentifier: Story = { + args: { + dataSource: 'YAHOO', + size: 'large', + symbol: 'AAPL', + tooltip: 'Apple Inc.' + } +}; + +export const LogoByUrl: Story = { + args: { + size: 'large', + tooltip: 'Ghostfolio', + url: 'https://ghostfol.io' + } +}; diff --git a/libs/ui/src/lib/entity-logo/entity-logo.component.ts b/libs/ui/src/lib/entity-logo/entity-logo.component.ts index 7598fb4d5..212e232be 100644 --- a/libs/ui/src/lib/entity-logo/entity-logo.component.ts +++ b/libs/ui/src/lib/entity-logo/entity-logo.component.ts @@ -1,3 +1,5 @@ +import { EntityLogoImageSourceService } from '@ghostfolio/ui/entity-logo/entity-logo-image-source.service'; + import { CommonModule } from '@angular/common'; import { CUSTOM_ELEMENTS_SCHEMA, @@ -25,11 +27,18 @@ export class GfEntityLogoComponent implements OnChanges { public src: string; + public constructor( + private readonly imageSourceService: EntityLogoImageSourceService + ) {} + public ngOnChanges() { if (this.dataSource && this.symbol) { - this.src = `../api/v1/logo/${this.dataSource}/${this.symbol}`; + this.src = this.imageSourceService.getLogoUrlByAssetProfileIdentifier({ + dataSource: this.dataSource, + symbol: this.symbol + }); } else if (this.url) { - this.src = `../api/v1/logo?url=${this.url}`; + this.src = this.imageSourceService.getLogoUrlByUrl(this.url); } } } diff --git a/libs/ui/src/lib/mocks/entity-logo-image-source.service.mock.ts b/libs/ui/src/lib/mocks/entity-logo-image-source.service.mock.ts new file mode 100644 index 000000000..3f4dbbef7 --- /dev/null +++ b/libs/ui/src/lib/mocks/entity-logo-image-source.service.mock.ts @@ -0,0 +1,24 @@ +import { AssetProfileIdentifier } from '@ghostfolio/common/interfaces'; + +import { DataSource } from '@prisma/client'; + +export class EntityLogoImageSourceServiceMock { + public getLogoUrlByAssetProfileIdentifier({ + dataSource, + symbol + }: AssetProfileIdentifier) { + if (dataSource === DataSource.YAHOO && symbol === 'AAPL') { + return 'data:image/png;base64,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'; + } + + return ''; + } + + public getLogoUrlByUrl(url: string) { + if (url === 'https://ghostfol.io') { + return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAP1BMVEU2z8v////x/Pspzcn0/Px73drR8/KC3tz6/v6e5eOl5+WM4d7n+PhI08/i9/eu6edV1dJk2NVx2teV4+G87evvttLSAAABDElEQVRYhe2V3Y6EIAyFrQXlTwHd93/WpeBsdiKbtF7tJJwbCKFfDlKO0zQ0NPQJwqrn1ZO2zlk9PWPgusClRcsJmHb4pWUTItDDu4zMBJ5w0yog4HGvB0gCgOoBZrYFdL16AMsmmD5AcQ3ofj3AwbOAX38BIhMw02ZjtQ+tLnht66mCAGA2eka1G3eabUZwD/PLbeuHenKMBODVV0Dru/TTQLgKAc1BvQ/9yAEkOnlon66oehEBIHp7dbSyPoIc0NEADMDnAa4wAvVK+CADRGx/VpNSi+iF3jMTUH4rJQ0aISPmVk+JoJiZeJw1QnaqL2OmWKSFkxnrZWsbXK4TzO5tmS+8TYaGhv6xvgEEfAgHGc7HRgAAAABJRU5ErkJggg=='; + } + + return ''; + } +}