Skip to content

Commit

Permalink
MARA-88 : 환경별 리다이렉트 uri 구분을 위한 status 값 추가, 나눔 변수 추가 및 수정, 전역 예외 처리 및…
Browse files Browse the repository at this point in the history
… 커스텀 예외 클래스 추가 (#49)

* feat: redirect Uri 변경을 위한 status 값 추가

* refactor: status enum 추가 , customException 추가, 나눔 변수 수정,추가

* refactor: ex message 변경

* refactor: error response 이름 변경, ex message 변경, status enum 공통화

* refactor: formatting

* refactor: add exception data

* refactor: add exception data

* 예외 처리 코드 리팩토링

* exception 폴더 구조 변경 및 custom exception 추가

* S3 Custom Exception 추가

* Http 403 status Handling 예제 추가

* refactor: exception 처리 공통 클래스로 처리

---------

Co-authored-by: blackswitch <[email protected]>
Co-authored-by: gwon188 <[email protected]>
  • Loading branch information
3 people authored Feb 29, 2024
1 parent aadf7d5 commit f2ea2b8
Show file tree
Hide file tree
Showing 16 changed files with 170 additions and 51 deletions.
6 changes: 6 additions & 0 deletions src/main/kotlin/mara/server/auth/ClientConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,9 @@ class ClientConfig {
return RestTemplate()
}
}

enum class DeployStatus(val uri: String) {
LOCAL(""),
DEV("http://localhost:3000/login"),
PROD("https://fridgelink.site/login")
}
26 changes: 16 additions & 10 deletions src/main/kotlin/mara/server/auth/google/GoogleApiClient.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package mara.server.auth.google

import mara.server.util.logger
import mara.server.auth.DeployStatus
import mara.server.exception.InvalidDeployStatusException
import mara.server.exception.InvalidDeployStatusException.Companion.INVALID_DEPLOY_STATUS
import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
Expand All @@ -10,6 +12,7 @@ import org.springframework.stereotype.Component
import org.springframework.util.LinkedMultiValueMap
import org.springframework.util.MultiValueMap
import org.springframework.web.client.RestTemplate
import java.util.Locale

@Component
class GoogleApiClient(
Expand All @@ -28,16 +31,19 @@ class GoogleApiClient(

) {

val log = logger()

fun getRedirectUri(): String {
val os = System.getProperty("os.name")
log.info("OS : {}", os)
if (os.contains("Mac") || os.contains("Windows")) return "http://localhost:8080/users/google-login"
return "http://localhost:3000/login"
fun getRedirectUri(status: String): String {
val deployStatus = try {
DeployStatus.valueOf(status.uppercase(Locale.getDefault()))
} catch (e: IllegalArgumentException) {
throw InvalidDeployStatusException("$INVALID_DEPLOY_STATUS Status: $status")
}
return when (deployStatus) {
DeployStatus.LOCAL -> "http://localhost:8080/users/google-login"
else -> deployStatus.uri
}
}

fun requestAccessToken(authorizedCode: String): String {
fun requestAccessToken(authorizedCode: String, status: String): String {
val url = "$authUrl/token"
val httpHeaders = HttpHeaders()
httpHeaders.contentType = MediaType.APPLICATION_FORM_URLENCODED
Expand All @@ -46,7 +52,7 @@ class GoogleApiClient(
body.add("grant_type", "authorization_code")
body.add("client_id", clientId)
body.add("client_secret", secret)
body.add("redirect_uri", getRedirectUri())
body.add("redirect_uri", getRedirectUri(status))

val request = HttpEntity(body, httpHeaders)

Expand Down
27 changes: 17 additions & 10 deletions src/main/kotlin/mara/server/auth/kakao/KakaoApiClient.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package mara.server.auth.kakao

import mara.server.util.logger
import mara.server.auth.DeployStatus
import mara.server.exception.InvalidDeployStatusException
import mara.server.exception.InvalidDeployStatusException.Companion.INVALID_DEPLOY_STATUS
import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
Expand All @@ -9,6 +11,7 @@ import org.springframework.stereotype.Component
import org.springframework.util.LinkedMultiValueMap
import org.springframework.util.MultiValueMap
import org.springframework.web.client.RestTemplate
import java.util.Locale

@Component
class KakaoApiClient(
Expand All @@ -29,16 +32,20 @@ class KakaoApiClient(
private val appAdminKey: String,
) {

val log = logger()

fun getRedirectUri(): String {
val os = System.getProperty("os.name")
log.info("OS : {}", os)
if (os.contains("Mac") || os.contains("Windows")) return "http://localhost:8080/users/kakao-login"
return "http://localhost:3000/login"
fun getRedirectUri(status: String): String {
val deployStatus = try {
DeployStatus.valueOf(status.uppercase(Locale.getDefault()))
} catch (e: IllegalArgumentException) {
throw InvalidDeployStatusException("$INVALID_DEPLOY_STATUS Status: $status")
}

return when (deployStatus) {
DeployStatus.LOCAL -> "http://localhost:8080/users/kakao-login"
else -> deployStatus.uri
}
}

fun requestAccessToken(authorizedCode: String): String {
fun requestAccessToken(authorizedCode: String, status: String): String {
val url = "$authUrl/oauth/token"

val httpHeaders = HttpHeaders()
Expand All @@ -48,7 +55,7 @@ class KakaoApiClient(
body.add("grant_type", "authorization_code")
body.add("client_id", clientId)
body.add("client_secret", secret)
body.add("redirect_uri", getRedirectUri())
body.add("redirect_uri", getRedirectUri(status))

val request = HttpEntity(body, httpHeaders)

Expand Down
11 changes: 11 additions & 0 deletions src/main/kotlin/mara/server/common/CommonResponse.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
package mara.server.common

import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity

data class CommonResponse<T>(
var message: String = "ok",
var data: T? = null,
)

data class ErrorResponse(
var message: String
)

fun <T> success(data: T? = null): CommonResponse<T> = CommonResponse(data = data)

fun fail(httpStatus: HttpStatus, message: String): ResponseEntity<ErrorResponse> = ResponseEntity
.status(httpStatus)
.body(ErrorResponse(message = message))
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mara.server.domain.ingredient

import mara.server.domain.refrigerator.RefrigeratorRepository
import mara.server.domain.refrigerator.RefrigeratorService
import mara.server.exception.RefrigeratorException.Companion.NO_SUCH_REFRIGERATOR
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
Expand All @@ -22,7 +23,7 @@ class IngredientDetailService(
fun createIngredientDetail(ingredientDetailRequest: IngredientDetailRequest): Long {
val refrigeratorId = ingredientDetailRequest.refrigeratorId
val refrigerator = refrigeratorRepository.findById(refrigeratorId)
.orElseThrow { NoSuchElementException("해당 냉장고가 존재하지 않습니다. ID: $refrigeratorId") }
.orElseThrow { NoSuchElementException(NO_SUCH_REFRIGERATOR) }

val ingredientId = ingredientDetailRequest.ingredientId
val ingredient = ingredientRepository.findById(ingredientId)
Expand Down Expand Up @@ -55,7 +56,7 @@ class IngredientDetailService(

fun getIngredientDetailList(refrigeratorId: Long, location: IngredientLocation, pageable: Pageable): Page<IngredientDetailResponse> {
val refrigerator = refrigeratorRepository.findById(refrigeratorId)
.orElseThrow { NoSuchElementException("해당 냉장고가 존재하지 않습니다. ID: $refrigeratorId") }
.orElseThrow { NoSuchElementException(NO_SUCH_REFRIGERATOR) }
val ingredientDetailList =
ingredientDetailRepository.findByRefrigerator(refrigerator, location, pageable)
return ingredientDetailList.toIngredientDetailResponseListPage()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package mara.server.domain.refrigerator

import mara.server.domain.user.UserRepository
import mara.server.domain.user.UserService
import mara.server.exception.RefrigeratorException.Companion.NO_SUCH_REFRIGERATOR
import mara.server.exception.UserException.Companion.NO_SUCH_USER
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

Expand All @@ -13,7 +15,8 @@ class RefrigeratorService(
) {
private val deleted = "deleted"

fun getCurrentLoginUserRefrigeratorList(): List<Refrigerator> = refrigeratorRepository.findByUser(userService.getCurrentLoginUser())
fun getCurrentLoginUserRefrigeratorList(): List<Refrigerator> =
refrigeratorRepository.findByUser(userService.getCurrentLoginUser())

@Transactional
fun createRefrigerator(refrigeratorRequest: RefrigeratorRequest): Long {
Expand All @@ -29,12 +32,12 @@ class RefrigeratorService(
// TODO : FE API 연동 테스트 이후 삭제 예정
// fun getRefrigerator(id: Long): RefrigeratorResponse {
// val refrigerator =
// refrigeratorRepository.findById(id).orElseThrow { NoSuchElementException("해당 냉장고가 존재하지 않습니다. ID: $id") }
// refrigeratorRepository.findById(id).orElseThrow { NO_SUCH_REFRIGERATOR }
// return RefrigeratorResponse(refrigerator)
// }

fun getRefrigeratorList(userId: Long): List<RefrigeratorResponse> {
val user = userRepository.findById(userId).orElseThrow { NoSuchElementException("해당 유저가 존재하지 않습니다. ID: $userId") }
val user = userRepository.findById(userId).orElseThrow { NoSuchElementException(NO_SUCH_USER) }
val refrigeratorList = refrigeratorRepository.findByUser(user)
return refrigeratorList.toRefrigeratorResponseList()
}
Expand All @@ -47,7 +50,7 @@ class RefrigeratorService(
@Transactional
fun updateRefrigerator(id: Long, refrigeratorRequest: RefrigeratorRequest): RefrigeratorResponse {
val refrigerator =
refrigeratorRepository.findById(id).orElseThrow { NoSuchElementException("해당 냉장고가 존재하지 않습니다. ID: $id") }
refrigeratorRepository.findById(id).orElseThrow { NoSuchElementException(NO_SUCH_REFRIGERATOR) }
refrigerator.update(refrigeratorRequest)
return RefrigeratorResponse(refrigeratorRepository.save(refrigerator))
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/kotlin/mara/server/domain/s3/S3Service.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import com.amazonaws.services.s3.model.CannedAccessControlList
import com.amazonaws.services.s3.model.ObjectMetadata
import com.amazonaws.services.s3.model.PutObjectRequest
import com.amazonaws.util.IOUtils
import mara.server.exception.InvalidS3PathException
import mara.server.exception.InvalidS3PathException.Companion.INVALID_S3_PATH
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
Expand All @@ -23,7 +25,7 @@ class S3Service(
@Transactional
fun upload(file: MultipartFile, customDir: String?): String {
val resultDir = customDir ?: dir
if (resultDir.startsWith("/")) throw IllegalArgumentException("올바르지 않은 경로입니다. $resultDir")
if (resultDir.startsWith("/")) throw InvalidS3PathException(INVALID_S3_PATH)

val fileName = UUID.randomUUID().toString() + "-" + file.originalFilename
val objMeta = ObjectMetadata()
Expand Down
14 changes: 8 additions & 6 deletions src/main/kotlin/mara/server/domain/share/ShareDto.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ data class ShareResponse(
val thumbnailImage: String,
val isApplied: Boolean?
) {
constructor(share: Share, isApplied: Boolean?) : this(
constructor(share: Share, isApplied: Boolean) : this(
shareId = share.id,
title = share.title,
shareTime = share.shareTime,
Expand All @@ -77,12 +77,13 @@ data class ShareDetailResponse(
val location: String,
val peopleCount: Int,
val status: ShareStatus,
val thumbNailImage: String,
val thumbnailImage: String,
val itemName: String,
val shareId: Long,
val isCreatedCurrentLoginUser: Boolean,
val isCreatedByCurrentLoginUser: Boolean,
val isApplied: Boolean,
) {
constructor(share: Share, isCreatedCurrentLoginUser: Boolean) : this(
constructor(share: Share, isCreatedByCurrentLoginUser: Boolean, isApplied: Boolean) : this(
nickname = share.user.nickname,
profileImage = share.user.profileImage,
title = share.title,
Expand All @@ -94,10 +95,11 @@ data class ShareDetailResponse(
location = share.location,
peopleCount = share.peopleCount,
status = share.status,
thumbNailImage = share.thumbnailImage,
thumbnailImage = share.thumbnailImage,
itemName = share.ingredientDetail.name,
shareId = share.id,
isCreatedCurrentLoginUser = isCreatedCurrentLoginUser
isCreatedByCurrentLoginUser = isCreatedByCurrentLoginUser,
isApplied = isApplied,
)
}

Expand Down
29 changes: 19 additions & 10 deletions src/main/kotlin/mara/server/domain/share/ShareService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ package mara.server.domain.share
import mara.server.auth.security.getCurrentLoginUserId
import mara.server.domain.ingredient.IngredientDetailRepository
import mara.server.domain.user.UserService
import mara.server.exception.IllegalAccessShareException
import mara.server.exception.IllegalAccessShareException.Companion.CREATED_BY_LOGIN_USER
import mara.server.exception.IllegalAccessShareException.Companion.DIFFERENT_USER
import mara.server.exception.IllegalAccessShareException.Companion.DUPLICATED_APPLY
import mara.server.exception.ShareException.Companion.NO_SUCH_APPLY_SHARE
import mara.server.exception.ShareException.Companion.NO_SUCH_INGREDIENT
import mara.server.exception.ShareException.Companion.NO_SUCH_SHARE
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.lang.RuntimeException

@Service
class ShareService(
Expand All @@ -24,7 +30,7 @@ class ShareService(
val ingredientDetailId = shareRequest.ingredientDetailId
val ingredientDetail =
ingredientDetailRepository.findById(ingredientDetailId)
.orElseThrow { NoSuchElementException("해당 식재료가 존재하지 않습니다. ID: $ingredientDetailId") }
.orElseThrow { NoSuchElementException("$NO_SUCH_INGREDIENT Id: $ingredientDetailId") }
val user = userService.getCurrentLoginUser()
// 생성 보단 조회가 빈번 할것 같아, 매번 조회 할 때마다, 일자와 시간을 분리하기 보단, 저장 할 때 각각 & 일자+시간 저장 하는 방식으로 진행
val share = Share(
Expand All @@ -48,8 +54,8 @@ class ShareService(
fun applyShare(applyShareRequest: ApplyShareRequest): Long {
val share = getShare(applyShareRequest.shareId)
val user = userService.getCurrentLoginUser()
if (share.user.userId == user.userId) throw IllegalAccessException("본인이 올린 나눔 글에는 신청을 할 수 없습니다.")
if (applyShareRepository.existsByUserAndShare(user, share)) throw IllegalAccessException("이미 신청한 나눔 입니다.")
if (share.user.userId == user.userId) throw IllegalAccessShareException(CREATED_BY_LOGIN_USER)
if (applyShareRepository.existsByUserAndShare(user, share)) throw IllegalAccessShareException(DUPLICATED_APPLY)
val applyShare = ApplyShare(
user = user,
share = share
Expand All @@ -66,12 +72,15 @@ class ShareService(

fun getShare(shareId: Long): Share {
return shareRepository.findById(shareId)
.orElseThrow { NoSuchElementException("해당 나눔 게시물이 존재하지 않습니다. ID: $shareId") }
.orElseThrow { NoSuchElementException("$NO_SUCH_SHARE Id: $shareId") }
}

fun getShareInfo(shareId: Long): ShareDetailResponse {
val share = getShare(shareId)
return ShareDetailResponse(share, getCurrentLoginUserId() == share.user.userId)
val hasMatchingUser = share.applyShareList.any { applyShare ->
applyShare.user.userId == getCurrentLoginUserId()
}
return ShareDetailResponse(share, getCurrentLoginUserId() == share.user.userId, hasMatchingUser)
}

fun getAllShareList(pageable: Pageable, status: String): Page<ShareResponse> {
Expand Down Expand Up @@ -114,7 +123,7 @@ class ShareService(
ingredientDetailRepository.findById(
ingredientDetailId
)
.orElseThrow { NoSuchElementException("해당 식재료가 존재하지 않습니다. ID: $ingredientDetailId") }
.orElseThrow { NoSuchElementException("$NO_SUCH_INGREDIENT Id: $ingredientDetailId") }
share.updateIngredientDetail(ingredientDetail)
}

Expand All @@ -136,7 +145,7 @@ class ShareService(
@Transactional
fun deleteShare(shareId: Long): String {
val user = userService.getCurrentLoginUser()
if (user.userId != getShare(shareId).user.userId) throw RuntimeException("잘못된 사용자로부터 전달된 요청입니다.")
if (user.userId != getShare(shareId).user.userId) throw IllegalAccessShareException(DIFFERENT_USER)
shareRepository.deleteById(shareId)
return deleted
}
Expand All @@ -145,8 +154,8 @@ class ShareService(
fun deleteApplyShare(applyId: Long): String {
val user = userService.getCurrentLoginUser()
val applyShare = applyShareRepository.findById(applyId)
.orElseThrow { NoSuchElementException("해당 나눔 신청이 존재 하지 않습니다. ID: $applyId") }
if (user.userId != applyShare.user.userId) throw RuntimeException("잘못된 사용자로부터 전달된 요청입니다.")
.orElseThrow { NoSuchElementException("$NO_SUCH_APPLY_SHARE Id: $applyId") }
if (user.userId != applyShare.user.userId) throw IllegalAccessShareException(DIFFERENT_USER)
/**
신청을 취소하면 사람 수 차감
**/
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/mara/server/domain/user/UserController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ class UserController(

@GetMapping("/kakao-login")
@Operation(summary = "카카오 로그인 API")
fun kakaoLogin(@RequestParam(value = "code") authorizedCode: String): CommonResponse<AuthDto> {
return success(userService.kakaoLogin(authorizedCode))
fun kakaoLogin(@RequestParam(value = "code") authorizedCode: String, @RequestParam(value = "status") status: String): CommonResponse<AuthDto> {
return success(userService.kakaoLogin(authorizedCode, status))
}

@GetMapping("/google-login")
@Operation(summary = "구글 로그인 API")
fun googleLogin(@RequestParam(value = "code") authorizedCode: String): CommonResponse<AuthDto> {
return success(userService.googleLogin(authorizedCode))
fun googleLogin(@RequestParam(value = "code") authorizedCode: String, @RequestParam(value = "status") status: String): CommonResponse<AuthDto> {
return success(userService.googleLogin(authorizedCode, status))
}

@GetMapping("/me")
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/mara/server/domain/user/UserService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ class UserService(

fun checkNickname(nickname: String): CheckDuplicateResponse = CheckDuplicateResponse(userRepository.existsByNickname(nickname))

fun kakaoLogin(authorizedCode: String): AuthDto {
fun kakaoLogin(authorizedCode: String, status: String): AuthDto {
// 리다이랙트 url 환경 따라 다르게 전달하기 위한 구분 값
val accessToken = kakaoApiClient.requestAccessToken(authorizedCode)
val accessToken = kakaoApiClient.requestAccessToken(authorizedCode, status)
val oauthInfoResponse = kakaoApiClient.requestOauthInfo(accessToken)
log.info("kakaoId ? " + oauthInfoResponse.id)
val user = userRepository.findByKakaoId(oauthInfoResponse.id)
Expand All @@ -100,8 +100,8 @@ class UserService(
)
}

fun googleLogin(authorizedCode: String): AuthDto {
val accessToken = googleApiClient.requestAccessToken(authorizedCode)
fun googleLogin(authorizedCode: String, status: String): AuthDto {
val accessToken = googleApiClient.requestAccessToken(authorizedCode, status)
val oauthInfoResponse = googleApiClient.requestOauthInfo(accessToken)

log.info(oauthInfoResponse.email)
Expand Down
Loading

0 comments on commit f2ea2b8

Please sign in to comment.