Browse Source

Merge remote-tracking branch 'origin/main' into feature/extend-holdings-endpoint-for-cash

pull/5650/head
KenTandrian 1 week ago
parent
commit
20806b3e69
  1. 10
      CHANGELOG.md
  2. 1
      apps/api/src/app/info/info.service.ts
  3. 2
      apps/api/src/app/subscription/subscription.service.ts
  4. 22
      apps/api/src/helper/object.helper.spec.ts
  5. 11
      apps/api/src/helper/object.helper.ts
  6. 1
      apps/api/src/services/configuration/configuration.service.ts
  7. 11
      apps/api/src/services/data-provider/manual/manual.service.ts
  8. 1
      apps/api/src/services/interfaces/environment.interface.ts
  9. 4
      libs/ui/src/lib/fire-calculator/fire-calculator.component.stories.ts
  10. 8
      libs/ui/src/lib/fire-calculator/fire-calculator.component.ts
  11. 20
      package-lock.json
  12. 3
      package.json

10
CHANGELOG.md

@ -11,6 +11,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Extended the holdings endpoint to include the performance with currency effect for cash
### Changed
- Initialized the input properties in the _FIRE_ calculator
- Removed the deprecated public _Stripe_ key
- Upgraded `stripe` from version `18.5.0` to `20.1.0`
### Fixed
- Fixed the import of `jsonpath` to support REST APIs (`JSON`) via the scraper configuration
## 2.226.0 - 2026-01-01
### Added

1
apps/api/src/app/info/info.service.ts

