Skip to content

Commit

Permalink
[KAN-36] 패스워드 업데이트 API 개발 (#24)
Browse files Browse the repository at this point in the history
* [KAN-34] 유저 - 이메일인증 메일 전송 API 개발

* [KAN-34] 유저 - 이메일인증 메일 전송 API 개발 (패스워드 재설정 기능 추가)

* [KAN-34] 유저 - 이메일인증 메일 전송 API 개발 (패스워드 재설정 기능 추가)

* [KAN-34] 유저 - 이메일인증 메일 전송 API 개발 (네이밍 변경

* [KAN-34] 유저 - 이메일인증 메일 전송 API 개발 (네이밍 변경

* [KAN-34] 유저 - 이메일인증 메일 전송 API 개발 (네이밍 변경

* [KAN-34] 유저 - 이메일인증 메일 전송 API 개발 (네이밍 변경 (ktlint)

* [KAN-36] 유저 - 패스워드 업데이트 API 개발
  • Loading branch information
sinkyoungdeok authored May 8, 2024
1 parent 0abe319 commit aa1f543
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,11 @@ data class SkkuEmailException(
data class InvalidEmailCodeException(
override val message: String = "인증 코드가 일치 하지 않습니다."
) : ServerException(400, message)

data class InvalidUserResetPasswordStateException(
override val message: String = "유저가 비밀번호 초기화 상태가 아닙니다."
) : ServerException(400, message)

data class NotEqualTokenException(
override val message: String = "토큰이 일치 하지 않습니다."
) : ServerException(400, message)
7 changes: 6 additions & 1 deletion src/main/kotlin/com/restaurant/be/user/domain/entity/User.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.restaurant.be.user.domain.entity

import com.restaurant.be.common.converter.SeparatorConverter
import com.restaurant.be.common.password.PasswordService
import javax.persistence.Column
import javax.persistence.Convert
import javax.persistence.Entity
Expand Down Expand Up @@ -30,4 +31,8 @@ class User(

@Convert(converter = SeparatorConverter::class)
var roles: List<String> = listOf()
)
) {
fun updatePassword(password: String) {
this.password = password.run(PasswordService::hashPassword)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.restaurant.be.user.domain.service

import com.restaurant.be.common.exception.InvalidUserResetPasswordStateException
import com.restaurant.be.common.exception.NotEqualTokenException
import com.restaurant.be.common.exception.NotFoundUserEmailException
import com.restaurant.be.common.redis.RedisRepository
import com.restaurant.be.user.presentation.dto.UpdatePasswordRequest
import com.restaurant.be.user.presentation.dto.common.EmailSendType
import com.restaurant.be.user.repository.UserRepository
import org.springframework.stereotype.Service
import java.util.*
import javax.transaction.Transactional

@Service
class UpdateUserService(
private val redisRepository: RedisRepository,
private val userRepository: UserRepository
) {

@Transactional
fun updatePassword(request: UpdatePasswordRequest) {
val user = userRepository.findByEmail(request.email)
?: throw NotFoundUserEmailException()
val token = redisRepository
.getValue(
"user:${request.email}:${EmailSendType
.RESET_PASSWORD
.name
.lowercase(Locale.getDefault())}_token"
)
?: throw InvalidUserResetPasswordStateException()
if (token != request.token) throw NotEqualTokenException()

user.updatePassword(request.password)
userRepository.save(user)

redisRepository.delValue(
"user:${request.email}:${EmailSendType
.RESET_PASSWORD
.name
.lowercase(Locale.getDefault())}_token"
)
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package com.restaurant.be.user.domain.service

import com.restaurant.be.common.exception.InvalidEmailCodeException
import com.restaurant.be.common.exception.SendEmailException
import com.restaurant.be.common.exception.SkkuEmailException
import com.restaurant.be.common.redis.RedisRepository
import com.restaurant.be.user.presentation.dto.SendEmailRequest
import com.restaurant.be.user.presentation.dto.ValidateEmailRequest
import com.restaurant.be.user.presentation.dto.ValidateEmailResponse
import com.restaurant.be.user.presentation.dto.common.EmailSendType
import com.restaurant.be.user.repository.EmailRepository
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import java.util.*
import java.util.concurrent.TimeUnit

@Service
Expand Down Expand Up @@ -55,12 +51,7 @@ class ValidateEmailService(
}
}.build()

redisRepository.setValue(
"user:$email:${request.sendType.name.lowercase(Locale.getDefault())}_code",
code,
3,
TimeUnit.MINUTES
)
redisRepository.setValue("user:$email:signUpCode", code, 3, TimeUnit.MINUTES)
emailRepository.sendEmail(message)
} else {
val message = software.amazon.awssdk.services.ses.model.SendEmailRequest
Expand All @@ -80,37 +71,11 @@ class ValidateEmailService(
}
}.build()

redisRepository.setValue(
"user:$email:${request.sendType.name.lowercase(Locale.getDefault())}_code",
code,
3,
TimeUnit.MINUTES
)
redisRepository.setValue("user:$email:resetPasswordCode", code, 3, TimeUnit.MINUTES)
emailRepository.sendEmail(message)
}
} catch (e: Exception) {
throw SendEmailException()
}
}

fun validateEmail(request: ValidateEmailRequest): ValidateEmailResponse {
if (!isValidCode(request.email, request.code, request.sendType)) {
throw InvalidEmailCodeException()
}

val token = (UUID.randomUUID().toString() + UUID.randomUUID().toString()).replace("-", "")
redisRepository.setValue(
"user:${request.email}:${request.sendType.name.lowercase(Locale.getDefault())}_token",
token,
3,
TimeUnit.MINUTES
)

return ValidateEmailResponse(token)
}

private fun isValidCode(email: String, code: String, sendType: EmailSendType): Boolean {
val key = "user:$email:${sendType.name.lowercase(Locale.getDefault())}_code"
return redisRepository.getValue(key) == code
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.restaurant.be.user.presentation.controller

import com.restaurant.be.common.response.CommonResponse
import com.restaurant.be.user.domain.service.UpdateUserService
import com.restaurant.be.user.presentation.dto.UpdatePasswordRequest
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
Expand All @@ -13,8 +14,10 @@ import javax.validation.Valid

@Api(tags = ["01. User Info"], description = "유저 서비스")
@RestController
@RequestMapping("/api/v1/users/password")
class UpdatePasswordController {
@RequestMapping("/v1/users/password")
class UpdatePasswordController(
private val updateUserService: UpdateUserService
) {

@PatchMapping
@ApiOperation(value = "비밀번호 변경 API")
Expand All @@ -26,6 +29,7 @@ class UpdatePasswordController {
@Valid @RequestBody
request: UpdatePasswordRequest
): CommonResponse<Unit> {
updateUserService.updatePassword(request)
return CommonResponse.success()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
package com.restaurant.be.user.presentation.dto

import io.swagger.annotations.ApiModelProperty
import javax.validation.constraints.Email
import javax.validation.constraints.NotEmpty
import javax.validation.constraints.Pattern

data class UpdatePasswordRequest(
@field:NotEmpty(message = "이메일은 필수 값 입니다.")
@field:Email(message = "유효하지 않는 이메일 입니다.")
@ApiModelProperty(value = "이메일", example = "[email protected]", required = true)
val email: String,
@field:NotEmpty(message = "비밀번호는 필수 값 입니다.")
@field:Pattern(
regexp = "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[\\W_])[A-Za-z\\d\\W_]{8,16}\$",
Expand Down

0 comments on commit aa1f543

Please sign in to comment.