Skip to content

refactor: 프로필 업데이트 api 분리 #84

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

Merged
merged 1 commit into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -35,25 +37,32 @@ 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 {
val objectKey = "$USER_IMAGE_STORAGE_DIR/${UUID.randomUUID()}"
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 {
Expand All @@ -66,4 +75,7 @@ class UserApplicationService(
val objectKey = "$USER_IMAGE_STORAGE_DIR/${it.split("/").last()}"
s3StorageClient.delete(objectKey)
}

fun UserSimpleDto.toIdResponse(): IdResponse = IdResponse(id)

}
Original file line number Diff line number Diff line change
@@ -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<UserMbti>? = emptySet(),
val preferTravelType: UserPreferTravelType? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<UserMbti>? = emptySet(),
val preferTravelType: UserPreferTravelType? = null,
Expand All @@ -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,
Expand Down Expand Up @@ -113,7 +71,7 @@ data class UserStatisticalProfileResponse(
}
}

data class UpdateProfileResponse(
data class PutProfileImageResponse(
val id: Long,
val preSignedUrl: String? = null,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.withaeng.api.common

data class IdResponse(
val id: Long,
)
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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<UserDetailResponse> {
@RequestBody @Valid request: PutTravelPreferenceRequest,
): ApiResponse<IdResponse> {
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<UpdateProfileResponse> {
@RequestBody @Valid request: PutIntroductionRequest,
): ApiResponse<IdResponse> {
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<PutProfileImageResponse> {
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<IdResponse> {
return ApiResponse.success(
userApplicationService.updateNickname(userInfo.id, request.nickname)
)
}

@Operation(
summary = "Delete Profile Image",
description = "프로필 이미지 삭제 API",
description = "",
security = [SecurityRequirement(name = "Authorization")]
)
@DeleteMapping("/profile-image")
Expand Down
Original file line number Diff line number Diff line change
@@ -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<UserMbti>? = emptySet(),

Expand All @@ -48,7 +40,7 @@ data class UpdateTravelPreferenceRequest(
val drinkingType: UserDrinkingType? = null,
)

fun UpdateTravelPreferenceRequest.toServiceRequest(): UpdateTravelPreferenceServiceRequest =
fun PutTravelPreferenceRequest.toServiceRequest(): UpdateTravelPreferenceServiceRequest =
UpdateTravelPreferenceServiceRequest(
mbti = mbti,
preferTravelType = preferTravelType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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,
Expand Down
Loading