@ -93,7 +93,6 @@ export class InfoService {
(await this.propertyService.getByKey<string[]>(
PROPERTY_COUNTRIES_OF_SUBSCRIBERS
)) ?? [];
info.stripePublicKey = this.configurationService.get('STRIPE_PUBLIC_KEY');
}
if (this.configurationService.get('ENABLE_FEATURE_SYSTEM_MESSAGE')) {

2
apps/api/src/app/subscription/subscription.service.ts

@ -35,7 +35,7 @@ export class SubscriptionService {
this.stripe = new Stripe(
this.configurationService.get('STRIPE_SECRET_KEY'),
{
apiVersion: '2025-08-27.basil'
apiVersion: '2025-12-15.clover'
}
);
}

22
apps/api/src/helper/object.helper.spec.ts

@ -1,4 +1,24 @@
import { redactAttributes } from './object.helper';
import { query, redactAttributes } from './object.helper';
describe('query', () => {
it('should get market price from stock API response', () => {
const object = {
currency: 'USD',
market: {
previousClose: 273.04,
price: 271.86
},
symbol: 'AAPL'
};
const result = query({
object,
pathExpression: '$.market.price'
})[0];
expect(result).toBe(271.86);
});
});
describe('redactAttributes', () => {
it('should redact provided attributes', () => {

11
apps/api/src/helper/object.helper.ts

@ -1,4 +1,5 @@
import { Big } from 'big.js';
import jsonpath from 'jsonpath';
import { cloneDeep, isArray, isObject } from 'lodash';
export function hasNotDefinedValuesInObject(aObject: Object): boolean {
@ -31,6 +32,16 @@ export function nullifyValuesInObjects<T>(aObjects: T[], keys: string[]): T[] {
});
}
export function query({
object,
pathExpression
}: {
object: object;
pathExpression: string;
}) {
return jsonpath.query(object, pathExpression);
}
export function redactAttributes({
isFirstRun = true,
object,

1
apps/api/src/services/configuration/configuration.service.ts

@ -102,7 +102,6 @@ export class ConfigurationService {
ROOT_URL: url({
default: environment.rootUrl
}),
STRIPE_PUBLIC_KEY: str({ default: '' }),
STRIPE_SECRET_KEY: str({ default: '' }),
TWITTER_ACCESS_TOKEN: str({ default: 'dummyAccessToken' }),
TWITTER_ACCESS_TOKEN_SECRET: str({ default: 'dummyAccessTokenSecret' }),

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

@ -1,3 +1,4 @@
import { query } from '@ghostfolio/api/helper/object.helper';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import {
DataProviderInterface,
@ -26,7 +27,6 @@ import { Injectable, Logger } from '@nestjs/common';
import { DataSource, SymbolProfile } from '@prisma/client';
import * as cheerio from 'cheerio';
import { addDays, format, isBefore } from 'date-fns';
import * as jsonpath from 'jsonpath';
@Injectable()
export class ManualService implements DataProviderInterface {
@ -286,9 +286,14 @@ export class ManualService implements DataProviderInterface {
let value: string;
if (response.headers.get('content-type')?.includes('application/json')) {
const data = await response.json();
const object = await response.json();
value = String(jsonpath.query(data, scraperConfiguration.selector)[0]);
value = String(
query({
object,
pathExpression: scraperConfiguration.selector
})[0]
);
} else {
const $ = cheerio.load(await response.text());

1
apps/api/src/services/interfaces/environment.interface.ts

@ -52,7 +52,6 @@ export interface Environment extends CleanedEnvAccessors {
REDIS_PORT: number;
REQUEST_TIMEOUT: number;
ROOT_URL: string;
STRIPE_PUBLIC_KEY: string;
STRIPE_SECRET_KEY: string;
TWITTER_ACCESS_TOKEN: string;
TWITTER_ACCESS_TOKEN_SECRET: string;

4
libs/ui/src/lib/fire-calculator/fire-calculator.component.stories.ts

@ -44,8 +44,10 @@ type Story = StoryObj<GfFireCalculatorComponent>;
export const Simple: Story = {
args: {
annualInterestRate: 5,
currency: 'USD',
fireWealth: 50000,
locale: locale
locale: locale,
savingsRate: 1000
}
};

8
libs/ui/src/lib/fire-calculator/fire-calculator.component.ts

@ -77,16 +77,16 @@ import { FireCalculatorService } from './fire-calculator.service';
templateUrl: './fire-calculator.component.html'
})
export class GfFireCalculatorComponent implements OnChanges, OnDestroy {
@Input() annualInterestRate: number;
@Input() annualInterestRate = 0;
@Input() colorScheme: ColorScheme;
@Input() currency: string;
@Input() deviceType: string;
@Input() fireWealth: number;
@Input() fireWealth = 0;
@Input() hasPermissionToUpdateUserSettings: boolean;
@Input() locale = getLocale();
@Input() projectedTotalAmount: number;
@Input() projectedTotalAmount = 0;
@Input() retirementDate: Date;
@Input() savingsRate: number;
@Input() savingsRate = 0;
@Output() annualInterestRateChanged = new EventEmitter<number>();
@Output() calculationCompleted =

20
package-lock.json

@ -84,7 +84,7 @@
"passport-openidconnect": "0.1.2",
"reflect-metadata": "0.2.2",
"rxjs": "7.8.1",
"stripe": "18.5.0",
"stripe": "20.1.0",
"svgmap": "2.14.0",
"tablemark": "4.1.0",
"twitter-api-v2": "1.27.0",
@ -124,6 +124,7 @@
"@types/big.js": "6.2.2",
"@types/google-spreadsheet": "3.1.5",
"@types/jest": "30.0.0",
"@types/jsonpath": "0.2.4",
"@types/lodash": "4.17.20",
"@types/node": "22.15.17",
"@types/papaparse": "5.3.7",
@ -12436,6 +12437,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/jsonpath": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@types/jsonpath/-/jsonpath-0.2.4.tgz",
"integrity": "sha512-K3hxB8Blw0qgW6ExKgMbXQv2UPZBoE2GqLpVY+yr7nMD2Pq86lsuIzyAaiQ7eMqFL5B6di6pxSkogLJEyEHoGA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/jsonwebtoken": {
"version": "9.0.10",
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
@ -31456,18 +31464,18 @@
}
},
"node_modules/stripe": {
"version": "18.5.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-18.5.0.tgz",
"integrity": "sha512-Hp+wFiEQtCB0LlNgcFh5uVyKznpDjzyUZ+CNVEf+I3fhlYvh7rZruIg+jOwzJRCpy0ZTPMjlzm7J2/M2N6d+DA==",
"version": "20.1.0",
"resolved": "https://registry.npmjs.org/stripe/-/stripe-20.1.0.tgz",
"integrity": "sha512-o1VNRuMkY76ZCq92U3EH3/XHm/WHp7AerpzDs4Zyo8uE5mFL4QUcv/2SudWsSnhBSp4moO2+ZoGCZ7mT8crPmQ==",
"license": "MIT",
"dependencies": {
"qs": "^6.11.0"
},
"engines": {
"node": ">=12.*"
"node": ">=16"
},
"peerDependencies": {
"@types/node": ">=12.x.x"
"@types/node": ">=16"
},
"peerDependenciesMeta": {
"@types/node": {

3
package.json

@ -128,7 +128,7 @@
"passport-openidconnect": "0.1.2",
"reflect-metadata": "0.2.2",
"rxjs": "7.8.1",
"stripe": "18.5.0",
"stripe": "20.1.0",
"svgmap": "2.14.0",
"tablemark": "4.1.0",
"twitter-api-v2": "1.27.0",
@ -168,6 +168,7 @@
"@types/big.js": "6.2.2",
"@types/google-spreadsheet": "3.1.5",
"@types/jest": "30.0.0",
"@types/jsonpath": "0.2.4",
"@types/lodash": "4.17.20",
"@types/node": "22.15.17",
"@types/papaparse": "5.3.7",

Loading…
Cancel
Save