Skip to content

Commit f2ea2b8

Browse files
Jiwon-chojhkang1517gwon188
authored
MARA-88 : 환경별 리다이렉트 uri 구분을 위한 status 값 추가, 나눔 변수 추가 및 수정, 전역 예외 처리 및 커스텀 예외 클래스 추가 (#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]>
1 parent aadf7d5 commit f2ea2b8

File tree

16 files changed

+170
-51
lines changed

16 files changed

+170
-51
lines changed

src/main/kotlin/mara/server/auth/ClientConfig.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,9 @@ class ClientConfig {
1111
return RestTemplate()
1212
}
1313
}
14+
15+
enum class DeployStatus(val uri: String) {
16+
LOCAL(""),
17+
DEV("http://localhost:3000/login"),
18+
PROD("https://fridgelink.site/login")
19+
}

src/main/kotlin/mara/server/auth/google/GoogleApiClient.kt

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package mara.server.auth.google
22

3-
import mara.server.util.logger
3+
import mara.server.auth.DeployStatus
4+
import mara.server.exception.InvalidDeployStatusException
5+
import mara.server.exception.InvalidDeployStatusException.Companion.INVALID_DEPLOY_STATUS
46
import org.springframework.beans.factory.annotation.Value
57
import org.springframework.http.HttpEntity
68
import org.springframework.http.HttpHeaders
@@ -10,6 +12,7 @@ import org.springframework.stereotype.Component
1012
import org.springframework.util.LinkedMultiValueMap
1113
import org.springframework.util.MultiValueMap
1214
import org.springframework.web.client.RestTemplate
15+
import java.util.Locale
1316

1417
@Component
1518
class GoogleApiClient(
@@ -28,16 +31,19 @@ class GoogleApiClient(
2831

2932
) {
3033

31-
val log = logger()
32-
33-
fun getRedirectUri(): String {
34-
val os = System.getProperty("os.name")
35-
log.info("OS : {}", os)
36-
if (os.contains("Mac") || os.contains("Windows")) return "http://localhost:8080/users/google-login"
37-
return "http://localhost:3000/login"
34+
fun getRedirectUri(status: String): String {
35+
val deployStatus = try {
36+
DeployStatus.valueOf(status.uppercase(Locale.getDefault()))
37+
} catch (e: IllegalArgumentException) {
38+
throw InvalidDeployStatusException("$INVALID_DEPLOY_STATUS Status: $status")
39+
}
40+
return when (deployStatus) {
41+
DeployStatus.LOCAL -> "http://localhost:8080/users/google-login"
42+
else -> deployStatus.uri
43+
}
3844
}
3945

40-
fun requestAccessToken(authorizedCode: String): String {
46+
fun requestAccessToken(authorizedCode: String, status: String): String {
4147
val url = "$authUrl/token"
4248
val httpHeaders = HttpHeaders()
4349
httpHeaders.contentType = MediaType.APPLICATION_FORM_URLENCODED
@@ -46,7 +52,7 @@ class GoogleApiClient(
4652
body.add("grant_type", "authorization_code")
4753
body.add("client_id", clientId)
4854
body.add("client_secret", secret)
49-
body.add("redirect_uri", getRedirectUri())
55+
body.add("redirect_uri", getRedirectUri(status))
5056

5157
val request = HttpEntity(body, httpHeaders)
5258

src/main/kotlin/mara/server/auth/kakao/KakaoApiClient.kt

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package mara.server.auth.kakao
22

3-
import mara.server.util.logger
3+
import mara.server.auth.DeployStatus
4+
import mara.server.exception.InvalidDeployStatusException
5+
import mara.server.exception.InvalidDeployStatusException.Companion.INVALID_DEPLOY_STATUS
46
import org.springframework.beans.factory.annotation.Value
57
import org.springframework.http.HttpEntity
68
import org.springframework.http.HttpHeaders
@@ -9,6 +11,7 @@ import org.springframework.stereotype.Component
911
import org.springframework.util.LinkedMultiValueMap
1012
import org.springframework.util.MultiValueMap
1113
import org.springframework.web.client.RestTemplate
14+
import java.util.Locale
1215

1316
@Component
1417
class KakaoApiClient(
@@ -29,16 +32,20 @@ class KakaoApiClient(
2932
private val appAdminKey: String,
3033
) {
3134

32-
val log = logger()
33-
34-
fun getRedirectUri(): String {
35-
val os = System.getProperty("os.name")
36-
log.info("OS : {}", os)
37-
if (os.contains("Mac") || os.contains("Windows")) return "http://localhost:8080/users/kakao-login"
38-
return "http://localhost:3000/login"
35+
fun getRedirectUri(status: String): String {
36+
val deployStatus = try {
37+
DeployStatus.valueOf(status.uppercase(Locale.getDefault()))
38+
} catch (e: IllegalArgumentException) {
39+
throw InvalidDeployStatusException("$INVALID_DEPLOY_STATUS Status: $status")
40+
}
41+
42+
return when (deployStatus) {
43+
DeployStatus.LOCAL -> "http://localhost:8080/users/kakao-login"
44+
else -> deployStatus.uri
45+
}
3946
}
4047

41-
fun requestAccessToken(authorizedCode: String): String {
48+
fun requestAccessToken(authorizedCode: String, status: String): String {
4249
val url = "$authUrl/oauth/token"
4350

4451
val httpHeaders = HttpHeaders()
@@ -48,7 +55,7 @@ class KakaoApiClient(
4855
body.add("grant_type", "authorization_code")
4956
body.add("client_id", clientId)
5057
body.add("client_secret", secret)
51-
body.add("redirect_uri", getRedirectUri())
58+
body.add("redirect_uri", getRedirectUri(status))
5259

5360
val request = HttpEntity(body, httpHeaders)
5461

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
package mara.server.common
22

3+
import org.springframework.http.HttpStatus
4+
import org.springframework.http.ResponseEntity
5+
36
data class CommonResponse<T>(
47
var message: String = "ok",
58
var data: T? = null,
69
)
710

11+
data class ErrorResponse(
12+
var message: String
13+
)
14+
815
fun <T> success(data: T? = null): CommonResponse<T> = CommonResponse(data = data)
16+
17+
fun fail(httpStatus: HttpStatus, message: String): ResponseEntity<ErrorResponse> = ResponseEntity
18+
.status(httpStatus)
19+
.body(ErrorResponse(message = message))

src/main/kotlin/mara/server/domain/ingredient/IngredientDetailService.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package mara.server.domain.ingredient
22

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

2728
val ingredientId = ingredientDetailRequest.ingredientId
2829
val ingredient = ingredientRepository.findById(ingredientId)
@@ -55,7 +56,7 @@ class IngredientDetailService(
5556

5657
fun getIngredientDetailList(refrigeratorId: Long, location: IngredientLocation, pageable: Pageable): Page<IngredientDetailResponse> {
5758
val refrigerator = refrigeratorRepository.findById(refrigeratorId)
58-
.orElseThrow { NoSuchElementException("해당 냉장고가 존재하지 않습니다. ID: $refrigeratorId") }
59+
.orElseThrow { NoSuchElementException(NO_SUCH_REFRIGERATOR) }
5960
val ingredientDetailList =
6061
ingredientDetailRepository.findByRefrigerator(refrigerator, location, pageable)
6162
return ingredientDetailList.toIngredientDetailResponseListPage()

src/main/kotlin/mara/server/domain/refrigerator/RefrigeratorService.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package mara.server.domain.refrigerator
22

33
import mara.server.domain.user.UserRepository
44
import mara.server.domain.user.UserService
5+
import mara.server.exception.RefrigeratorException.Companion.NO_SUCH_REFRIGERATOR
6+
import mara.server.exception.UserException.Companion.NO_SUCH_USER
57
import org.springframework.stereotype.Service
68
import org.springframework.transaction.annotation.Transactional
79

@@ -13,7 +15,8 @@ class RefrigeratorService(
1315
) {
1416
private val deleted = "deleted"
1517

16-
fun getCurrentLoginUserRefrigeratorList(): List<Refrigerator> = refrigeratorRepository.findByUser(userService.getCurrentLoginUser())
18+
fun getCurrentLoginUserRefrigeratorList(): List<Refrigerator> =
19+
refrigeratorRepository.findByUser(userService.getCurrentLoginUser())
1720

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

3639
fun getRefrigeratorList(userId: Long): List<RefrigeratorResponse> {
37-
val user = userRepository.findById(userId).orElseThrow { NoSuchElementException("해당 유저가 존재하지 않습니다. ID: $userId") }
40+
val user = userRepository.findById(userId).orElseThrow { NoSuchElementException(NO_SUCH_USER) }
3841
val refrigeratorList = refrigeratorRepository.findByUser(user)
3942
return refrigeratorList.toRefrigeratorResponseList()
4043
}
@@ -47,7 +50,7 @@ class RefrigeratorService(
4750
@Transactional
4851
fun updateRefrigerator(id: Long, refrigeratorRequest: RefrigeratorRequest): RefrigeratorResponse {
4952
val refrigerator =
50-
refrigeratorRepository.findById(id).orElseThrow { NoSuchElementException("해당 냉장고가 존재하지 않습니다. ID: $id") }
53+
refrigeratorRepository.findById(id).orElseThrow { NoSuchElementException(NO_SUCH_REFRIGERATOR) }
5154
refrigerator.update(refrigeratorRequest)
5255
return RefrigeratorResponse(refrigeratorRepository.save(refrigerator))
5356
}

src/main/kotlin/mara/server/domain/s3/S3Service.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import com.amazonaws.services.s3.model.CannedAccessControlList
55
import com.amazonaws.services.s3.model.ObjectMetadata
66
import com.amazonaws.services.s3.model.PutObjectRequest
77
import com.amazonaws.util.IOUtils
8+
import mara.server.exception.InvalidS3PathException
9+
import mara.server.exception.InvalidS3PathException.Companion.INVALID_S3_PATH
810
import org.springframework.beans.factory.annotation.Value
911
import org.springframework.stereotype.Service
1012
import org.springframework.transaction.annotation.Transactional
@@ -23,7 +25,7 @@ class S3Service(
2325
@Transactional
2426
fun upload(file: MultipartFile, customDir: String?): String {
2527
val resultDir = customDir ?: dir
26-
if (resultDir.startsWith("/")) throw IllegalArgumentException("올바르지 않은 경로입니다. $resultDir")
28+
if (resultDir.startsWith("/")) throw InvalidS3PathException(INVALID_S3_PATH)
2729

2830
val fileName = UUID.randomUUID().toString() + "-" + file.originalFilename
2931
val objMeta = ObjectMetadata()

src/main/kotlin/mara/server/domain/share/ShareDto.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ data class ShareResponse(
5050
val thumbnailImage: String,
5151
val isApplied: Boolean?
5252
) {
53-
constructor(share: Share, isApplied: Boolean?) : this(
53+
constructor(share: Share, isApplied: Boolean) : this(
5454
shareId = share.id,
5555
title = share.title,
5656
shareTime = share.shareTime,
@@ -77,12 +77,13 @@ data class ShareDetailResponse(
7777
val location: String,
7878
val peopleCount: Int,
7979
val status: ShareStatus,
80-
val thumbNailImage: String,
80+
val thumbnailImage: String,
8181
val itemName: String,
8282
val shareId: Long,
83-
val isCreatedCurrentLoginUser: Boolean,
83+
val isCreatedByCurrentLoginUser: Boolean,
84+
val isApplied: Boolean,
8485
) {
85-
constructor(share: Share, isCreatedCurrentLoginUser: Boolean) : this(
86+
constructor(share: Share, isCreatedByCurrentLoginUser: Boolean, isApplied: Boolean) : this(
8687
nickname = share.user.nickname,
8788
profileImage = share.user.profileImage,
8889
title = share.title,
@@ -94,10 +95,11 @@ data class ShareDetailResponse(
9495
location = share.location,
9596
peopleCount = share.peopleCount,
9697
status = share.status,
97-
thumbNailImage = share.thumbnailImage,
98+
thumbnailImage = share.thumbnailImage,
9899
itemName = share.ingredientDetail.name,
99100
shareId = share.id,
100-
isCreatedCurrentLoginUser = isCreatedCurrentLoginUser
101+
isCreatedByCurrentLoginUser = isCreatedByCurrentLoginUser,
102+
isApplied = isApplied,
101103
)
102104
}
103105

src/main/kotlin/mara/server/domain/share/ShareService.kt

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@ package mara.server.domain.share
33
import mara.server.auth.security.getCurrentLoginUserId
44
import mara.server.domain.ingredient.IngredientDetailRepository
55
import mara.server.domain.user.UserService
6+
import mara.server.exception.IllegalAccessShareException
7+
import mara.server.exception.IllegalAccessShareException.Companion.CREATED_BY_LOGIN_USER
8+
import mara.server.exception.IllegalAccessShareException.Companion.DIFFERENT_USER
9+
import mara.server.exception.IllegalAccessShareException.Companion.DUPLICATED_APPLY
10+
import mara.server.exception.ShareException.Companion.NO_SUCH_APPLY_SHARE
11+
import mara.server.exception.ShareException.Companion.NO_SUCH_INGREDIENT
12+
import mara.server.exception.ShareException.Companion.NO_SUCH_SHARE
613
import org.springframework.data.domain.Page
714
import org.springframework.data.domain.Pageable
815
import org.springframework.stereotype.Service
916
import org.springframework.transaction.annotation.Transactional
10-
import java.lang.RuntimeException
1117

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

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

7278
fun getShareInfo(shareId: Long): ShareDetailResponse {
7379
val share = getShare(shareId)
74-
return ShareDetailResponse(share, getCurrentLoginUserId() == share.user.userId)
80+
val hasMatchingUser = share.applyShareList.any { applyShare ->
81+
applyShare.user.userId == getCurrentLoginUserId()
82+
}
83+
return ShareDetailResponse(share, getCurrentLoginUserId() == share.user.userId, hasMatchingUser)
7584
}
7685

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

@@ -136,7 +145,7 @@ class ShareService(
136145
@Transactional
137146
fun deleteShare(shareId: Long): String {
138147
val user = userService.getCurrentLoginUser()
139-
if (user.userId != getShare(shareId).user.userId) throw RuntimeException("잘못된 사용자로부터 전달된 요청입니다.")
148+
if (user.userId != getShare(shareId).user.userId) throw IllegalAccessShareException(DIFFERENT_USER)
140149
shareRepository.deleteById(shareId)
141150
return deleted
142151
}
@@ -145,8 +154,8 @@ class ShareService(
145154
fun deleteApplyShare(applyId: Long): String {
146155
val user = userService.getCurrentLoginUser()
147156
val applyShare = applyShareRepository.findById(applyId)
148-
.orElseThrow { NoSuchElementException("해당 나눔 신청이 존재 하지 않습니다. ID: $applyId") }
149-
if (user.userId != applyShare.user.userId) throw RuntimeException("잘못된 사용자로부터 전달된 요청입니다.")
157+
.orElseThrow { NoSuchElementException("$NO_SUCH_APPLY_SHARE Id: $applyId") }
158+
if (user.userId != applyShare.user.userId) throw IllegalAccessShareException(DIFFERENT_USER)
150159
/**
151160
신청을 취소하면 사람 수 차감
152161
**/

src/main/kotlin/mara/server/domain/user/UserController.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ class UserController(
3636

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

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

4949
@GetMapping("/me")

0 commit comments

Comments
 (0)