Skip to content

Commit

Permalink
Merge branch 'develop' into feat/#29
Browse files Browse the repository at this point in the history
  • Loading branch information
PgmJun authored Mar 18, 2024
2 parents 1ad9b1f + ae446d3 commit 30e4021
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.th.plu.api.controller.member

import com.th.plu.api.config.interceptor.Auth
import com.th.plu.api.config.resolver.MemberId
import com.th.plu.api.controller.member.dto.request.CheckNicknameRequestDto
import com.th.plu.api.controller.member.dto.request.UpdateNicknameRequestDto
import com.th.plu.api.controller.member.dto.response.CheckNicknameResponse
import com.th.plu.api.controller.member.dto.response.MyPageResponseDto
import com.th.plu.api.service.member.MemberService
import com.th.plu.common.dto.response.ApiResponse
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import org.springframework.web.bind.annotation.*

@Tag(name = "Member")
@RestController
class MemberController(
private val memberService: MemberService,
) {
@Operation(summary = "닉네임 중복 체크")
@PostMapping("/api/v1/member/nickname/dupl")
fun checkNicknameDuplication(@RequestBody request: CheckNicknameRequestDto): ApiResponse<CheckNicknameResponse> {
val response = memberService.checkNicknameDuplication(request)
return ApiResponse.success(response)
}

@Auth
@Operation(summary = "[인증] 닉네임 수정")
@PutMapping("/api/v1/member/{memberId}/nickname")
fun updateNickname(
@PathVariable memberId: Long,
@RequestBody request: UpdateNicknameRequestDto
): ApiResponse<Any> {
memberService.updateNickname(memberId, request.newNickname)
return ApiResponse.success()
}

@Auth
@Operation(summary = "[인증] 회원 탈퇴")
@DeleteMapping("/api/v1/member")
fun deleteMember(@MemberId memberId: Long): ApiResponse<Any> {
memberService.deleteMember(memberId)
return ApiResponse.success()
}

@Auth
@Operation(summary = "[인증] 마이페이지 조회")
@GetMapping("/api/v1/mypage")
fun getMyPageInfo(@MemberId memberId: Long): ApiResponse<MyPageResponseDto> {
val myPageInfo = memberService.getMyPageInfo(memberId)
return ApiResponse.success(data = myPageInfo)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.th.plu.api.controller.member.dto.request

data class CheckNicknameRequestDto(
val nickname: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.th.plu.api.controller.member.dto.request

data class UpdateNicknameRequestDto(
val newNickname: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.th.plu.api.controller.member.dto.response

data class CheckNicknameResponse(
val isAvailable: Boolean
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.th.plu.api.controller.member.dto.response

data class MyPageResponseDto(
val nickname: String,
val notificationStatus: Boolean
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ class AnswerService(
private val memberExplorer: MemberExplorer
) {
@Transactional(readOnly = true)
fun findAnswerInfoById(id: Long): AnswerInfoResponse {
val answer = answerExplorer.findAnswerById(id)
fun findAnswerInfoById(answerId: Long, memberId: Long): AnswerInfoResponse {
val answer = answerExplorer.findAnswerById(answerId)
if (!answer.isPublic) {
answerValidator.validateIsMemberOwnerOfAnswer(answerId, memberId)
}
val question = questionExplorer.findQuestionById(answer.getQuestionId())

return AnswerInfoResponse.of(answer.question, answer)
return AnswerInfoResponse.of(question, answer)
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.th.plu.api.service.answer

import com.th.plu.common.exception.code.ErrorCode
import com.th.plu.common.exception.model.ValidationException
import com.th.plu.domain.domain.answer.explorer.AnswerExplorer
import com.th.plu.domain.domain.answer.repository.AnswerRepository
import org.springframework.stereotype.Component

@Component
class AnswerValidator(
private val answerExplorer: AnswerExplorer,
private val answerRepository: AnswerRepository
) {
fun validateIsMemberOwnerOfAnswer(answerId: Long, memberId: Long) {
val answer = answerExplorer.findAnswerById(answerId)
if (answer.member.id != memberId) {
throw ValidationException(ErrorCode.INVALID_ANSWER_OWNER,
"멤버 (ID: ${memberId})는 답변 (ID: ${answerId})의 답변자가 아니기 때문에 답변 정보에 접근할 수 없습니다.")
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.th.plu.api.service.member

import com.th.plu.api.controller.member.dto.request.CheckNicknameRequestDto
import com.th.plu.api.controller.member.dto.request.CreateUserRequestDto
import com.th.plu.api.controller.member.dto.response.CheckNicknameResponse
import com.th.plu.api.controller.member.dto.response.MyPageResponseDto
import com.th.plu.domain.domain.member.Member
import com.th.plu.domain.domain.member.Onboarding
import com.th.plu.domain.domain.member.Setting
import com.th.plu.domain.domain.member.explorer.MemberExplorer
import com.th.plu.domain.domain.member.repository.MemberRepository
import com.th.plu.domain.domain.member.repository.OnboardingRepository
import com.th.plu.domain.domain.member.repository.SettingRepository
Expand All @@ -15,13 +19,15 @@ class MemberService(
private val memberValidator: MemberValidator,
private val memberRepository: MemberRepository,
private val onboardingRepository: OnboardingRepository,
private val settingRepository: SettingRepository
private val settingRepository: SettingRepository,
private val memberExplorer: MemberExplorer
) {

@Transactional
fun registerUser(request: CreateUserRequestDto): Long {
memberValidator.validateNotExistsMember(request.socialId, request.socialType)
// TODO: 닉네임 중복 체크 추가해야합니다.
memberValidator.validateDuplicatedNickname(request.nickname)

val member = memberRepository.save(
Member.newInstance(
socialId = request.socialId,
Expand All @@ -36,8 +42,43 @@ class MemberService(
nickname = request.nickname
)
)

member.initOnboarding(onboarding)
return member.id!!
}

@Transactional(readOnly = true)
fun checkNicknameDuplication(request: CheckNicknameRequestDto): CheckNicknameResponse {
val isAvailable = !memberRepository.existsByNickname(request.nickname)
return CheckNicknameResponse(isAvailable)
}

@Transactional
fun updateNickname(memberId: Long, newNickname: String) {
val member = memberExplorer.findMemberById(memberId)

memberValidator.validateDuplicatedNickname(newNickname)
memberValidator.validateOnboardingExists(member)

member.onboarding!!.nickname = newNickname

}

@Transactional
fun deleteMember(memberId: Long) {
val member = memberExplorer.findMemberById(memberId)
memberRepository.delete(member)
}

@Transactional(readOnly = true)
fun getMyPageInfo(memberId: Long): MyPageResponseDto {
val member = memberExplorer.findMemberById(memberId)
val onboarding = memberValidator.validateOnboardingExists(member)

return MyPageResponseDto(
nickname = onboarding.nickname,
notificationStatus = member.setting.notificationStatus
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package com.th.plu.api.service.member

import com.th.plu.common.exception.code.ErrorCode
import com.th.plu.common.exception.model.ConflictException
import com.th.plu.common.exception.model.IllegalArgumentException
import com.th.plu.common.exception.model.NotFoundException
import com.th.plu.domain.domain.member.Member
import com.th.plu.domain.domain.member.MemberSocialType
import com.th.plu.domain.domain.member.Onboarding
import com.th.plu.domain.domain.member.repository.MemberRepository
import org.springframework.stereotype.Component

Expand All @@ -15,4 +19,22 @@ class MemberValidator(
throw ConflictException(ErrorCode.CONFLICT_MEMBER_EXCEPTION, "이미 존재하는 유저 $socialId - $socialType 입니다")
}
}

fun validateDuplicatedNickname(nickname: String) {
if (memberRepository.existsByNickname(nickname)) {
throw ConflictException(ErrorCode.CONFLICT_NICKNAME_EXCEPTION, "이미 사용 중인 닉네임입니다.")
}
}

fun validateNullorBlankNickname(nickname: String?) {
if (nickname.isNullOrBlank()) {
throw IllegalArgumentException(ErrorCode.Illegal_ARGUMENT_NICKNAME_EXCEPTION, "닉네임은 비어 있을 수 없습니다.")
}
}

fun validateOnboardingExists(member: Member): Onboarding {
return member.onboarding
?: throw NotFoundException(ErrorCode.NOT_FOUND_ONBOARDING_EXCEPTION, "Onboarding 정보가 없는 유저 입니다")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ enum class ErrorCode(val code: String, val message: String) {
BIND_EXCEPTION("V005", "요청 값을 바인딩하는 과정에서 오류가 발생하였습니다."),
METHOD_ARGUMENT_NOT_VALID_EXCEPTION("V006", "요청 값이 검증되지 않은 값 입니다."),
INVALID_FORMAT_EXCEPTION("V007", "요청 값이 유효하지 않은 데이터입니다."),
INVALID_ANSWER_OWNER("V008", "질문의 소유자가 아닙니다."),

// Unauthorized Exception
UNAUTHORIZED_EXCEPTION("U001", "토큰이 만료되었습니다. 다시 로그인 해주세요."),
Expand All @@ -29,16 +30,21 @@ enum class ErrorCode(val code: String, val message: String) {
NOT_FOUND_ARTICLE_EXCEPTION("N005", "삭제되었거나 존재하지 않는 아티클입니다."),
NOT_FOUND_ARTICLE_IN_WEEK_AND_DAY_EXCEPTION("N006", "해당 주차 일차에 해당하는 아티클이 존재하지 않습니다."),
NOT_FOUND_ENDPOINT_EXCEPTION("N007", "존재하지 않는 엔드포인트입니다."),
NOT_FOUND_ONBOARDING_EXCEPTION("N007", "존재하지 않는 엔드포인트입니다."),

// Conflict Exception
CONFLICT_EXCEPTION("C001", "이미 존재합니다."),
CONFLICT_MEMBER_EXCEPTION("C002", "이미 해당 계정으로 회원가입하셨습니다.\n로그인 해주세요."),
CONFLICT_LIKE_EXCEPTION("C003", "이미 해당 답변에 대한 공감이 되어있습니다."),
CONFLICT_BOOKMARK_EXCEPTION("C003", "요청과 동일한 북마크 상태 입니다."),
CONFLICT_NICKNAME_EXCEPTION("C004", "이미 사용 중인 닉네임 입니다."),

// Internal Server Exception
INTERNAL_SERVER_EXCEPTION("I001", "서버 내부에서 에러가 발생하였습니다."),

// Bad Gateway Exception
BAD_GATEWAY_EXCEPTION("B001", "외부 연동 중 에러가 발생하였습니다."),

// Illegal Argument Exception
Illegal_ARGUMENT_NICKNAME_EXCEPTION("IA001", "잘못된 닉네임 형식입니다."),
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ interface MemberRepositoryCustom {
fun findMemberById(id: Long): Member?
fun findMemberBySocialIdAndSocialType(socialId: String, socialType: MemberSocialType): Member?
fun existBySocialIdAndSocialType(socialId: String, socialType: MemberSocialType): Boolean
fun existsByNickname(nickname: String): Boolean

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,40 @@ import com.querydsl.jpa.impl.JPAQueryFactory
import com.th.plu.domain.domain.member.Member
import com.th.plu.domain.domain.member.MemberSocialType
import com.th.plu.domain.domain.member.QMember.member
import com.th.plu.domain.domain.member.QOnboarding.onboarding
import org.springframework.stereotype.Repository

@Repository
class MemberRepositoryImpl(private val queryFactory: JPAQueryFactory) : MemberRepositoryCustom {
override fun findMemberById(id: Long): Member? {
return queryFactory
.selectFrom(member)
.where(member.id.eq(id))
.fetchOne()
.selectFrom(member)
.where(member.id.eq(id))
.fetchOne()
}

override fun findMemberBySocialIdAndSocialType(socialId: String, socialType: MemberSocialType): Member? {
return queryFactory
.selectFrom(member)
.where(
member.socialId.eq(socialId),
member.socialType.eq(socialType)
).fetchOne()
.selectFrom(member)
.where(
member.socialId.eq(socialId),
member.socialType.eq(socialType)
).fetchOne()
}

override fun existBySocialIdAndSocialType(socialId: String, socialType: MemberSocialType): Boolean {
return queryFactory
.selectFrom(member)
.where(
member.socialId.eq(socialId),
member.socialType.eq(socialType)
).fetchOne() != null
.selectFrom(member)
.where(
member.socialId.eq(socialId),
member.socialType.eq(socialType)
).fetchOne() != null
}

override fun existsByNickname(nickname: String): Boolean {
return queryFactory
.selectFrom(onboarding)
.where(onboarding.nickname.eq(nickname))
.fetchOne() != null
}
}
2 changes: 1 addition & 1 deletion scripts/plu-api/switch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ else
exit 1
fi

echo "set \$service_url http://127.0.0.1:${TARGET_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc
echo "set \$service_url http://127.0.0.1:${TARGET_PORT};" >> /home/ubuntu/plu-api/deploy.log | sudo tee /etc/nginx/conf.d/service-url.inc

echo "[$NOW_TIME] Now Nginx proxies to ${TARGET_PORT}." >> /home/ubuntu/plu-api/deploy.log
sudo service nginx reload
Expand Down

0 comments on commit 30e4021

Please sign in to comment.