From 4aa0bd7be3c4a8105c027d1515ae04289b4be31c Mon Sep 17 00:00:00 2001 From: rollrat Date: Sat, 8 Apr 2023 22:42:30 +0900 Subject: [PATCH 1/3] #49 Feat-[declare components] --- src/store/dto/buyItem.request.dto.ts | 5 +++++ src/store/dto/buyItem.response.dto.ts | 0 src/store/store.controller.spec.ts | 18 ++++++++++++++++++ src/store/store.controller.ts | 23 +++++++++++++++++++++++ src/store/store.module.ts | 7 ++++++- src/store/store.service.spec.ts | 18 ++++++++++++++++++ src/store/store.service.ts | 4 ++++ 7 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/store/dto/buyItem.request.dto.ts create mode 100644 src/store/dto/buyItem.response.dto.ts create mode 100644 src/store/store.controller.spec.ts create mode 100644 src/store/store.controller.ts create mode 100644 src/store/store.service.spec.ts create mode 100644 src/store/store.service.ts diff --git a/src/store/dto/buyItem.request.dto.ts b/src/store/dto/buyItem.request.dto.ts new file mode 100644 index 0000000..59036b4 --- /dev/null +++ b/src/store/dto/buyItem.request.dto.ts @@ -0,0 +1,5 @@ + + +export class buyItemRequestDto { + +} \ No newline at end of file diff --git a/src/store/dto/buyItem.response.dto.ts b/src/store/dto/buyItem.response.dto.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/store/store.controller.spec.ts b/src/store/store.controller.spec.ts new file mode 100644 index 0000000..cb5a344 --- /dev/null +++ b/src/store/store.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { StoreController } from './store.controller'; + +describe('StoreController', () => { + let controller: StoreController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [StoreController], + }).compile(); + + controller = module.get(StoreController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/store/store.controller.ts b/src/store/store.controller.ts new file mode 100644 index 0000000..ac6db45 --- /dev/null +++ b/src/store/store.controller.ts @@ -0,0 +1,23 @@ +import { Body, Controller, Post, Req, UseGuards } from '@nestjs/common'; +import { ApiBody, ApiOperation, ApiResponse } from '@nestjs/swagger'; +import { JwtAuthGuard } from 'src/auth/jwt-auth.guard'; +import { buyItemRequestDto } from './dto/buyItem.request.dto'; +import { StoreService } from './store.service'; + +@Controller('store') +export class StoreController { + constructor(private storeService: StoreService) { } + + @UseGuards(JwtAuthGuard) + @Post('/') + @ApiOperation({ summary: '상점에서 아이템 구매' }) + @ApiBody({ type: buyItemRequestDto }) + @ApiResponse({ + status: 200, + description: '성공', + // type: scheduleResponseDto, + }) + async buyItem(@Req() req, @Body() data: buyItemRequestDto) { + // return this.storeService.buyItem(); + } +} diff --git a/src/store/store.module.ts b/src/store/store.module.ts index 11f13e7..d45f934 100644 --- a/src/store/store.module.ts +++ b/src/store/store.module.ts @@ -1,4 +1,9 @@ import { Module } from '@nestjs/common'; +import { StoreController } from './store.controller'; +import { StoreService } from './store.service'; -@Module({}) +@Module({ + controllers: [StoreController], + providers: [StoreService] +}) export class StoreModule {} diff --git a/src/store/store.service.spec.ts b/src/store/store.service.spec.ts new file mode 100644 index 0000000..1aeff7d --- /dev/null +++ b/src/store/store.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { StoreService } from './store.service'; + +describe('StoreService', () => { + let service: StoreService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [StoreService], + }).compile(); + + service = module.get(StoreService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/store/store.service.ts b/src/store/store.service.ts new file mode 100644 index 0000000..5fbc898 --- /dev/null +++ b/src/store/store.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class StoreService {} From 74933210088d33b8efb5cb4e420b994527446ab0 Mon Sep 17 00:00:00 2001 From: rollrat Date: Sun, 9 Apr 2023 17:26:25 +0900 Subject: [PATCH 2/3] =?UTF-8?q?#49=20Feat-[buyItem=20Api=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/store/dto/buyItem.request.dto.ts | 14 +++++-- src/store/dto/buyItem.response.dto.ts | 0 src/store/store.controller.ts | 17 +++++--- src/store/store.service.ts | 60 ++++++++++++++++++++++++++- 4 files changed, 81 insertions(+), 10 deletions(-) delete mode 100644 src/store/dto/buyItem.response.dto.ts diff --git a/src/store/dto/buyItem.request.dto.ts b/src/store/dto/buyItem.request.dto.ts index 59036b4..dcf9da4 100644 --- a/src/store/dto/buyItem.request.dto.ts +++ b/src/store/dto/buyItem.request.dto.ts @@ -1,5 +1,13 @@ - +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsNumber } from 'class-validator'; export class buyItemRequestDto { - -} \ No newline at end of file + @IsNumber() + @IsNotEmpty() + @ApiProperty({ + name: 'itemId', + description: '아이템 아이디', + example: 1, + }) + itemId: number; +} diff --git a/src/store/dto/buyItem.response.dto.ts b/src/store/dto/buyItem.response.dto.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/store/store.controller.ts b/src/store/store.controller.ts index ac6db45..f5e5f12 100644 --- a/src/store/store.controller.ts +++ b/src/store/store.controller.ts @@ -1,12 +1,20 @@ import { Body, Controller, Post, Req, UseGuards } from '@nestjs/common'; -import { ApiBody, ApiOperation, ApiResponse } from '@nestjs/swagger'; +import { + ApiBody, + ApiHeader, + ApiOperation, + ApiResponse, + ApiTags, +} from '@nestjs/swagger'; import { JwtAuthGuard } from 'src/auth/jwt-auth.guard'; import { buyItemRequestDto } from './dto/buyItem.request.dto'; import { StoreService } from './store.service'; -@Controller('store') +@ApiTags('store') +@ApiHeader({ name: 'access', description: 'access token' }) +@Controller('api/store') export class StoreController { - constructor(private storeService: StoreService) { } + constructor(private storeService: StoreService) {} @UseGuards(JwtAuthGuard) @Post('/') @@ -15,9 +23,8 @@ export class StoreController { @ApiResponse({ status: 200, description: '성공', - // type: scheduleResponseDto, }) async buyItem(@Req() req, @Body() data: buyItemRequestDto) { - // return this.storeService.buyItem(); + await this.storeService.buyItem(req.userId, data.itemId); } } diff --git a/src/store/store.service.ts b/src/store/store.service.ts index 5fbc898..acd3621 100644 --- a/src/store/store.service.ts +++ b/src/store/store.service.ts @@ -1,4 +1,60 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; +import { DataSource, Repository } from 'typeorm'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Inventory } from 'src/entities/inventory'; +import { Users } from 'src/entities/user'; +import { Item } from 'src/entities/item'; @Injectable() -export class StoreService {} +export class StoreService { + constructor( + private dataSource: DataSource, + @InjectRepository(Users) private usersRepository: Repository, + @InjectRepository(Inventory) + private inventoryRepository: Repository, + @InjectRepository(Item) + private itemRepository: Repository, + ) {} + + async buyItem(userId: number, itemId: number) { + // 1. get item price + const item = await this.itemRepository.findOne({ + where: { id: itemId }, + }); + + if (item) { + throw new BadRequestException('요청하신 아이템은 존재하지 않습니다!'); + } + + // 2. check user budget + const user = await this.usersRepository.findOne({ + where: { id: userId }, + }); + + if (user) { + throw new BadRequestException('잘못된 요청입니다!'); + } + + if (user.cash < item.price) { + throw new BadRequestException('아이템을 구매할 수 없습니다!'); + } + + // 3. run transaction + // 3-1. insert info to user table + // 3-2. reduce budget from user + await this.dataSource.manager + .transaction(async (manager) => { + const inventory = new Inventory(); + inventory.itemOwnerId = userId; + inventory.itemId = itemId; + inventory.isUsed = false; + + user.cash -= item.price; + await manager.save(user); + await manager.save(inventory); + }) + .catch((e) => { + throw e; + }); + } +} From 394f88229bab0882c66753a4127c9e05a00cc662 Mon Sep 17 00:00:00 2001 From: rollrat Date: Sun, 9 Apr 2023 17:41:45 +0900 Subject: [PATCH 3/3] =?UTF-8?q?#49=20Feat-[=EC=9D=B8=EB=B2=A4=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EB=B6=88=EB=9F=AC=EC=98=A4=EA=B8=B0=20api=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/getInventoryItems.response.dto.ts | 42 +++++++++++++++++++ src/inventory/inventory.controller.ts | 26 ++++++++++++ src/inventory/inventory.module.ts | 11 ++++- src/inventory/inventory.service.ts | 40 ++++++++++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/inventory/dto/getInventoryItems.response.dto.ts create mode 100644 src/inventory/inventory.controller.ts create mode 100644 src/inventory/inventory.service.ts diff --git a/src/inventory/dto/getInventoryItems.response.dto.ts b/src/inventory/dto/getInventoryItems.response.dto.ts new file mode 100644 index 0000000..4e01e3e --- /dev/null +++ b/src/inventory/dto/getInventoryItems.response.dto.ts @@ -0,0 +1,42 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class itemDto { + @ApiProperty({ + name: 'itemId', + description: '아이템 id', + example: 1, + }) + itemId: number; + + @ApiProperty({ + name: 'isUsed', + description: '아이템의 사용여부', + example: false, + }) + isUsed: boolean; + + @ApiProperty({ + name: 'name', + description: '아이템 이름', + example: '감자칩', + }) + name: string; + + @ApiProperty({ + name: 'price', + description: '아이템의 가격', + example: 1000, + }) + price: number; + + @ApiProperty({ + name: 'comment', + description: '아이템 설명', + example: '짭잘하고 바삭한 맛있는 감자칩이다', + }) + comment: string; +} + +export class getInventoryItemsResponseDto { + items: itemDto[]; +} diff --git a/src/inventory/inventory.controller.ts b/src/inventory/inventory.controller.ts new file mode 100644 index 0000000..f56c98b --- /dev/null +++ b/src/inventory/inventory.controller.ts @@ -0,0 +1,26 @@ +import { Controller, Get, Req, UseGuards } from '@nestjs/common'; +import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; +import { InventoryService } from './inventory.service'; +import { JwtAuthGuard } from 'src/auth/jwt-auth.guard'; +import { getInventoryItemsResponseDto } from './dto/getInventoryItems.response.dto'; + +@ApiTags('inventory') +@Controller('api/inventory') +export class InventoryController { + constructor(private inventorySercie: InventoryService) {} + + @UseGuards(JwtAuthGuard) + @Get('/') + @ApiOperation({ + summary: '인벤토리 아이템 가져오기', + description: '인벤토리에 있는 모든 사용자 아이템을 가져옵니다.', + }) + @ApiResponse({ + status: 200, + description: '성공', + type: getInventoryItemsResponseDto, + }) + async getInventoryItems(@Req() req) { + return await this.inventorySercie.getInventoryItems(req.userId); + } +} diff --git a/src/inventory/inventory.module.ts b/src/inventory/inventory.module.ts index 9608e4d..cbfb6d4 100644 --- a/src/inventory/inventory.module.ts +++ b/src/inventory/inventory.module.ts @@ -1,4 +1,13 @@ import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Users } from 'src/entities/user'; +import { InventoryService } from './inventory.service'; +import { InventoryController } from './inventory.controller'; +import { Inventory } from 'src/entities/inventory'; -@Module({}) +@Module({ + imports: [TypeOrmModule.forFeature([Users, Inventory])], + controllers: [InventoryController, InventoryService], + providers: [InventoryService], +}) export class InventoryModule {} diff --git a/src/inventory/inventory.service.ts b/src/inventory/inventory.service.ts new file mode 100644 index 0000000..d52c332 --- /dev/null +++ b/src/inventory/inventory.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Inventory } from 'src/entities/inventory'; + +import { DataSource, Repository } from 'typeorm'; +import { itemDto } from './dto/getInventoryItems.response.dto'; + +@Injectable() +export class InventoryService { + constructor( + private dataSource: DataSource, + @InjectRepository(Inventory) + private inventoryRepository: Repository, + ) {} + + async getInventoryItems(userId: number) { + const inventoryItems = await this.inventoryRepository.find({ + where: { itemOwnerId: userId }, + relations: ['ItemId'], + }); + + const result: itemDto[] = []; + + inventoryItems.forEach((e) => { + const item: itemDto = { + itemId: e.itemId, + isUsed: e.isUsed, + name: e.ItemId.name, + price: e.ItemId.price, + comment: e.ItemId.comment, + }; + + result.push(item); + }); + + return { + items: result, + }; + } +}