From aeb7bbb663fec290718d1a38d4614f31199045ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=88=EC=98=81=EA=B8=B8?= Date: Mon, 23 Sep 2024 20:06:40 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20api=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/UserApplicationService.kt | 36 +++++++---- .../user/dto/UserServiceRequest.kt | 14 ----- .../user/dto/UserServiceResponse.kt | 44 +------------ .../com/withaeng/api/common/IdResponse.kt | 5 ++ .../api/controller/user/UserMeController.kt | 62 ++++++++++++++----- .../api/controller/user/dto/UserRequest.kt | 20 ++---- .../com/withaeng/domain/user/UserService.kt | 38 ++++++++---- 7 files changed, 107 insertions(+), 112 deletions(-) create mode 100644 withaeng-api/src/main/kotlin/com/withaeng/api/common/IdResponse.kt diff --git a/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/UserApplicationService.kt b/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/UserApplicationService.kt index 6dbaf9d..cfac3b9 100644 --- a/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/UserApplicationService.kt +++ b/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/UserApplicationService.kt @@ -1,8 +1,10 @@ package com.withaeng.api.applicationservice.user import com.withaeng.api.applicationservice.user.dto.* +import com.withaeng.api.common.IdResponse import com.withaeng.domain.accompany.AccompanyService import com.withaeng.domain.user.UserService +import com.withaeng.domain.user.dto.UserSimpleDto import com.withaeng.external.image.PreSignedUrl import com.withaeng.external.image.PreSignedUrlGenerator import com.withaeng.external.image.S3StorageClient @@ -35,14 +37,25 @@ class UserApplicationService( ?: UserTravelPreferenceResponse() } - fun updateProfile(userId: Long, serviceRequest: UpdateProfileServiceRequest): UpdateProfileResponse { - if (serviceRequest.hasImage) { - val preSignedUrl = generatePreSignedUrl() - val userSimpleDto = userService.updateProfile(userId, serviceRequest.toCommand(preSignedUrl.imageUrl())) - return UpdateProfileResponse(userSimpleDto.id, preSignedUrl.uploadUrl()) - } - val userSimpleDto = userService.updateProfile(userId, serviceRequest.toCommand()) - return UpdateProfileResponse(userSimpleDto.id) + fun updateTravelPreference(userId: Long, serviceRequest: UpdateTravelPreferenceServiceRequest): IdResponse { + return userService.replaceTravelPreference(userId, serviceRequest.toCommand()).toIdResponse() + } + + fun updateNickname(id: Long, nickname: String?): IdResponse { + return userService.updateNickname(id, nickname).toIdResponse() + } + + fun putIntroduction(id: Long, introduction: String?): IdResponse { + return userService.putIntroduction(id, introduction).toIdResponse() + } + + fun putProfileImage(id: Long): PutProfileImageResponse { + val preSignedUrl = generatePreSignedUrl() + val userSimpleDto = userService.putProfileImage(id, preSignedUrl.imageUrl()) + return PutProfileImageResponse( + id = userSimpleDto.id, + preSignedUrl = preSignedUrl.uploadUrl(), + ) } private fun generatePreSignedUrl(): PreSignedUrl { @@ -50,10 +63,6 @@ class UserApplicationService( return preSignedUrlGenerator.generate(objectKey) } - fun updateTravelPreference(userId: Long, serviceRequest: UpdateTravelPreferenceServiceRequest): UserDetailResponse { - return userService.replaceTravelPreference(userId, serviceRequest.toCommand()).toDetailResponse() - } - fun deleteProfileImage(id: Long) { val userSimpleDto = userService.findSimpleById(id) userSimpleDto.profile.profileImageUrl?.let { @@ -66,4 +75,7 @@ class UserApplicationService( val objectKey = "$USER_IMAGE_STORAGE_DIR/${it.split("/").last()}" s3StorageClient.delete(objectKey) } + + fun UserSimpleDto.toIdResponse(): IdResponse = IdResponse(id) + } diff --git a/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/dto/UserServiceRequest.kt b/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/dto/UserServiceRequest.kt index 911b610..b1f226f 100644 --- a/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/dto/UserServiceRequest.kt +++ b/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/dto/UserServiceRequest.kt @@ -1,22 +1,8 @@ package com.withaeng.api.applicationservice.user.dto import com.withaeng.domain.user.* -import com.withaeng.domain.user.dto.UpdateProfileCommand import com.withaeng.domain.user.dto.UpdateTravelPreferenceCommand -data class UpdateProfileServiceRequest( - val nickname: String?, - val introduction: String?, - val hasImage: Boolean = false, -) - -fun UpdateProfileServiceRequest.toCommand(imageUrl: String? = null): UpdateProfileCommand = - UpdateProfileCommand( - nickname = nickname, - introduction = introduction, - profileImageUrl = imageUrl - ) - data class UpdateTravelPreferenceServiceRequest( val mbti: Set? = emptySet(), val preferTravelType: UserPreferTravelType? = null, diff --git a/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/dto/UserServiceResponse.kt b/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/dto/UserServiceResponse.kt index 0c8bddb..63be36f 100644 --- a/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/dto/UserServiceResponse.kt +++ b/withaeng-api/src/main/kotlin/com/withaeng/api/applicationservice/user/dto/UserServiceResponse.kt @@ -18,23 +18,6 @@ fun UserSimpleDto.toSimpleResponse(): UserSimpleResponse = UserSimpleResponse( nickname = profile.nickname ) -data class UserDetailResponse( - val id: Long, - val createdDate: LocalDate, - val email: String, - val gender: Gender, - val birth: LocalDate, - val mannerScore: Double, - val profile: UserProfileResponse, - val travelPreference: UserTravelPreferenceResponse? = null, -) - -data class UserProfileResponse( - val nickname: String, - val introduction: String? = null, - val profileImageUrl: String? = null, -) - data class UserTravelPreferenceResponse( val mbti: Set? = emptySet(), val preferTravelType: UserPreferTravelType? = null, @@ -45,31 +28,6 @@ data class UserTravelPreferenceResponse( val drinkingType: UserDrinkingType? = null, ) -fun UserDetailDto.toDetailResponse(): UserDetailResponse = UserDetailResponse( - id = id, - createdDate = createdDate, - email = email, - gender = gender, - birth = birth, - mannerScore = mannerScore, - profile = UserProfileResponse( - nickname = profile.nickname, - introduction = profile.introduction, - profileImageUrl = profile.profileImageUrl, - ), - travelPreference = travelPreference?.let { - UserTravelPreferenceResponse( - mbti = it.mbti, - preferTravelType = it.preferTravelType, - preferTravelThemes = it.preferTravelThemes, - consumeStyle = it.consumeStyle, - foodRestrictions = it.foodRestrictions, - smokingType = it.smokingType, - drinkingType = it.drinkingType - ) - }, -) - fun UserTravelPreferenceDto.toServiceResponse(): UserTravelPreferenceResponse = UserTravelPreferenceResponse( mbti = mbti, @@ -113,7 +71,7 @@ data class UserStatisticalProfileResponse( } } -data class UpdateProfileResponse( +data class PutProfileImageResponse( val id: Long, val preSignedUrl: String? = null, ) diff --git a/withaeng-api/src/main/kotlin/com/withaeng/api/common/IdResponse.kt b/withaeng-api/src/main/kotlin/com/withaeng/api/common/IdResponse.kt new file mode 100644 index 0000000..e82250a --- /dev/null +++ b/withaeng-api/src/main/kotlin/com/withaeng/api/common/IdResponse.kt @@ -0,0 +1,5 @@ +package com.withaeng.api.common + +data class IdResponse( + val id: Long, +) \ No newline at end of file diff --git a/withaeng-api/src/main/kotlin/com/withaeng/api/controller/user/UserMeController.kt b/withaeng-api/src/main/kotlin/com/withaeng/api/controller/user/UserMeController.kt index 77302c8..9686844 100644 --- a/withaeng-api/src/main/kotlin/com/withaeng/api/controller/user/UserMeController.kt +++ b/withaeng-api/src/main/kotlin/com/withaeng/api/controller/user/UserMeController.kt @@ -1,13 +1,14 @@ package com.withaeng.api.controller.user import com.withaeng.api.applicationservice.user.UserApplicationService -import com.withaeng.api.applicationservice.user.dto.UpdateProfileResponse -import com.withaeng.api.applicationservice.user.dto.UserDetailResponse +import com.withaeng.api.applicationservice.user.dto.PutProfileImageResponse import com.withaeng.api.applicationservice.user.dto.UserStatisticalProfileResponse import com.withaeng.api.applicationservice.user.dto.UserTravelPreferenceResponse import com.withaeng.api.common.ApiResponse -import com.withaeng.api.controller.user.dto.UpdateProfileRequest -import com.withaeng.api.controller.user.dto.UpdateTravelPreferenceRequest +import com.withaeng.api.common.IdResponse +import com.withaeng.api.controller.user.dto.PatchNicknameRequest +import com.withaeng.api.controller.user.dto.PutIntroductionRequest +import com.withaeng.api.controller.user.dto.PutTravelPreferenceRequest import com.withaeng.api.controller.user.dto.toServiceRequest import com.withaeng.api.security.authentication.UserInfo import com.withaeng.api.security.resolver.GetAuth @@ -51,38 +52,67 @@ class UserMeController(private val userApplicationService: UserApplicationServic } @Operation( - summary = "Update Travel Preference", + summary = "Replace Travel Preference", description = "여행 선호 정보 업데이트 API", security = [SecurityRequirement(name = "Authorization")] ) @PutMapping("/travel-preference") - fun updateTravelPreference( + fun putTravelPreference( @GetAuth userInfo: UserInfo, - @RequestBody @Valid request: UpdateTravelPreferenceRequest, - ): ApiResponse { + @RequestBody @Valid request: PutTravelPreferenceRequest, + ): ApiResponse { return ApiResponse.success( userApplicationService.updateTravelPreference(userInfo.id, request.toServiceRequest()) ) } @Operation( - summary = "Update Profile", - description = "프로필 업데이트 API", + summary = "Replace Introduction", + description = "이전 소개글은 삭제됩니다.", security = [SecurityRequirement(name = "Authorization")] ) - @PatchMapping("/profile") - fun updateProfile( + @PutMapping("/introduction") + fun putIntroduction( @GetAuth userInfo: UserInfo, - @RequestBody @Valid request: UpdateProfileRequest, - ): ApiResponse { + @RequestBody @Valid request: PutIntroductionRequest, + ): ApiResponse { return ApiResponse.success( - userApplicationService.updateProfile(userInfo.id, request.toServiceRequest()) + userApplicationService.putIntroduction(userInfo.id, request.introduction) + ) + } + + @Operation( + summary = "Replace Profile Image", + description = "이전 프로필 이미지는 삭제됩니다.", + security = [SecurityRequirement(name = "Authorization")] + ) + @PutMapping("/profile-image") + fun putProfileImage( + @GetAuth userInfo: UserInfo, + ): ApiResponse { + return ApiResponse.success( + userApplicationService.putProfileImage(userInfo.id) + ) + } + + @Operation( + summary = "Update Nickname", + description = "nickname 값이 null 이면 기존 닉네임이 유지됩니다.", + security = [SecurityRequirement(name = "Authorization")] + ) + @PatchMapping("/nickname") + fun patchNickname( + @GetAuth userInfo: UserInfo, + @RequestBody @Valid request: PatchNicknameRequest, + ): ApiResponse { + return ApiResponse.success( + userApplicationService.updateNickname(userInfo.id, request.nickname) ) } @Operation( summary = "Delete Profile Image", - description = "프로필 이미지 삭제 API", + description = "", security = [SecurityRequirement(name = "Authorization")] ) @DeleteMapping("/profile-image") diff --git a/withaeng-api/src/main/kotlin/com/withaeng/api/controller/user/dto/UserRequest.kt b/withaeng-api/src/main/kotlin/com/withaeng/api/controller/user/dto/UserRequest.kt index 96fd009..7c11438 100644 --- a/withaeng-api/src/main/kotlin/com/withaeng/api/controller/user/dto/UserRequest.kt +++ b/withaeng-api/src/main/kotlin/com/withaeng/api/controller/user/dto/UserRequest.kt @@ -1,31 +1,23 @@ package com.withaeng.api.controller.user.dto -import com.withaeng.api.applicationservice.user.dto.UpdateProfileServiceRequest import com.withaeng.api.applicationservice.user.dto.UpdateTravelPreferenceServiceRequest import com.withaeng.domain.user.* import io.swagger.v3.oas.annotations.media.Schema @Schema(description = "[Request] User 프로필 정보를 추가합니다") -data class UpdateProfileRequest( +data class PatchNicknameRequest( @Schema(description = "유저 닉네임") val nickname: String? = null, +) +@Schema(description = "[Request] User 소개 정보를 추가합니다") +data class PutIntroductionRequest( @Schema(description = "유저 소개") val introduction: String? = null, - - @Schema(description = "프로필 이미지 URL") - val hasImage: Boolean = false, ) -fun UpdateProfileRequest.toServiceRequest(): UpdateProfileServiceRequest = - UpdateProfileServiceRequest( - nickname = nickname, - introduction = introduction, - hasImage = hasImage, - ) - @Schema(description = "[Request] User 여행 선호 스타일 정보를 추가합니다") -data class UpdateTravelPreferenceRequest( +data class PutTravelPreferenceRequest( @Schema(description = "유저 MBTI") val mbti: Set? = emptySet(), @@ -48,7 +40,7 @@ data class UpdateTravelPreferenceRequest( val drinkingType: UserDrinkingType? = null, ) -fun UpdateTravelPreferenceRequest.toServiceRequest(): UpdateTravelPreferenceServiceRequest = +fun PutTravelPreferenceRequest.toServiceRequest(): UpdateTravelPreferenceServiceRequest = UpdateTravelPreferenceServiceRequest( mbti = mbti, preferTravelType = preferTravelType, diff --git a/withaeng-domain/src/main/kotlin/com/withaeng/domain/user/UserService.kt b/withaeng-domain/src/main/kotlin/com/withaeng/domain/user/UserService.kt index 1fe9068..313f553 100644 --- a/withaeng-domain/src/main/kotlin/com/withaeng/domain/user/UserService.kt +++ b/withaeng-domain/src/main/kotlin/com/withaeng/domain/user/UserService.kt @@ -69,7 +69,7 @@ class UserService(private val userRepository: UserRepository) { } @Transactional - fun replaceTravelPreference(userId: Long, command: UpdateTravelPreferenceCommand): UserDetailDto { + fun replaceTravelPreference(userId: Long, command: UpdateTravelPreferenceCommand): UserSimpleDto { val user = userRepository.findByIdOrNull(userId).getOrThrow() user.travelPreference = user.travelPreference ?: UserTravelPreference.create(user) user.travelPreference?.mbti = command.mbti ?: emptySet() @@ -79,7 +79,7 @@ class UserService(private val userRepository: UserRepository) { user.travelPreference?.foodRestrictions = command.foodRestrictions ?: emptySet() user.travelPreference?.smokingType = command.smokingType user.travelPreference?.drinkingType = command.drinkingType - return user.toDetailDto() + return user.toSimpleDto() } @Transactional @@ -89,15 +89,6 @@ class UserService(private val userRepository: UserRepository) { return user.toSimpleDto() } - @Transactional - fun updateProfile(userId: Long, command: UpdateProfileCommand): UserSimpleDto { - val user = userRepository.findByIdOrNull(userId).getOrThrow() - user.profile.nickname = command.nickname ?: user.profile.nickname - user.profile.introduction = command.introduction ?: user.profile.introduction - user.profile.profileImageUrl = command.profileImageUrl ?: user.profile.profileImageUrl - return user.toSimpleDto() - } - @Transactional fun grantUserRole(id: Long) { val user = userRepository.findByIdOrNull(id) @@ -107,8 +98,24 @@ class UserService(private val userRepository: UserRepository) { } @Transactional - fun deleteByEmail(email: String) { - return userRepository.deleteByEmail(email) + fun updateNickname(id: Long, nickname: String?): UserSimpleDto { + val user = userRepository.findByIdOrNull(id).getOrThrow() + user.profile.nickname = nickname ?: user.profile.nickname + return user.toSimpleDto() + } + + @Transactional + fun putIntroduction(id: Long, introduction: String?): UserSimpleDto { + val user = userRepository.findByIdOrNull(id).getOrThrow() + user.profile.introduction = introduction + return user.toSimpleDto() + } + + @Transactional + fun putProfileImage(id: Long, imageUrl: String): UserSimpleDto { + val user = userRepository.findByIdOrNull(id).getOrThrow() + user.profile.profileImageUrl = imageUrl + return user.toSimpleDto() } @Transactional @@ -117,6 +124,11 @@ class UserService(private val userRepository: UserRepository) { user.profile.profileImageUrl = null } + @Transactional + fun deleteByEmail(email: String) { + return userRepository.deleteByEmail(email) + } + private fun User?.getOrThrow(): User { this ?: throw WithaengException.of( type = WithaengExceptionType.NOT_EXIST,