mirror of https://github.com/ghostfolio/ghostfolio
23 changed files with 345 additions and 56 deletions
@ -0,0 +1,54 @@ |
|||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; |
|||
import { RequestWithUser } from '@ghostfolio/common/types'; |
|||
import { |
|||
Body, |
|||
Controller, |
|||
Get, |
|||
HttpException, |
|||
Inject, |
|||
Post, |
|||
Req, |
|||
Res, |
|||
UseGuards |
|||
} from '@nestjs/common'; |
|||
import { REQUEST } from '@nestjs/core'; |
|||
import { AuthGuard } from '@nestjs/passport'; |
|||
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; |
|||
|
|||
import { SubscriptionService } from './subscription.service'; |
|||
|
|||
@Controller('subscription') |
|||
export class SubscriptionController { |
|||
public constructor( |
|||
private readonly configurationService: ConfigurationService, |
|||
@Inject(REQUEST) private readonly request: RequestWithUser, |
|||
private readonly subscriptionService: SubscriptionService |
|||
) {} |
|||
|
|||
@Get('stripe/callback') |
|||
public async stripeCallback(@Req() req, @Res() res) { |
|||
await this.subscriptionService.createSubscription( |
|||
req.query.checkoutSessionId |
|||
); |
|||
|
|||
res.redirect(`${this.configurationService.get('ROOT_URL')}/account`); |
|||
} |
|||
|
|||
@Post('stripe/checkout-session/create') |
|||
@UseGuards(AuthGuard('jwt')) |
|||
public async createCheckoutSession(@Body() { priceId }: { priceId: string }) { |
|||
try { |
|||
return await this.subscriptionService.createCheckoutSession({ |
|||
priceId, |
|||
userId: this.request.user.id |
|||
}); |
|||
} catch (error) { |
|||
console.error(error); |
|||
|
|||
throw new HttpException( |
|||
getReasonPhrase(StatusCodes.BAD_REQUEST), |
|||
StatusCodes.BAD_REQUEST |
|||
); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,13 @@ |
|||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; |
|||
import { PrismaService } from '@ghostfolio/api/services/prisma.service'; |
|||
import { Module } from '@nestjs/common'; |
|||
|
|||
import { SubscriptionController } from './subscription.controller'; |
|||
import { SubscriptionService } from './subscription.service'; |
|||
|
|||
@Module({ |
|||
imports: [], |
|||
controllers: [SubscriptionController], |
|||
providers: [ConfigurationService, PrismaService, SubscriptionService] |
|||
}) |
|||
export class SubscriptionModule {} |
@ -0,0 +1,74 @@ |
|||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service'; |
|||
import { PrismaService } from '@ghostfolio/api/services/prisma.service'; |
|||
import { Injectable } from '@nestjs/common'; |
|||
import { addDays } from 'date-fns'; |
|||
import Stripe from 'stripe'; |
|||
|
|||
@Injectable() |
|||
export class SubscriptionService { |
|||
private stripe: Stripe; |
|||
|
|||
public constructor( |
|||
private readonly configurationService: ConfigurationService, |
|||
private prisma: PrismaService |
|||
) { |
|||
this.stripe = new Stripe( |
|||
this.configurationService.get('STRIPE_SECRET_KEY'), |
|||
{ |
|||
apiVersion: '2020-08-27' |
|||
} |
|||
); |
|||
} |
|||
|
|||
public async createCheckoutSession({ |
|||
priceId, |
|||
userId |
|||
}: { |
|||
priceId: string; |
|||
userId: string; |
|||
}) { |
|||
const session = await this.stripe.checkout.sessions.create({ |
|||
cancel_url: `${this.configurationService.get('ROOT_URL')}/account`, |
|||
client_reference_id: userId, |
|||
line_items: [ |
|||
{ |
|||
price: priceId, |
|||
quantity: 1 |
|||
} |
|||
], |
|||
metadata: { |
|||
user_id: userId |
|||
}, |
|||
mode: 'subscription', |
|||
payment_method_types: ['card'], |
|||
success_url: `${this.configurationService.get( |
|||
'ROOT_URL' |
|||
)}/api/subscription/stripe/callback?checkoutSessionId={CHECKOUT_SESSION_ID}` |
|||
}); |
|||
|
|||
return { |
|||
sessionId: session.id |
|||
}; |
|||
} |
|||
|
|||
public async createSubscription(aCheckoutSessionId: string) { |
|||
try { |
|||
const session = await this.stripe.checkout.sessions.retrieve( |
|||
aCheckoutSessionId |
|||
); |
|||
|
|||
await this.prisma.subscription.create({ |
|||
data: { |
|||
expiresAt: addDays(new Date(), 365), |
|||
User: { |
|||
connect: { |
|||
id: session.client_reference_id |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
} catch (error) { |
|||
console.error(error); |
|||
} |
|||
} |
|||
} |
@ -1,5 +1,6 @@ |
|||
export const environment = { |
|||
lastPublish: '{BUILD_TIMESTAMP}', |
|||
production: true, |
|||
stripePublicKey: '{STRIPE_PUBLIC_KEY}', |
|||
version: `v${require('../../../../package.json').version}` |
|||
}; |
|||
|
@ -0,0 +1,4 @@ |
|||
export interface Subscription { |
|||
price: number; |
|||
priceId: string; |
|||
} |
Loading…
Reference in new issue