-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[송지민] 과제 제출 #5
base: main
Are you sure you want to change the base?
[송지민] 과제 제출 #5
Changes from all commits
6ca7f84
97a2538
6be22d6
72c134f
a6c20c6
a4630eb
4ae2ed8
5e92270
87bd324
946f1c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { IsNotEmpty, IsString } from 'class-validator'; | ||
import { Expose } from 'class-transformer'; | ||
import { ApiProperty } from '@nestjs/swagger'; | ||
|
||
export class AuthCodeDto { | ||
@IsString() | ||
@IsNotEmpty() | ||
@ApiProperty({ description: 'phoneNumber' }) | ||
readonly phoneNumber: string; | ||
@IsNotEmpty() | ||
@ApiProperty({ description: 'code' }) | ||
readonly code: string; | ||
} | ||
|
||
export class ResponseAuthCodeDto { | ||
@Expose() | ||
@ApiProperty({ description: 'result' }) | ||
readonly result: boolean; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { IsNotEmpty, IsString, MinLength } from 'class-validator'; | ||
import { Expose } from 'class-transformer'; | ||
import { ApiProperty } from '@nestjs/swagger'; | ||
|
||
export class CreateUserDto { | ||
@IsString() | ||
@IsNotEmpty() | ||
@ApiProperty({ description: 'phoneNumber' }) | ||
readonly phoneNumber: string; | ||
} | ||
|
||
export class ResponseUserDto { | ||
@Expose() | ||
@MinLength(6) | ||
@ApiProperty({ description: 'code' }) | ||
code: string; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { | ||
Column, | ||
CreateDateColumn, | ||
DeleteDateColumn, | ||
Entity, | ||
ManyToOne, | ||
PrimaryGeneratedColumn, | ||
} from 'typeorm'; | ||
import { User } from './user.entity'; | ||
import { ApiProperty } from '@nestjs/swagger'; | ||
|
||
@Entity({ name: 'AUTHCODE' }) | ||
export class AuthCode { | ||
@PrimaryGeneratedColumn({ name: 'id' }) | ||
@ApiProperty({ description: 'id' }) | ||
id: number; | ||
@Column() | ||
@ApiProperty({ description: 'code' }) | ||
code: string; | ||
@ManyToOne(() => User, (user) => user.authCodes) | ||
user: User; | ||
@CreateDateColumn({ | ||
type: 'timestamp', | ||
}) | ||
createdAt: Date; | ||
@DeleteDateColumn({ type: 'timestamp' }) | ||
deletedAt?: Date | null; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { | ||
CreateDateColumn, | ||
DeleteDateColumn, | ||
Entity, | ||
OneToMany, | ||
PrimaryColumn, | ||
} from 'typeorm'; | ||
import { AuthCode } from './auth-code.entity'; | ||
import { ApiProperty } from '@nestjs/swagger'; | ||
|
||
@Entity({ name: 'USERS' }) | ||
export class User { | ||
@PrimaryColumn() | ||
@ApiProperty({ description: 'phoneNumber' }) | ||
phoneNumber: string; | ||
@OneToMany(() => AuthCode, (authCode) => authCode.user) | ||
@ApiProperty({ description: 'authCodes' }) | ||
authCodes: AuthCode[]; | ||
@CreateDateColumn({ | ||
type: 'timestamp', | ||
}) | ||
createdAt: Date; | ||
@DeleteDateColumn({ type: 'timestamp' }) | ||
deletedAt?: Date | null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 보통 entity에 optional을 붙이기도 하나요? 하지만 deletedAt Column은 User Entity에 필수로 보여서요! |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { Controller, Post, Body } from '@nestjs/common'; | ||
import { UsersService } from './users.service'; | ||
import { CreateUserDto, ResponseUserDto } from './dto/users.dto'; | ||
import { AuthCodeDto, ResponseAuthCodeDto } from './dto/auth-codes.dto'; | ||
import { ApiCreatedResponse, ApiOperation, ApiTags } from '@nestjs/swagger'; | ||
|
||
@Controller('api/v1/users') | ||
@ApiTags('유저 API') | ||
export class UsersController { | ||
constructor(private readonly usersService: UsersService) {} | ||
|
||
@Post() | ||
@ApiOperation({ summary: '전화번호 등록 API ' }) | ||
@ApiCreatedResponse({ | ||
description: '전회번호를 등록한다.', | ||
type: ResponseUserDto, | ||
}) | ||
create(@Body() createUserDto: CreateUserDto) { | ||
return this.usersService.create(createUserDto); | ||
} | ||
|
||
@Post('auth') | ||
@ApiOperation({ summary: '인증 API ' }) | ||
@ApiCreatedResponse({ | ||
description: '전회번호로 발송된 인증번호를 통해 인증을 진행한다.', | ||
type: ResponseAuthCodeDto, | ||
}) | ||
auth(@Body() authCodeDto: AuthCodeDto) { | ||
return this.usersService.auth(authCodeDto); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { UsersService } from './users.service'; | ||
import { UsersController } from './users.controller'; | ||
import { TypeOrmModule } from '@nestjs/typeorm'; | ||
import { User } from './entities/user.entity'; | ||
import { AuthCode } from './entities/auth-code.entity'; | ||
|
||
@Module({ | ||
imports: [TypeOrmModule.forFeature([User, AuthCode])], | ||
controllers: [UsersController], | ||
providers: [UsersService], | ||
}) | ||
export class UsersModule {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { | ||
BadRequestException, | ||
Injectable, | ||
NotFoundException, | ||
} from '@nestjs/common'; | ||
import { CreateUserDto, ResponseUserDto } from './dto/users.dto'; | ||
import { InjectRepository } from '@nestjs/typeorm'; | ||
import { Between, Repository } from 'typeorm'; | ||
import { User } from './entities/user.entity'; | ||
import { AuthCode } from './entities/auth-code.entity'; | ||
import { plainToInstance } from 'class-transformer'; | ||
import { AuthCodeDto, ResponseAuthCodeDto } from './dto/auth-codes.dto'; | ||
|
||
@Injectable() | ||
export class UsersService { | ||
constructor( | ||
@InjectRepository(User) | ||
private userRepository: Repository<User>, | ||
@InjectRepository(AuthCode) | ||
private authCodeRepository: Repository<AuthCode>, | ||
) {} | ||
|
||
async create(create: CreateUserDto) { | ||
const phoneNumber = create.phoneNumber; | ||
const user = this.userRepository.create({ | ||
phoneNumber: phoneNumber, | ||
}); | ||
await this.userRepository.save(user); | ||
|
||
console.log(user); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저도 자주 까먹는데 디버깅용 |
||
const authCode = await this.authCodeRepository.findOne({ | ||
where: { user: user }, | ||
}); | ||
|
||
if (authCode) this.authCodeRepository.softDelete(authCode.id); | ||
const newAuthCode = this.authCodeRepository.create({ | ||
user: user, | ||
code: String(Math.floor(Math.random() * 1000000)).padStart(6, '0'), | ||
}); | ||
await this.authCodeRepository.save(newAuthCode); | ||
|
||
return plainToInstance(ResponseUserDto, newAuthCode, { | ||
excludeExtraneousValues: true, | ||
}); | ||
} | ||
|
||
async auth(auth: AuthCodeDto) { | ||
const phoneNumber = auth.phoneNumber; | ||
const code = auth.code; | ||
|
||
const currentDate = new Date(); | ||
const fiveMinuteAgo = new Date(); | ||
fiveMinuteAgo.setMinutes(currentDate.getMinutes() - 5); | ||
const userData = await this.userRepository.findOne({ | ||
where: { phoneNumber: phoneNumber }, | ||
}); | ||
const user = this.userRepository.create({ | ||
phoneNumber: userData.phoneNumber, | ||
}); | ||
|
||
if (!user) | ||
throw new NotFoundException('등록되어 있지 않은 전화번호 입니다.'); | ||
const test = await this.authCodeRepository.find({ where: { user: user } }); | ||
console.log(test); | ||
const authCode = await this.authCodeRepository.findOne({ | ||
where: { user: user, createdAt: Between(fiveMinuteAgo, currentDate) }, | ||
}); | ||
if (!authCode) { | ||
throw new NotFoundException( | ||
'인증번호가 없습니다. 인증 요청 후 다시 시도해주세요.', | ||
); | ||
} | ||
if (code != authCode.code) { | ||
throw new BadRequestException( | ||
'잘못된 인증번호 입니다. 정확한 인증번호로 다시 요청해주세요.', | ||
); | ||
} | ||
|
||
await this.authCodeRepository.softDelete(authCode.id); | ||
return plainToInstance(ResponseAuthCodeDto, { result: true }); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expose() 데코레이터는 무엇인가요?!