diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bb5324a0..b138ff035 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Migrated the asset profile dialogs of the market data management in the admin control panel to dedicated routes -## 3.67.0 - 2026-09-05 +## 3.67.1 - 2026-09-05 ### Added diff --git a/apps/api/src/app/subscription/subscription.controller.ts b/apps/api/src/app/subscription/subscription.controller.ts index 0cfc4d90e..778e32243 100644 --- a/apps/api/src/app/subscription/subscription.controller.ts +++ b/apps/api/src/app/subscription/subscription.controller.ts @@ -1,4 +1,5 @@ import { AllowDuringImpersonation } from '@ghostfolio/api/decorators/allow-during-impersonation.decorator'; +import { CustomThrottlerGuard } from '@ghostfolio/api/guards/custom-throttler.guard'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; @@ -46,7 +47,7 @@ export class SubscriptionController { @Post('redeem-coupon') @HttpCode(StatusCodes.OK) - @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseGuards(AuthGuard('jwt'), CustomThrottlerGuard, HasPermissionGuard) public async redeemCoupon(@Body() { couponCode }: { couponCode: string }) { if (!this.request.user) { throw new HttpException( @@ -119,7 +120,7 @@ export class SubscriptionController { } @Post('stripe/checkout-session') - @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseGuards(AuthGuard('jwt'), CustomThrottlerGuard, HasPermissionGuard) public async createStripeCheckoutSession( @Body() { couponId, priceId }: { couponId?: string; priceId: string } ): Promise { diff --git a/apps/api/src/app/subscription/subscription.service.ts b/apps/api/src/app/subscription/subscription.service.ts index aaa4deb5a..312b8c3ae 100644 --- a/apps/api/src/app/subscription/subscription.service.ts +++ b/apps/api/src/app/subscription/subscription.service.ts @@ -17,7 +17,7 @@ import { UserWithSettings } from '@ghostfolio/common/types'; -import { Injectable, Logger } from '@nestjs/common'; +import { BadRequestException, Injectable, Logger } from '@nestjs/common'; import { Prisma, Subscription } from '@prisma/client'; import { addMilliseconds, isBefore } from 'date-fns'; import ms, { StringValue } from 'ms'; @@ -64,6 +64,14 @@ export class SubscriptionService { } ); + if (!subscriptionOffer) { + throw new BadRequestException('Invalid priceId'); + } + + if (couponId && couponId !== subscriptionOffer.couponId) { + throw new BadRequestException('Invalid couponId'); + } + const stripeCheckoutSessionCreateParams: Stripe.Checkout.SessionCreateParams = { cancel_url: `${this.configurationService.get('ROOT_URL')}/${ @@ -77,9 +85,7 @@ export class SubscriptionService { } ], locale: this.getStripeLocale(user.settings?.settings?.language), - metadata: subscriptionOffer - ? { subscriptionOffer: JSON.stringify(subscriptionOffer) } - : {}, + metadata: { subscriptionOffer: JSON.stringify(subscriptionOffer) }, mode: 'payment', payment_method_types: ['card'], success_url: `${this.configurationService.get( diff --git a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts index cbe5b4363..31bfb620e 100644 --- a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts +++ b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts @@ -70,6 +70,8 @@ export class TransformDataSourceInResponseInterceptor< } } + data.dataProviderInfo = undefined; + if (Object.keys(valueMap).length === 0) { return data; } diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html index 5b0f1682b..2b378a4d6 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -358,7 +358,7 @@ - @if (dataProviderInfo) { + @if (dataProviderInfo?.name) {

- Market data provided by  + Market data provided by{{ ' ' }} @for ( dataProviderInfo of dataProviderInfos; track dataProviderInfo; @@ -7,10 +7,7 @@ ) { {{ dataProviderInfo.name - }} - @if (!last) { - ,  - } + }}{{ last ? '.' : ', ' }} } - . diff --git a/package-lock.json b/package-lock.json index 39a02c7ad..2b7b58fd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "3.67.0", + "version": "3.67.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "3.67.0", + "version": "3.67.1", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index c0439aefb..9ee6a75be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "3.67.0", + "version": "3.67.1", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio",