Introduce database integration in the service
parent
a92855396b
commit
9b883068cd
|
|
@ -0,0 +1,17 @@
|
|||
FROM node:20
|
||||
|
||||
ENV PORT=3000
|
||||
ENV STAGE=prod
|
||||
|
||||
WORKDIR /var/prod
|
||||
COPY package.json .
|
||||
RUN npm install
|
||||
COPY . .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
EXPOSE ${PORT}
|
||||
|
||||
CMD ["npm", "run", "start:prod"]
|
||||
|
||||
|
||||
|
|
@ -12,7 +12,9 @@
|
|||
"@nestjs/common": "^11.0.1",
|
||||
"@nestjs/core": "^11.0.1",
|
||||
"@nestjs/platform-express": "^11.0.1",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"dotenv": "^17.2.3",
|
||||
"pg": "^8.16.3",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"stripe": "^20.0.0",
|
||||
|
|
@ -2513,6 +2515,19 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/typeorm": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-11.0.0.tgz",
|
||||
"integrity": "sha512-SOeUQl70Lb2OfhGkvnh4KXWlsd+zA08RuuQgT7kKbzivngxzSo1Oc7Usu5VxCxACQC9wc2l9esOHILSJeK7rJA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
||||
"@nestjs/core": "^10.0.0 || ^11.0.0",
|
||||
"reflect-metadata": "^0.1.13 || ^0.2.0",
|
||||
"rxjs": "^7.2.0",
|
||||
"typeorm": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/hashes": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
|
||||
|
|
@ -8236,6 +8251,95 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pg": {
|
||||
"version": "8.16.3",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
|
||||
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pg-connection-string": "^2.9.1",
|
||||
"pg-pool": "^3.10.1",
|
||||
"pg-protocol": "^1.10.3",
|
||||
"pg-types": "2.2.0",
|
||||
"pgpass": "1.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"pg-cloudflare": "^1.2.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pg-native": ">=3.0.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"pg-native": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pg-cloudflare": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz",
|
||||
"integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/pg-connection-string": {
|
||||
"version": "2.9.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz",
|
||||
"integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pg-int8": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
|
||||
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-pool": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz",
|
||||
"integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"pg": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-protocol": {
|
||||
"version": "1.10.3",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz",
|
||||
"integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pg-types": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
|
||||
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pg-int8": "1.0.1",
|
||||
"postgres-array": "~2.0.0",
|
||||
"postgres-bytea": "~1.0.0",
|
||||
"postgres-date": "~1.0.4",
|
||||
"postgres-interval": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/pgpass": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
|
||||
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"split2": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
|
|
@ -8354,6 +8458,45 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-array": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-bytea": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
|
||||
"integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-date": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
|
||||
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-interval": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
|
||||
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
|
|
@ -8999,6 +9142,15 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/split2": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
|
||||
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@
|
|||
"@nestjs/common": "^11.0.1",
|
||||
"@nestjs/core": "^11.0.1",
|
||||
"@nestjs/platform-express": "^11.0.1",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"dotenv": "^17.2.3",
|
||||
"pg": "^8.16.3",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"stripe": "^20.0.0",
|
||||
|
|
|
|||
|
|
@ -4,9 +4,25 @@ import { UserService } from './service/user.service';
|
|||
import { BuyController } from './controller/buy.controller';
|
||||
import { PurchaseService } from './service/purchase.service';
|
||||
import { StripeService } from './service/stripe.service';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { User } from './dto/user';
|
||||
import { Purchase } from './dto/purchase';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
imports: [
|
||||
TypeOrmModule.forRoot({
|
||||
// @ts-ignore
|
||||
type: process.env.DB_TYPE || 'postgres',
|
||||
host: process.env.DB_HOST || 'localhost',
|
||||
port: process.env.DB_PORT || 5432,
|
||||
username: process.env.DB_USER || 'postgres',
|
||||
password: process.env.DB_PASSWORD || 'postgres',
|
||||
database: process.env.DB_NAME || 'appdb',
|
||||
entities: [User, Purchase],
|
||||
synchronize: true,
|
||||
}),
|
||||
TypeOrmModule.forFeature([User, Purchase]),
|
||||
],
|
||||
controllers: [AccessController, BuyController],
|
||||
providers: [UserService, PurchaseService, StripeService],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@ export class AccessController {
|
|||
constructor(private readonly userService: UserService) {}
|
||||
|
||||
@Post('/login')
|
||||
public login(
|
||||
public async login(
|
||||
@Body('name') name: string,
|
||||
@Body('password') password: string,
|
||||
): { userId: number } {
|
||||
) {
|
||||
this.logger.debug('Received login request');
|
||||
const user = this.userService.getUserByName(name);
|
||||
const user = await this.userService.getUserByName(name);
|
||||
if (user.password !== password) {
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
|
|
@ -29,12 +29,12 @@ export class AccessController {
|
|||
}
|
||||
|
||||
@Post('/register')
|
||||
public new(
|
||||
public async new(
|
||||
@Body('name') name: string,
|
||||
@Body('password') password: string,
|
||||
): { userId: number } {
|
||||
) {
|
||||
this.logger.debug('Received register request');
|
||||
const user = this.userService.createUser(name, password);
|
||||
const user = await this.userService.createUser(name, password);
|
||||
return {
|
||||
userId: user.id,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Body, Controller, Get, Logger, Param, Post, Redirect } from '@nestjs/common';
|
||||
import { Body, Controller, Logger, Post } from '@nestjs/common';
|
||||
import { PurchaseService } from '../service/purchase.service';
|
||||
import { UserService } from '../service/user.service';
|
||||
import { PurchaseItem } from '../dto/purchase-item';
|
||||
|
|
@ -7,6 +7,10 @@ import { PurchaseStatus } from 'src/dto/purchase-status';
|
|||
|
||||
@Controller('/buy')
|
||||
export class BuyController {
|
||||
private static PURCHASE_STATUS_TO_REEVALUATE = [
|
||||
PurchaseStatus.CREATED,
|
||||
PurchaseStatus.IN_PROGRESS,
|
||||
];
|
||||
private readonly logger = new Logger(BuyController.name);
|
||||
|
||||
constructor(
|
||||
|
|
@ -17,32 +21,41 @@ export class BuyController {
|
|||
|
||||
@Post('/start')
|
||||
public async startPurchaseFlow(
|
||||
@Body('userId') userId: number,
|
||||
@Body('userId') userId: string,
|
||||
@Body('quantity') quantity: number,
|
||||
) {
|
||||
const user = this.userService.getUserById(userId);
|
||||
const purchase = this.purchaseService.recordPurchaseStart(
|
||||
const user = await this.userService.getUserById(userId);
|
||||
const purchase = await this.purchaseService.createPurchase(
|
||||
user,
|
||||
PurchaseItem.PAELLA,
|
||||
quantity,
|
||||
);
|
||||
const { sessionUrl } = await this.stripeService.createStripeSession(
|
||||
user,
|
||||
purchase,
|
||||
);
|
||||
const { sessionId, sessionUrl } =
|
||||
await this.stripeService.createStripeSession(purchase);
|
||||
purchase.stripeSessionId = sessionId;
|
||||
this.purchaseService.recordPurchase(purchase);
|
||||
this.logger.debug(`Redirecting to ${sessionUrl}`);
|
||||
return { url: sessionUrl };
|
||||
}
|
||||
|
||||
@Post('/complete')
|
||||
public async complete(@Body('userId') userId: number) {
|
||||
const user = this.userService.getUserById(userId);
|
||||
const { isPaid, purchaseId } =
|
||||
await this.stripeService.getStripeSessionForCustomer(user);
|
||||
this.purchaseService.transitionPurchaseStatus(
|
||||
purchaseId,
|
||||
isPaid ? PurchaseStatus.COMPLETED : PurchaseStatus.IN_PROGRESS,
|
||||
public async complete(@Body('userId') userId: string) {
|
||||
const user = await this.userService.getUserById(userId);
|
||||
const purchases = await this.purchaseService.getPurchasesForUser(user);
|
||||
purchases
|
||||
.filter((purchase) =>
|
||||
BuyController.PURCHASE_STATUS_TO_REEVALUATE.includes(purchase.status),
|
||||
)
|
||||
.forEach(async (purchase) => {
|
||||
const { isPaid } = await this.stripeService.getStripeSessionFromId(
|
||||
purchase.stripeSessionId!,
|
||||
);
|
||||
purchase.status = isPaid
|
||||
? PurchaseStatus.COMPLETED
|
||||
: PurchaseStatus.IN_PROGRESS;
|
||||
this.purchaseService.recordPurchase(purchase);
|
||||
});
|
||||
|
||||
return { url: '/signup' };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,25 @@
|
|||
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { PurchaseItem } from './purchase-item';
|
||||
import { PurchaseStatus } from './purchase-status';
|
||||
import { User } from './user';
|
||||
|
||||
@Entity('PURCHASE')
|
||||
export class Purchase {
|
||||
id: number;
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@ManyToOne(() => User, (user) => user.purchases)
|
||||
purchasedBy: User;
|
||||
|
||||
@Column()
|
||||
purchasedProduct: PurchaseItem;
|
||||
|
||||
@Column()
|
||||
purchasedUnits: number;
|
||||
|
||||
@Column()
|
||||
status: PurchaseStatus;
|
||||
|
||||
@Column({ nullable: true })
|
||||
stripeSessionId?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
export class StripeSession {
|
||||
sessionId: string;
|
||||
userId: number;
|
||||
purchaseId: number;
|
||||
}
|
||||
|
|
@ -1,5 +1,17 @@
|
|||
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { Purchase } from './purchase';
|
||||
|
||||
@Entity('USERS')
|
||||
export class User {
|
||||
id: number;
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
password: string;
|
||||
|
||||
@OneToMany(() => Purchase, (purchase) => purchase.purchasedBy)
|
||||
purchases: Purchase[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +1,39 @@
|
|||
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Purchase } from 'src/dto/purchase';
|
||||
import { PurchaseItem } from 'src/dto/purchase-item';
|
||||
import { PurchaseStatus } from 'src/dto/purchase-status';
|
||||
import { User } from 'src/dto/user';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class PurchaseService {
|
||||
private readonly purchases: Purchase[] = [];
|
||||
private readonly logger = new Logger(PurchaseService.name);
|
||||
|
||||
constructor() {}
|
||||
constructor(
|
||||
@InjectRepository(Purchase) private purchaseRepo: Repository<Purchase>,
|
||||
) {}
|
||||
|
||||
public recordPurchaseStart(
|
||||
public createPurchase(
|
||||
user: User,
|
||||
purchasedItem: PurchaseItem,
|
||||
units: number,
|
||||
): Purchase {
|
||||
) {
|
||||
this.logger.debug(`Recording purchase for user ID: ${user.id}`);
|
||||
const purchase: Purchase = {
|
||||
id: this.purchases.length,
|
||||
const purchase = this.purchaseRepo.create({
|
||||
purchasedBy: user,
|
||||
purchasedProduct: purchasedItem,
|
||||
purchasedUnits: units,
|
||||
status: PurchaseStatus.CREATED,
|
||||
};
|
||||
this.purchases.push(purchase);
|
||||
return purchase;
|
||||
});
|
||||
return this.purchaseRepo.save(purchase);
|
||||
}
|
||||
|
||||
public transitionPurchaseStatus(
|
||||
purchaseId: number,
|
||||
purchaseStatus: PurchaseStatus,
|
||||
) {
|
||||
const purchase = this.purchases.find(
|
||||
(purchase) => purchase.id === purchaseId,
|
||||
);
|
||||
if (!purchase) {
|
||||
throw new NotFoundException();
|
||||
public recordPurchase(purchase: Purchase) {
|
||||
this.purchaseRepo.save(purchase);
|
||||
}
|
||||
|
||||
purchase.status = purchaseStatus;
|
||||
}
|
||||
|
||||
public findPurchasesByUser(userId: number): Purchase[] {
|
||||
this.logger.debug(`Searching purchases for user ID: ${userId}`);
|
||||
return this.purchases.filter(
|
||||
(purchase) => (purchase.purchasedBy.id = userId),
|
||||
);
|
||||
public getPurchasesForUser(user: User) {
|
||||
return this.purchaseRepo.find({ where: { purchasedBy: user } });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,19 @@
|
|||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Purchase } from '../dto/purchase';
|
||||
import Stripe from 'stripe';
|
||||
import { User } from '../dto/user';
|
||||
import { StripeSession } from 'src/dto/stripe-session';
|
||||
|
||||
@Injectable()
|
||||
export class StripeService {
|
||||
private readonly stripe: Stripe;
|
||||
private readonly stripeSessions: StripeSession[] = [];
|
||||
|
||||
constructor() {
|
||||
const stripePrivateKey = process.env.STRIPE_PRIVATE_KEY!;
|
||||
console.log(stripePrivateKey);
|
||||
this.stripe = new Stripe(stripePrivateKey);
|
||||
}
|
||||
|
||||
public async createStripeSession(user: User, purchase: Purchase) {
|
||||
const redirectUrl = `http://localhost:5173/buy/return?purchaseId=${purchase.id}`
|
||||
public async createStripeSession(purchase: Purchase) {
|
||||
const redirectUrl = `http://localhost:8000/buy/return?purchaseId=${purchase.id}`;
|
||||
const session = await this.stripe.checkout.sessions.create({
|
||||
line_items: [
|
||||
{
|
||||
|
|
@ -28,32 +26,17 @@ export class StripeService {
|
|||
cancel_url: redirectUrl,
|
||||
payment_method_types: ['card', 'paypal'],
|
||||
});
|
||||
const stripeSession: StripeSession = {
|
||||
sessionId: session.id,
|
||||
userId: user.id,
|
||||
purchaseId: purchase.id,
|
||||
};
|
||||
|
||||
this.stripeSessions.push(stripeSession);
|
||||
return {
|
||||
sessionUrl: session.url,
|
||||
sessionId: session.id,
|
||||
sessionUrl: session.url!,
|
||||
};
|
||||
}
|
||||
|
||||
public async getStripeSessionForCustomer(user: User) {
|
||||
const stripeSession = this.stripeSessions.find(
|
||||
(session) => session.userId === user.id,
|
||||
);
|
||||
if (!stripeSession) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
const session = await this.stripe.checkout.sessions.retrieve(
|
||||
stripeSession.sessionId,
|
||||
);
|
||||
public async getStripeSessionFromId(sessionId: string) {
|
||||
const session = await this.stripe.checkout.sessions.retrieve(sessionId);
|
||||
return {
|
||||
isPaid: session.payment_status === 'paid',
|
||||
purchaseId: stripeSession.purchaseId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,46 +1,46 @@
|
|||
import { Injectable, Logger, NotFoundException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { User } from 'src/dto/user';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
private readonly users: User[] = [];
|
||||
private readonly logger = new Logger(UserService.name);
|
||||
|
||||
constructor() {}
|
||||
constructor(@InjectRepository(User) private userRepo: Repository<User>) {}
|
||||
|
||||
public getUserByName(name: string): User {
|
||||
public async getUserByName(name: string) {
|
||||
this.logger.debug(`Get user by name: ${name}`);
|
||||
const user = this.users.find((u) => u.name === name);
|
||||
const user = await this.userRepo.findOne({ where: { name: name } });
|
||||
if (!user) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public getUserById(userId: number): User {
|
||||
public async getUserById(userId: string) {
|
||||
this.logger.debug(`Get user by id: ${userId}`);
|
||||
const user = this.users.find((u) => u.id === userId);
|
||||
const user = await this.userRepo.findOne({ where: { id: userId } });
|
||||
if (!user) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public createUser(name: string, password: string): User {
|
||||
public async createUser(name: string, password: string) {
|
||||
try {
|
||||
this.getUserByName(name);
|
||||
await this.getUserByName(name);
|
||||
throw new NotFoundException();
|
||||
} catch (e) {
|
||||
if (!(e instanceof NotFoundException)) throw e;
|
||||
}
|
||||
|
||||
this.logger.debug(`Creating user with name: ${name}`);
|
||||
const user: User = {
|
||||
id: this.users.length,
|
||||
const user: User = this.userRepo.create({
|
||||
name,
|
||||
password,
|
||||
};
|
||||
this.users.push(user);
|
||||
return user;
|
||||
purchases: [],
|
||||
});
|
||||
return this.userRepo.save(user);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue