diff --git a/CHANGELOG.md b/CHANGELOG.md index 482fa74c6..61032da99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgraded `nx` from version `21.5.1` to `22.1.3` +#### Changed + +- Upgraded `envalid` from version `8.1.0` to `8.1.1` + +## 2.221.0 - 2025-12-01 + ### Changed - Refactored the API query parameters in various data provider services @@ -21,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Improved the country weightings in the _Financial Modeling Prep_ service +- Improved the search functionality by name in the _Financial Modeling Prep_ service +- Resolved an issue in the user endpoint where the list was returning empty in the admin control panel’s users section ## 2.220.0 - 2025-11-29 @@ -2256,7 +2264,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed an issue in the portfolio summary with the currency conversion of fees -- Fixed an issue in the the search for a holding +- Fixed an issue in the search for a holding - Removed the show condition of the experimental features setting in the user settings ## 2.95.0 - 2024-07-12 diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 0a6df7647..705085a48 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -532,12 +532,7 @@ export class AdminService { this.countUsersWithAnalytics(), this.getUsersWithAnalytics({ skip, - take, - where: { - NOT: { - analytics: null - } - } + take }) ]); @@ -855,6 +850,20 @@ export class AdminService { } } ]; + + const noAnalyticsCondition: Prisma.UserWhereInput['NOT'] = { + analytics: null + }; + + if (where) { + if (where.NOT) { + where.NOT = { ...where.NOT, ...noAnalyticsCondition }; + } else { + where.NOT = noAnalyticsCondition; + } + } else { + where = { NOT: noAnalyticsCondition }; + } } const usersWithAnalytics = await this.prismaService.user.findMany({ diff --git a/apps/api/src/app/subscription/subscription.service.ts b/apps/api/src/app/subscription/subscription.service.ts index 0458005c9..0fad8c8ac 100644 --- a/apps/api/src/app/subscription/subscription.service.ts +++ b/apps/api/src/app/subscription/subscription.service.ts @@ -179,6 +179,8 @@ export class SubscriptionService { offerKey = 'renewal-early-bird-2023'; } else if (isBefore(createdAt, parseDate('2024-01-01'))) { offerKey = 'renewal-early-bird-2024'; + } else if (isBefore(createdAt, parseDate('2025-12-01'))) { + offerKey = 'renewal-early-bird-2025'; } const offer = await this.getSubscriptionOffer({ diff --git a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts index ecbc38256..65bcd6c06 100644 --- a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts @@ -317,7 +317,7 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { return { assetClass, assetSubClass }; } - private parseSector(aString: string): string { + private parseSector(aString: string) { let sector = UNKNOWN_KEY; switch (aString) { diff --git a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts index 27f462c90..2b4193af5 100644 --- a/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts +++ b/apps/api/src/services/data-provider/financial-modeling-prep/financial-modeling-prep.service.ts @@ -41,6 +41,7 @@ import { isSameDay, parseISO } from 'date-fns'; +import { uniqBy } from 'lodash'; @Injectable() export class FinancialModelingPrepService implements DataProviderInterface { @@ -549,14 +550,27 @@ export class FinancialModelingPrepService implements DataProviderInterface { apikey: this.apiKey }); - const result = await fetch( - `${this.getUrl({ version: 'stable' })}/search-symbol?${queryParams.toString()}`, - { - signal: AbortSignal.timeout( - this.configurationService.get('REQUEST_TIMEOUT') - ) + const [nameResults, symbolResults] = await Promise.all([ + fetch( + `${this.getUrl({ version: 'stable' })}/search-name?${queryParams.toString()}`, + { + signal: AbortSignal.timeout(requestTimeout) + } + ).then((res) => res.json()), + fetch( + `${this.getUrl({ version: 'stable' })}/search-symbol?${queryParams.toString()}`, + { + signal: AbortSignal.timeout(requestTimeout) + } + ).then((res) => res.json()) + ]); + + const result = uniqBy( + [...nameResults, ...symbolResults], + ({ exchange, symbol }) => { + return `${exchange}-${symbol}`; } - ).then((res) => res.json()); + ); items = result .filter(({ exchange, symbol }) => { diff --git a/libs/common/src/lib/types/subscription-offer-key.type.ts b/libs/common/src/lib/types/subscription-offer-key.type.ts index f6d898a01..89322a400 100644 --- a/libs/common/src/lib/types/subscription-offer-key.type.ts +++ b/libs/common/src/lib/types/subscription-offer-key.type.ts @@ -2,4 +2,5 @@ export type SubscriptionOfferKey = | 'default' | 'renewal' | 'renewal-early-bird-2023' - | 'renewal-early-bird-2024'; + | 'renewal-early-bird-2024' + | 'renewal-early-bird-2025'; diff --git a/package-lock.json b/package-lock.json index 5e798c729..6cba89dd3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "2.220.0", + "version": "2.221.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "2.220.0", + "version": "2.221.0", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { @@ -62,7 +62,7 @@ "date-fns": "4.1.0", "dotenv": "17.2.3", "dotenv-expand": "12.0.3", - "envalid": "8.1.0", + "envalid": "8.1.1", "fuse.js": "7.1.0", "google-spreadsheet": "3.2.0", "helmet": "7.0.0", @@ -20054,9 +20054,9 @@ } }, "node_modules/envalid": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/envalid/-/envalid-8.1.0.tgz", - "integrity": "sha512-OT6+qVhKVyCidaGoXflb2iK1tC8pd0OV2Q+v9n33wNhUJ+lus+rJobUj4vJaQBPxPZ0vYrPGuxdrenyCAIJcow==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/envalid/-/envalid-8.1.1.tgz", + "integrity": "sha512-vOUfHxAFFvkBjbVQbBfgnCO9d3GcNfMMTtVfgqSU2rQGMFEVqWy9GBuoSfHnwGu7EqR0/GeukQcL3KjFBaga9w==", "license": "MIT", "dependencies": { "tslib": "2.8.1" diff --git a/package.json b/package.json index fd3cc4cd5..c52bbacfa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "2.220.0", + "version": "2.221.0", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio", @@ -106,7 +106,7 @@ "date-fns": "4.1.0", "dotenv": "17.2.3", "dotenv-expand": "12.0.3", - "envalid": "8.1.0", + "envalid": "8.1.1", "fuse.js": "7.1.0", "google-spreadsheet": "3.2.0", "helmet": "7.0.0",