230 lines
9.6 KiB
Kotlin
230 lines
9.6 KiB
Kotlin
package kr.co.vividnext.sodalive.member
|
|
|
|
import com.amazonaws.services.s3.model.ObjectMetadata
|
|
import com.fasterxml.jackson.databind.ObjectMapper
|
|
import kr.co.vividnext.sodalive.aws.s3.S3Uploader
|
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
|
import kr.co.vividnext.sodalive.common.SodaException
|
|
import kr.co.vividnext.sodalive.jwt.TokenProvider
|
|
import kr.co.vividnext.sodalive.member.info.GetMemberInfoResponse
|
|
import kr.co.vividnext.sodalive.member.login.LoginRequest
|
|
import kr.co.vividnext.sodalive.member.login.LoginResponse
|
|
import kr.co.vividnext.sodalive.member.notification.MemberNotificationService
|
|
import kr.co.vividnext.sodalive.member.notification.UpdateNotificationSettingRequest
|
|
import kr.co.vividnext.sodalive.member.signUp.SignUpRequest
|
|
import kr.co.vividnext.sodalive.member.stipulation.Stipulation
|
|
import kr.co.vividnext.sodalive.member.stipulation.StipulationAgree
|
|
import kr.co.vividnext.sodalive.member.stipulation.StipulationAgreeRepository
|
|
import kr.co.vividnext.sodalive.member.stipulation.StipulationIds
|
|
import kr.co.vividnext.sodalive.member.stipulation.StipulationRepository
|
|
import kr.co.vividnext.sodalive.utils.generateFileName
|
|
import org.springframework.beans.factory.annotation.Value
|
|
import org.springframework.data.repository.findByIdOrNull
|
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
|
|
import org.springframework.security.core.context.SecurityContextHolder
|
|
import org.springframework.security.core.userdetails.UserDetails
|
|
import org.springframework.security.core.userdetails.UserDetailsService
|
|
import org.springframework.security.core.userdetails.UsernameNotFoundException
|
|
import org.springframework.security.crypto.password.PasswordEncoder
|
|
import org.springframework.stereotype.Service
|
|
import org.springframework.transaction.annotation.Transactional
|
|
import org.springframework.web.multipart.MultipartFile
|
|
|
|
@Service
|
|
@Transactional(readOnly = true)
|
|
class MemberService(
|
|
private val repository: MemberRepository,
|
|
private val stipulationRepository: StipulationRepository,
|
|
private val stipulationAgreeRepository: StipulationAgreeRepository,
|
|
|
|
private val memberNotificationService: MemberNotificationService,
|
|
|
|
private val s3Uploader: S3Uploader,
|
|
private val validator: SignUpValidator,
|
|
private val tokenProvider: TokenProvider,
|
|
private val passwordEncoder: PasswordEncoder,
|
|
private val authenticationManagerBuilder: AuthenticationManagerBuilder,
|
|
|
|
private val objectMapper: ObjectMapper,
|
|
|
|
@Value("\${cloud.aws.s3.bucket}")
|
|
private val s3Bucket: String
|
|
) : UserDetailsService {
|
|
@Transactional
|
|
fun signUp(
|
|
profileImage: MultipartFile?,
|
|
requestString: String
|
|
): ApiResponse<LoginResponse> {
|
|
val stipulationTermsOfService = stipulationRepository.findByIdOrNull(StipulationIds.TERMS_OF_SERVICE_ID)
|
|
?: throw SodaException("잘못된 요청입니다\n앱 종료 후 다시 시도해 주세요.")
|
|
|
|
val stipulationPrivacyPolicy = stipulationRepository.findByIdOrNull(StipulationIds.PRIVACY_POLICY_ID)
|
|
?: throw SodaException("잘못된 요청입니다\n앱 종료 후 다시 시도해 주세요.")
|
|
|
|
val request = objectMapper.readValue(requestString, SignUpRequest::class.java)
|
|
if (!request.isAgreePrivacyPolicy || !request.isAgreeTermsOfService) {
|
|
throw SodaException("약관에 동의하셔야 회원가입이 가능합니다.")
|
|
}
|
|
|
|
validatePassword(request.password)
|
|
duplicateCheckEmail(request.email)
|
|
duplicateCheckNickname(request.nickname)
|
|
|
|
val member = createMember(request)
|
|
member.profileImage = uploadProfileImage(profileImage = profileImage, memberId = member.id!!)
|
|
agreeTermsOfServiceAndPrivacyPolicy(member, stipulationTermsOfService, stipulationPrivacyPolicy)
|
|
|
|
return ApiResponse.ok(message = "회원가입을 축하드립니다.", data = login(request.email, request.password))
|
|
}
|
|
|
|
fun login(request: LoginRequest): ApiResponse<LoginResponse> {
|
|
return ApiResponse.ok(
|
|
message = "로그인 되었습니다.",
|
|
data = login(request.email, request.password, request.isAdmin, request.isCreator)
|
|
)
|
|
}
|
|
|
|
fun getMemberInfo(member: Member, container: String): GetMemberInfoResponse {
|
|
return GetMemberInfoResponse(
|
|
can = member.getChargeCan(container) + member.getRewardCan(container),
|
|
isAuth = member.auth != null,
|
|
role = member.role,
|
|
messageNotice = member.notification?.message,
|
|
followingChannelLiveNotice = member.notification?.live,
|
|
followingChannelUploadContentNotice = member.notification?.uploadContent
|
|
)
|
|
}
|
|
|
|
@Transactional
|
|
fun updateNotificationSettings(request: UpdateNotificationSettingRequest, member: Member) {
|
|
memberNotificationService.updateNotification(
|
|
live = request.live,
|
|
uploadContent = request.uploadContent,
|
|
message = request.message,
|
|
member = member
|
|
)
|
|
}
|
|
|
|
private fun login(
|
|
email: String,
|
|
password: String,
|
|
isAdmin: Boolean = false,
|
|
isCreator: Boolean = false
|
|
): LoginResponse {
|
|
val member = repository.findByEmail(email = email) ?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
if (!member.isActive) {
|
|
throw SodaException("탈퇴한 계정입니다.\n고객센터로 문의해 주시기 바랍니다.")
|
|
}
|
|
|
|
if (isCreator && member.role != MemberRole.CREATOR) {
|
|
throw SodaException("로그인 정보를 확인해주세요.")
|
|
}
|
|
|
|
if (isAdmin && member.role != MemberRole.ADMIN) {
|
|
throw SodaException("로그인 정보를 확인해주세요.")
|
|
}
|
|
|
|
val authenticationToken = UsernamePasswordAuthenticationToken(email, password)
|
|
val authentication = authenticationManagerBuilder.`object`.authenticate(authenticationToken)
|
|
SecurityContextHolder.getContext().authentication = authentication
|
|
|
|
val jwt = tokenProvider.createToken(
|
|
authentication = authentication,
|
|
memberId = member.id!!
|
|
)
|
|
|
|
return LoginResponse(
|
|
userId = member.id!!,
|
|
token = jwt,
|
|
nickname = member.nickname,
|
|
email = member.email,
|
|
profileImage = member.profileImage ?: ""
|
|
)
|
|
}
|
|
|
|
private fun uploadProfileImage(profileImage: MultipartFile?, memberId: Long): String {
|
|
return if (profileImage != null) {
|
|
val metadata = ObjectMetadata()
|
|
metadata.contentLength = profileImage.size
|
|
|
|
s3Uploader.upload(
|
|
inputStream = profileImage.inputStream,
|
|
bucket = s3Bucket,
|
|
filePath = "profile/$memberId/${generateFileName(prefix = "$memberId-profile")}",
|
|
metadata = metadata
|
|
)
|
|
} else {
|
|
"profile/default-profile.png"
|
|
}
|
|
}
|
|
|
|
private fun agreeTermsOfServiceAndPrivacyPolicy(
|
|
member: Member,
|
|
stipulationTermsOfService: Stipulation,
|
|
stipulationPrivacyPolicy: Stipulation
|
|
) {
|
|
val termsOfServiceAgree = StipulationAgree(true)
|
|
termsOfServiceAgree.member = member
|
|
termsOfServiceAgree.stipulation = stipulationTermsOfService
|
|
stipulationAgreeRepository.save(termsOfServiceAgree)
|
|
|
|
val privacyPolicyAgree = StipulationAgree(true)
|
|
privacyPolicyAgree.member = member
|
|
privacyPolicyAgree.stipulation = stipulationPrivacyPolicy
|
|
stipulationAgreeRepository.save(privacyPolicyAgree)
|
|
}
|
|
|
|
private fun createMember(request: SignUpRequest): Member {
|
|
val member = Member(
|
|
email = request.email,
|
|
password = passwordEncoder.encode(request.password),
|
|
nickname = request.nickname,
|
|
gender = request.gender,
|
|
container = request.container
|
|
)
|
|
|
|
return repository.save(member)
|
|
}
|
|
|
|
private fun validatePassword(password: String) {
|
|
val passwordValidationMessage = validator.passwordValidation(password)
|
|
if (passwordValidationMessage.trim().isNotEmpty()) {
|
|
throw SodaException(passwordValidationMessage)
|
|
}
|
|
}
|
|
|
|
fun duplicateCheckEmail(email: String): ApiResponse<Any> {
|
|
validateEmail(email)
|
|
repository.findByEmail(email)?.let { throw SodaException("이미 사용중인 이메일 입니다.", "email") }
|
|
return ApiResponse.ok(message = "사용 가능한 이메일 입니다.")
|
|
}
|
|
|
|
private fun validateEmail(email: String) {
|
|
val emailValidationMessage = validator.emailValidation(email)
|
|
if (emailValidationMessage.trim().isNotEmpty()) {
|
|
throw SodaException(emailValidationMessage, "email")
|
|
}
|
|
}
|
|
|
|
fun duplicateCheckNickname(nickname: String): ApiResponse<Any> {
|
|
validateNickname(nickname)
|
|
repository.findByNickname(nickname)?.let { throw SodaException("이미 사용중인 닉네임 입니다.", "nickname") }
|
|
return ApiResponse.ok(message = "사용 가능한 닉네임 입니다.")
|
|
}
|
|
|
|
private fun validateNickname(nickname: String) {
|
|
val nicknameValidationMessage = validator.nicknameValidation(nickname)
|
|
if (nicknameValidationMessage.trim().isNotEmpty()) {
|
|
throw SodaException(nicknameValidationMessage, "nickname")
|
|
}
|
|
}
|
|
|
|
override fun loadUserByUsername(username: String): UserDetails {
|
|
val member = repository.findByEmail(email = username)
|
|
?: throw UsernameNotFoundException(username)
|
|
|
|
return MemberAdapter(member)
|
|
}
|
|
}
|