Skip to content

Commit

Permalink
fix: solve user update error (#208)
Browse files Browse the repository at this point in the history
* chore: TripleMeetingServiceTest commented

* fix: change update user information to upsert user information

* chore: commented broken test

* feat: initialize repository test

* fix: remove gender update

* chore: format

* fix: change findUserProfile due to misfunction

* fix: change update user information logic

* test: add user integration test

* feat: move update user profile logic to user service

* test: add user domain test

* chore: fix some missing value due to solving conflict

* chore: add service injection

* chore: delete comment

* fix: delete h2 mode

* fix: add h2 option to avoid keyword

* fix: change url in user api

* chore: move private function to end

* fix: delete making test-aplication.yml

* feat: add swagger for UserApi

* feat: change user creation logic
  • Loading branch information
SangMinLeeAI authored Nov 25, 2024
1 parent 4d9f2ed commit dd68a9c
Show file tree
Hide file tree
Showing 11 changed files with 372 additions and 135 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/dev-validate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ jobs:
run: |
mkdir -p ./src/main/resources
echo "${{ env.PROD_PROPERTIES }}" > ./src/main/resources/application.yml
- name: Create test-application.yml
run: |
mkdir -p ./src/test/resources
echo "${{ env.TEST_PROPERTIES }}" > ./src/test/resources/application.yml
# - name: Create test-application.yml
# run: |
# mkdir -p ./src/test/resources
# echo "${{ env.TEST_PROPERTIES }}" > ./src/test/resources/application.yml
- name: Build with Gradle
run: ./gradlew clean build
90 changes: 69 additions & 21 deletions src/main/kotlin/uoslife/servermeeting/user/api/UserApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import org.springframework.web.bind.annotation.*
import uoslife.servermeeting.global.error.ErrorResponse
import uoslife.servermeeting.user.dto.request.UserPersonalInformationUpdateRequest
import uoslife.servermeeting.user.dto.request.UserUpdateRequest
import uoslife.servermeeting.user.dto.response.UserAllInformationResponse
import uoslife.servermeeting.user.dto.response.UserBranchResponse
import uoslife.servermeeting.user.dto.response.UserProfileResponse
import uoslife.servermeeting.user.dto.response.UserSimpleResponse
import uoslife.servermeeting.user.service.UserService

Expand All @@ -26,15 +26,14 @@ import uoslife.servermeeting.user.service.UserService
class UserApi(
private val userService: UserService,
) {
@Operation(summary = "User 정보 조회", description = "토큰을 통해서 User의 정보를 조회합니다.")
@Operation(summary = "User 정보 조회", description = "토큰을 통해서 User의 간단 정보를 조회합니다.")
@ApiResponses(
value =
[
ApiResponse(
responseCode = "200",
description = "유저 정보 조회 성공",
content =
[Content(schema = Schema(implementation = UserProfileResponse::class))]
content = [Content(schema = Schema(implementation = UserSimpleResponse::class))]
),
ApiResponse(
responseCode = "400",
Expand All @@ -56,24 +55,54 @@ class UserApi(
return ResponseEntity.ok().body(userSimpleResponse)
}

@GetMapping("/profile")
@Operation(summary = "User 상세 조회", description = "토큰을 통해서 유저의 모든 정보를 조회합니다.")
@ApiResponses(
value =
[
ApiResponse(
responseCode = "200",
description = "유저 정보 조회 성공",
content =
[
Content(
schema = Schema(implementation = UserAllInformationResponse::class)
)]
),
ApiResponse(
responseCode = "400",
description = "해당 유저 정보 없음",
content =
[
Content(
schema = Schema(implementation = ErrorResponse::class),
)]
),
]
)
@GetMapping("/all-info")
fun getUserProfile(
@AuthenticationPrincipal userDetails: UserDetails
): ResponseEntity<UserProfileResponse> {
val userProfileResponse: UserProfileResponse =
UserProfileResponse.valueOf(userService.getUserProfile(userDetails.username.toLong()))
): ResponseEntity<UserAllInformationResponse> {
val userAllInformationResponse: UserAllInformationResponse =
UserAllInformationResponse.valueOf(
userService.getUserDetailedInformation(userDetails.username.toLong())
)

return ResponseEntity.ok().body(userProfileResponse)
return ResponseEntity.ok().body(userAllInformationResponse)
}

@Operation(summary = "User 정보 업데이트", description = "유저의 정보를 업데이트합니다.")
@Operation(summary = "User 정보 업데이트", description = "유저의 상세 정보를 업데이트합니다.")
@ApiResponses(
value =
[
ApiResponse(
responseCode = "204",
responseCode = "200",
description = "유저 정보 업데이트 성공",
content = [Content(schema = Schema(implementation = Unit::class))]
content =
[
Content(
schema = Schema(implementation = UserAllInformationResponse::class)
)]
),
ApiResponse(
responseCode = "400",
Expand All @@ -86,30 +115,49 @@ class UserApi(
),
]
)
@PatchMapping
@PatchMapping("/user-info")
fun updateUser(
@RequestBody(required = false) requestBody: UserUpdateRequest,
@AuthenticationPrincipal userDetails: UserDetails,
): ResponseEntity<UserSimpleResponse> {
): ResponseEntity<UserAllInformationResponse> {
val user =
userService.updateUserInformation(
requestBody.toUpdateUserInformationCommand(userDetails.username.toLong())
)
val userSimpleResponse = UserSimpleResponse.valueOf(user)
return ResponseEntity.status(HttpStatus.OK).body(userSimpleResponse)
val userAllInformationResponse = UserAllInformationResponse.valueOf(user)
return ResponseEntity.status(HttpStatus.OK).body(userAllInformationResponse)
}

@PatchMapping("/user-info")
@Operation(summary = "User 기본 정보 업데이트", description = "유저의 기본 정보를 업데이트합니다.")
@ApiResponses(
value =
[
ApiResponse(
responseCode = "200",
description = "유저 정보 업데이트 성공",
content = [Content(schema = Schema(implementation = UserSimpleResponse::class))]
),
ApiResponse(
responseCode = "400",
description = "해당 유저 정보 없음",
content =
[
Content(
schema = Schema(implementation = ErrorResponse::class),
)]
),
]
)
@PatchMapping
fun updateUserPersonalInformation(
@RequestBody(required = false) requestBody: UserPersonalInformationUpdateRequest,
@AuthenticationPrincipal userDetails: UserDetails,
): ResponseEntity<UserProfileResponse> {
): ResponseEntity<UserSimpleResponse> {
val command =
requestBody.toUpdateUserPersonalInformationCommand(userDetails.username.toLong())
println(command.toString())
val user = userService.updateUserPersonalInformation(command)
val userProfileResponse = UserProfileResponse.valueOf(user)
return ResponseEntity.status(HttpStatus.OK).body(userProfileResponse)
val userSimpleResponse = UserSimpleResponse.valueOf(user)
return ResponseEntity.status(HttpStatus.OK).body(userSimpleResponse)
}

@Operation(summary = "User 계정 삭제", description = "유저 ID를 이용하여 삭제합니다.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package uoslife.servermeeting.user.command

import uoslife.servermeeting.user.entity.enums.AppearanceType
import uoslife.servermeeting.user.entity.enums.EyelidType
import uoslife.servermeeting.user.entity.enums.GenderType
import uoslife.servermeeting.user.entity.enums.SmokingType

class UserCommand {
Expand All @@ -24,7 +23,6 @@ class UserCommand {
val userId: Long,
val name: String?,
val phoneNumber: String?,
val gender: GenderType?,
val kakaoTalkId: String?,
)
}
32 changes: 2 additions & 30 deletions src/main/kotlin/uoslife/servermeeting/user/dao/UserDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import org.springframework.stereotype.Repository
import uoslife.servermeeting.payment.entity.Payment
import uoslife.servermeeting.payment.entity.QPayment.payment
import uoslife.servermeeting.payment.entity.enums.PaymentStatus
import uoslife.servermeeting.user.command.UserCommand
import uoslife.servermeeting.user.entity.QUser.user
import uoslife.servermeeting.user.entity.QUserInformation.userInformation
import uoslife.servermeeting.user.entity.User
Expand All @@ -27,36 +26,9 @@ class UserDao(
fun findUserProfile(userId: Long): User? {
return queryFactory
.selectFrom(user)
.join(userInformation)
.on(userInformation.user.eq(user))
.where(user.id.eq(userId))
.leftJoin(user.userInformation, userInformation)
.fetchJoin()
.where(user.id.eq(userId))
.fetchOne()
}

fun updateUserInformation(command: UserCommand.UpdateUserInformation): Long {

val jpaClause =
queryFactory.update(userInformation).where(userInformation.user.id.eq(command.userId))

command.smoking?.let { jpaClause.set(userInformation.smoking, it) }
command.mbti?.let { jpaClause.set(userInformation.mbti, it) }
command.interest?.let { jpaClause.set(userInformation.interest, it) }
command.height?.let { jpaClause.set(userInformation.height, it) }
command.age?.let { jpaClause.set(userInformation.age, it) }
command.studentNumber?.let { jpaClause.set(userInformation.studentNumber, it) }
command.department?.let { jpaClause.set(userInformation.department, it) }
command.eyelidType?.let { jpaClause.set(userInformation.eyelidType, it) }
command.appearanceType?.let { jpaClause.set(userInformation.appearanceType, it) }
return jpaClause.execute()
}

fun updateUserPersonalInformation(command: UserCommand.UpdateUserPersonalInformation): Long {
val jpaClause = queryFactory.update(user).where(user.id.eq(command.userId))
command.name?.let { jpaClause.set(user.name, it) }
command.phoneNumber?.let { jpaClause.set(user.phoneNumber, it) }
command.gender?.let { jpaClause.set(user.gender, it) }
command.kakaoTalkId?.let { jpaClause.set(user.kakaoTalkId, it) }
return jpaClause.execute()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ data class UserPersonalInformationUpdateRequest(
name = this.name,
phoneNumber = this.phoneNumber,
kakaoTalkId = this.kakaoTalkId,
gender = this.genderType,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema
import uoslife.servermeeting.user.entity.User
import uoslife.servermeeting.user.entity.enums.*

data class UserProfileResponse(
data class UserAllInformationResponse(
@Schema(description = "이름", example = "유현승") val name: String?,
@Schema(description = "성별", example = "MALE") val genderType: GenderType?,
@Schema(description = "나이", example = "26") val age: Int?,
Expand All @@ -22,8 +22,8 @@ data class UserProfileResponse(
@Schema(description = "학적", example = "UNDERGRADUATE") val studentType: StudentType?,
) {
companion object {
fun valueOf(user: User): UserProfileResponse {
return UserProfileResponse(
fun valueOf(user: User): UserAllInformationResponse {
return UserAllInformationResponse(
name = user.name,
genderType = user.gender,
phoneNumber = user.phoneNumber,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package uoslife.servermeeting.user.exception

import uoslife.servermeeting.global.error.exception.EntityNotFoundException
import uoslife.servermeeting.global.error.exception.ErrorCode

class UserInformationNotFoundException : EntityNotFoundException(ErrorCode.INFORMATION_NOT_FOUND)
47 changes: 41 additions & 6 deletions src/main/kotlin/uoslife/servermeeting/user/service/UserService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ import uoslife.servermeeting.user.command.UserCommand
import uoslife.servermeeting.user.dao.UserDao
import uoslife.servermeeting.user.dto.response.UserBranchResponse
import uoslife.servermeeting.user.entity.User
import uoslife.servermeeting.user.entity.UserInformation
import uoslife.servermeeting.user.exception.KakaoTalkIdDuplicationException
import uoslife.servermeeting.user.exception.UserInformationNotFoundException
import uoslife.servermeeting.user.exception.UserNotFoundException
import uoslife.servermeeting.user.repository.UserInformationRepository
import uoslife.servermeeting.user.repository.UserRepository

@Service
Expand All @@ -28,6 +31,7 @@ class UserService(
private val userRepository: UserRepository,
@Qualifier("portOneService") private val paymentService: PaymentService,
private val userTeamRepository: UserTeamRepository,
private val userInformationRepository: UserInformationRepository,
private val userDao: UserDao,
private val userTeamDao: UserTeamDao,
private val validator: Validator,
Expand All @@ -44,31 +48,34 @@ class UserService(

@Transactional
fun createUserByEmail(email: String): User {
return userRepository.save(User.create(email = email))
val user = userRepository.save(User.create(email = email))
val userInformation = userInformationRepository.save(UserInformation(user = user))
user.userInformation = userInformation
return user
}

fun getUser(userId: Long): User {
return userRepository.findByIdOrNull(userId) ?: throw UserNotFoundException()
}

fun getUserProfile(userId: Long): User {
fun getUserDetailedInformation(userId: Long): User {
return userDao.findUserProfile(userId) ?: throw UserNotFoundException()
}

@Transactional
fun updateUserInformation(command: UserCommand.UpdateUserInformation): User {
command.mbti = validator.setValidMBTI(command.mbti)
val updated: Long = userDao.updateUserInformation(command)
return userDao.findUserProfile(command.userId) ?: throw UserNotFoundException()
val user = userRepository.findByIdOrNull(command.userId) ?: throw UserNotFoundException()
return upsertUserInformation(user, command)
}

@Transactional
fun updateUserPersonalInformation(command: UserCommand.UpdateUserPersonalInformation): User {
if (command.kakaoTalkId != null) {
isDuplicatedKakaoTalkId(command.kakaoTalkId)
}
val updateUserPersonalInformation = userDao.updateUserPersonalInformation(command)
return userRepository.findByIdOrNull(command.userId) ?: throw UserNotFoundException()
val user = userRepository.findByIdOrNull(command.userId) ?: throw UserNotFoundException()
return updateUserProfile(user, command)
}

/**
Expand Down Expand Up @@ -126,6 +133,34 @@ class UserService(
return determineMeetingTeamStatus(userId, userTeams)
}

private fun upsertUserInformation(
user: User,
command: UserCommand.UpdateUserInformation
): User {
val information: UserInformation =
user.userInformation ?: throw UserInformationNotFoundException()

information.smoking = command.smoking ?: information.smoking
information.mbti = command.mbti ?: information.mbti
information.interest = command.interest ?: information.interest
information.height = command.height ?: information.height
information.age = command.age ?: information.age
information.studentNumber = command.studentNumber ?: information.studentNumber
information.department = command.department ?: information.department
information.eyelidType = command.eyelidType ?: information.eyelidType
information.appearanceType = command.appearanceType ?: information.appearanceType
return user
}

private fun updateUserProfile(
user: User,
command: UserCommand.UpdateUserPersonalInformation
): User {
user.name = command.name ?: user.name
user.phoneNumber = command.phoneNumber ?: user.phoneNumber
user.kakaoTalkId = command.kakaoTalkId ?: user.kakaoTalkId
return user
}
private fun determineMeetingTeamStatus(
userId: Long,
userTeams: List<UserTeam>
Expand Down
Loading

0 comments on commit dd68a9c

Please sign in to comment.