740 lines
29 KiB
Kotlin
740 lines
29 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.can.charge.ChargeRepository
|
|
import kr.co.vividnext.sodalive.can.payment.CanPaymentService
|
|
import kr.co.vividnext.sodalive.can.use.CanUsage
|
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
|
import kr.co.vividnext.sodalive.common.SodaException
|
|
import kr.co.vividnext.sodalive.content.order.OrderService
|
|
import kr.co.vividnext.sodalive.email.SendEmailService
|
|
import kr.co.vividnext.sodalive.jwt.TokenProvider
|
|
import kr.co.vividnext.sodalive.live.reservation.LiveReservationRepository
|
|
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser
|
|
import kr.co.vividnext.sodalive.member.block.BlockMember
|
|
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
|
import kr.co.vividnext.sodalive.member.block.GetBlockedMemberListResponse
|
|
import kr.co.vividnext.sodalive.member.block.MemberBlockRequest
|
|
import kr.co.vividnext.sodalive.member.following.CreatorFollowing
|
|
import kr.co.vividnext.sodalive.member.following.CreatorFollowingRepository
|
|
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.myPage.MyPageResponse
|
|
import kr.co.vividnext.sodalive.member.nickname.NicknameChangeLog
|
|
import kr.co.vividnext.sodalive.member.nickname.NicknameChangeLogRepository
|
|
import kr.co.vividnext.sodalive.member.nickname.NicknameGenerateService
|
|
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.signUp.SignUpRequestV2
|
|
import kr.co.vividnext.sodalive.member.signUp.SignUpResponse
|
|
import kr.co.vividnext.sodalive.member.signUp.SignUpValidator
|
|
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.member.tag.MemberCreatorTag
|
|
import kr.co.vividnext.sodalive.member.tag.MemberTagRepository
|
|
import kr.co.vividnext.sodalive.member.token.MemberTokenRepository
|
|
import kr.co.vividnext.sodalive.utils.generateFileName
|
|
import kr.co.vividnext.sodalive.utils.generatePassword
|
|
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.User
|
|
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
|
|
import java.time.LocalDateTime
|
|
import java.time.ZoneId
|
|
import java.time.format.DateTimeFormatter
|
|
import java.util.concurrent.locks.ReentrantReadWriteLock
|
|
import kotlin.concurrent.write
|
|
|
|
@Service
|
|
@Transactional(readOnly = true)
|
|
class MemberService(
|
|
private val repository: MemberRepository,
|
|
private val tokenRepository: MemberTokenRepository,
|
|
private val stipulationRepository: StipulationRepository,
|
|
private val stipulationAgreeRepository: StipulationAgreeRepository,
|
|
private val creatorFollowingRepository: CreatorFollowingRepository,
|
|
private val blockMemberRepository: BlockMemberRepository,
|
|
private val signOutRepository: SignOutRepository,
|
|
private val nicknameChangeLogRepository: NicknameChangeLogRepository,
|
|
private val memberTagRepository: MemberTagRepository,
|
|
private val liveReservationRepository: LiveReservationRepository,
|
|
private val chargeRepository: ChargeRepository,
|
|
|
|
private val orderService: OrderService,
|
|
private val emailService: SendEmailService,
|
|
private val canPaymentService: CanPaymentService,
|
|
private val nicknameGenerateService: NicknameGenerateService,
|
|
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,
|
|
|
|
@Value("\${cloud.aws.cloud-front.host}")
|
|
private val cloudFrontHost: String
|
|
) : UserDetailsService {
|
|
|
|
private val tokenLocks: MutableMap<Long, ReentrantReadWriteLock> = mutableMapOf()
|
|
|
|
@Transactional
|
|
fun signUpV2(request: SignUpRequestV2): SignUpResponse {
|
|
val stipulationTermsOfService = stipulationRepository.findByIdOrNull(StipulationIds.TERMS_OF_SERVICE_ID)
|
|
?: throw SodaException("잘못된 요청입니다\n앱 종료 후 다시 시도해 주세요.")
|
|
|
|
val stipulationPrivacyPolicy = stipulationRepository.findByIdOrNull(StipulationIds.PRIVACY_POLICY_ID)
|
|
?: throw SodaException("잘못된 요청입니다\n앱 종료 후 다시 시도해 주세요.")
|
|
|
|
if (!request.isAgreePrivacyPolicy || !request.isAgreeTermsOfService) {
|
|
throw SodaException("약관에 동의하셔야 회원가입이 가능합니다.")
|
|
}
|
|
|
|
duplicateCheckEmail(request.email)
|
|
validatePassword(request.password)
|
|
|
|
val nickname = nicknameGenerateService.generateUniqueNickname()
|
|
val member = Member(
|
|
email = request.email,
|
|
password = passwordEncoder.encode(request.password),
|
|
nickname = nickname,
|
|
profileImage = "profile/default-profile.png",
|
|
gender = Gender.NONE,
|
|
container = request.container
|
|
)
|
|
|
|
if (!request.marketingPid.isNullOrBlank()) {
|
|
member.activePid = request.marketingPid
|
|
member.partnerExpirationDatetime = LocalDateTime.now().plusYears(1)
|
|
}
|
|
|
|
repository.save(member)
|
|
agreeTermsOfServiceAndPrivacyPolicy(member, stipulationTermsOfService, stipulationPrivacyPolicy)
|
|
|
|
return SignUpResponse(
|
|
memberId = member.id!!,
|
|
marketingPid = request.marketingPid,
|
|
loginResponse = login(request.email, request.password)
|
|
)
|
|
}
|
|
|
|
@Transactional
|
|
fun signUp(
|
|
profileImage: MultipartFile?,
|
|
requestString: String
|
|
): SignUpResponse {
|
|
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 SignUpResponse(
|
|
memberId = member.id!!,
|
|
marketingPid = request.marketingPid,
|
|
loginResponse = 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 getMember(id: Long, container: String): ProfileResponse {
|
|
val member = repository.findByIdOrNull(id)
|
|
?: throw SodaException("없는 사용자 입니다.")
|
|
|
|
return ProfileResponse(member, cloudFrontHost, container)
|
|
}
|
|
|
|
fun getMemberInfo(member: Member, container: String): GetMemberInfoResponse {
|
|
val gender = if (member.auth != null) {
|
|
if (member.auth!!.gender == 1) {
|
|
"남"
|
|
} else {
|
|
"여"
|
|
}
|
|
} else {
|
|
null
|
|
}
|
|
|
|
val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
|
val signUpDate = member.createdAt!!
|
|
.atZone(ZoneId.of("UTC"))
|
|
.withZoneSameInstant(ZoneId.of("Asia/Seoul"))
|
|
.format(dateTimeFormatter)
|
|
|
|
val chargeCount = chargeRepository.getChargeCount(memberId = member.id!!)
|
|
|
|
return GetMemberInfoResponse(
|
|
can = member.getChargeCan(container) + member.getRewardCan(container),
|
|
isAuth = member.auth != null,
|
|
gender = gender,
|
|
signupDate = signUpDate,
|
|
chargeCount = chargeCount,
|
|
role = member.role,
|
|
messageNotice = member.notification?.message,
|
|
followingChannelLiveNotice = member.notification?.live,
|
|
followingChannelUploadContentNotice = member.notification?.uploadContent,
|
|
auditionNotice = member.notification?.audition
|
|
)
|
|
}
|
|
|
|
@Transactional
|
|
fun updateNotificationSettings(request: UpdateNotificationSettingRequest, member: Member) {
|
|
memberNotificationService.updateNotification(
|
|
live = request.live,
|
|
uploadContent = request.uploadContent,
|
|
message = request.message,
|
|
audition = request.audition,
|
|
member = member
|
|
)
|
|
}
|
|
|
|
@Transactional
|
|
fun updatePushToken(memberId: Long, pushToken: String, container: String) {
|
|
val existsHavePushTokenMemberList = repository.findByPushToken(pushToken = pushToken)
|
|
for (existsHavePushTokenMember in existsHavePushTokenMemberList) {
|
|
existsHavePushTokenMember.pushToken = null
|
|
}
|
|
|
|
val member = repository.findByIdOrNull(id = memberId)
|
|
?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
|
|
member.pushToken = pushToken
|
|
member.container = container
|
|
}
|
|
|
|
@Transactional
|
|
fun updateAdid(memberId: Long, adid: String) {
|
|
val member = repository.findByIdOrNull(id = memberId)
|
|
?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
|
|
member.adid = adid
|
|
}
|
|
|
|
fun getMyPage(member: Member, container: String): MyPageResponse {
|
|
val liveReservationCount = liveReservationRepository.getReservationCount(memberId = member.id!!)
|
|
|
|
val orderList = orderService.getAudioContentOrderList(
|
|
member = member,
|
|
offset = 0,
|
|
limit = 4
|
|
)
|
|
|
|
return MyPageResponse(
|
|
nickname = member.nickname,
|
|
profileUrl = if (member.profileImage != null) {
|
|
"$cloudFrontHost/${member.profileImage}"
|
|
} else {
|
|
"$cloudFrontHost/profile/default-profile.png"
|
|
},
|
|
chargeCan = member.getChargeCan(container = container),
|
|
rewardCan = member.getRewardCan(container = container),
|
|
youtubeUrl = member.youtubeUrl,
|
|
instagramUrl = member.instagramUrl,
|
|
websiteUrl = member.websiteUrl,
|
|
blogUrl = member.blogUrl,
|
|
liveReservationCount = liveReservationCount,
|
|
isAuth = member.auth != null,
|
|
orderList = orderList
|
|
)
|
|
}
|
|
|
|
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 = if (member.profileImage != null) {
|
|
"$cloudFrontHost/${member.profileImage}"
|
|
} else {
|
|
"$cloudFrontHost/profile/default-profile.png"
|
|
}
|
|
)
|
|
}
|
|
|
|
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
|
|
)
|
|
|
|
if (!request.marketingPid.isNullOrBlank()) {
|
|
member.activePid = request.marketingPid
|
|
member.partnerExpirationDatetime = LocalDateTime.now().plusYears(1)
|
|
}
|
|
|
|
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)
|
|
|
|
if (repository.existsByEmail(email)) {
|
|
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)
|
|
}
|
|
|
|
@Transactional
|
|
fun creatorFollow(creatorId: Long, isNotify: Boolean, isActive: Boolean, memberId: Long) {
|
|
val creatorFollowing = creatorFollowingRepository.findByCreatorIdAndMemberId(
|
|
creatorId = creatorId,
|
|
memberId = memberId
|
|
)
|
|
|
|
if (creatorFollowing == null) {
|
|
val creator = repository.findByIdOrNull(creatorId) ?: throw SodaException("크리에이터 정보를 확인해주세요.")
|
|
val member = repository.findByIdOrNull(memberId) ?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
|
|
val newCreatorFollowing = CreatorFollowing()
|
|
newCreatorFollowing.member = member
|
|
newCreatorFollowing.creator = creator
|
|
creatorFollowingRepository.save(newCreatorFollowing)
|
|
} else {
|
|
creatorFollowing.isNotify = isNotify && isActive
|
|
creatorFollowing.isActive = isActive
|
|
}
|
|
}
|
|
|
|
@Transactional
|
|
fun creatorUnFollow(creatorId: Long, memberId: Long) {
|
|
val creatorFollowing = creatorFollowingRepository.findByCreatorIdAndMemberId(
|
|
creatorId = creatorId,
|
|
memberId = memberId
|
|
)
|
|
|
|
if (creatorFollowing != null) {
|
|
creatorFollowing.isActive = false
|
|
}
|
|
}
|
|
|
|
fun getBlockedMemberIdList(memberId: Long): List<Long> {
|
|
return blockMemberRepository.getBlockedMemberIdList(memberId)
|
|
}
|
|
|
|
fun getBlockedMemberList(memberId: Long, offset: Long, limit: Long): GetBlockedMemberListResponse {
|
|
val totalCount = blockMemberRepository.getBlockedMemberTotalCount(memberId)
|
|
val items = blockMemberRepository.getBlockedMemberList(offset = offset, limit = limit, memberId = memberId)
|
|
|
|
return GetBlockedMemberListResponse(totalCount = totalCount, items = items)
|
|
}
|
|
|
|
@Transactional
|
|
fun memberBlock(request: MemberBlockRequest, memberId: Long) {
|
|
var blockMember = blockMemberRepository.getBlockAccount(
|
|
blockedMemberId = request.blockMemberId,
|
|
memberId = memberId
|
|
)
|
|
|
|
if (blockMember == null) {
|
|
val blockedMember = repository.findByIdOrNull(id = request.blockMemberId)
|
|
?: throw SodaException("잘못된 요청입니다.")
|
|
|
|
val member = repository.findByIdOrNull(id = memberId)
|
|
?: throw SodaException("잘못된 요청입니다.")
|
|
|
|
blockMember = BlockMember()
|
|
blockMember.member = member
|
|
blockMember.blockedMember = blockedMember
|
|
|
|
blockMemberRepository.save(blockMember)
|
|
} else {
|
|
blockMember.isActive = true
|
|
}
|
|
}
|
|
|
|
@Transactional
|
|
fun memberUnBlock(request: MemberBlockRequest, memberId: Long) {
|
|
val blockMember = blockMemberRepository.getBlockAccount(
|
|
blockedMemberId = request.blockMemberId,
|
|
memberId = memberId
|
|
)
|
|
|
|
if (blockMember != null) {
|
|
blockMember.isActive = false
|
|
}
|
|
}
|
|
|
|
fun isBlocked(blockedMemberId: Long, memberId: Long) = blockMemberRepository.isBlocked(blockedMemberId, memberId)
|
|
|
|
fun searchMember(nickname: String, member: Member): List<GetRoomDetailUser> {
|
|
if (nickname.length < 2) {
|
|
throw SodaException("두 글자 이상 입력 하셔야 합니다.")
|
|
}
|
|
|
|
return repository.findByNicknameAndOtherCondition(nickname, member)
|
|
.asSequence()
|
|
.filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.id!!) }
|
|
.map {
|
|
GetRoomDetailUser(it, cloudFrontHost)
|
|
}
|
|
.toList()
|
|
}
|
|
|
|
@Transactional
|
|
fun logout(token: String, memberId: Long) {
|
|
val member = repository.findByIdOrNull(memberId)
|
|
?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
|
|
member.pushToken = null
|
|
|
|
val lock = getOrCreateLock(memberId = memberId)
|
|
lock.write {
|
|
val memberToken = tokenRepository.findByIdOrNull(memberId)
|
|
?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
|
|
memberToken.tokenSet.remove(token)
|
|
tokenRepository.save(memberToken)
|
|
}
|
|
}
|
|
|
|
@Transactional
|
|
fun logoutAll(memberId: Long) {
|
|
val member = repository.findByIdOrNull(memberId)
|
|
?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
|
|
member.pushToken = null
|
|
|
|
val lock = getOrCreateLock(memberId = memberId)
|
|
lock.write { tokenRepository.deleteById(memberId) }
|
|
}
|
|
|
|
@Transactional
|
|
fun signOut(signOutRequest: SignOutRequest, user: User) {
|
|
val member = repository.findByEmail(user.username) ?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
if (!passwordEncoder.matches(signOutRequest.password, member.password)) {
|
|
throw SodaException("비밀번호가 일치하지 않습니다.")
|
|
}
|
|
|
|
if (signOutRequest.reason.isBlank()) {
|
|
throw SodaException("탈퇴하려는 이유를 입력해 주세요.")
|
|
}
|
|
|
|
logoutAll(memberId = member.id!!)
|
|
member.isActive = false
|
|
member.nickname = "deleted_${member.nickname}"
|
|
|
|
val signOut = SignOut(reason = signOutRequest.reason)
|
|
signOut.member = member
|
|
signOutRepository.save(signOut)
|
|
}
|
|
|
|
fun getChangeNicknamePrice(memberId: Long): GetChangeNicknamePriceResponse {
|
|
return repository.getChangeNicknamePrice(memberId = memberId)
|
|
}
|
|
|
|
@Transactional
|
|
fun updateNickname(profileUpdateRequest: ProfileUpdateRequest, user: User) {
|
|
if (profileUpdateRequest.email != user.username) {
|
|
throw SodaException("로그인 정보를 확인해 주세요.")
|
|
}
|
|
|
|
val member = repository.findByEmail(user.username) ?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
|
|
if (profileUpdateRequest.nickname != null) {
|
|
validateNickname(profileUpdateRequest.nickname)
|
|
repository.findByNickname(profileUpdateRequest.nickname)
|
|
?.let { throw SodaException("이미 사용중인 닉네임 입니다.") }
|
|
|
|
val price = repository.getChangeNicknamePrice(memberId = member.id!!).price
|
|
if (price > 0) {
|
|
canPaymentService.spendCan(
|
|
memberId = member.id!!,
|
|
needCan = price,
|
|
canUsage = CanUsage.CHANGE_NICKNAME,
|
|
container = profileUpdateRequest.container
|
|
)
|
|
}
|
|
|
|
val nicknameChangeLog = NicknameChangeLog(prevNickname = member.nickname)
|
|
nicknameChangeLog.member = member
|
|
nicknameChangeLogRepository.save(nicknameChangeLog)
|
|
|
|
member.nickname = profileUpdateRequest.nickname
|
|
}
|
|
}
|
|
|
|
@Transactional
|
|
fun profileUpdate(profileUpdateRequest: ProfileUpdateRequest, user: User): ProfileResponse {
|
|
if (profileUpdateRequest.email != user.username) {
|
|
throw SodaException("로그인 정보를 확인해 주세요.")
|
|
}
|
|
|
|
val member = repository.findByEmail(user.username) ?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
|
|
if (profileUpdateRequest.modifyPassword != null) {
|
|
if (passwordEncoder.matches(profileUpdateRequest.password, member.password)) {
|
|
validatePassword(profileUpdateRequest.modifyPassword)
|
|
member.password = passwordEncoder.encode(profileUpdateRequest.modifyPassword)
|
|
} else {
|
|
throw SodaException("비밀번호가 일치하지 않습니다.")
|
|
}
|
|
}
|
|
|
|
if (profileUpdateRequest.gender != null) {
|
|
member.gender = profileUpdateRequest.gender
|
|
}
|
|
|
|
if (profileUpdateRequest.nickname != null) {
|
|
validateNickname(profileUpdateRequest.nickname)
|
|
repository.findByNickname(profileUpdateRequest.nickname)
|
|
?.let { throw SodaException("이미 사용중인 닉네임 입니다.") }
|
|
member.nickname = profileUpdateRequest.nickname
|
|
}
|
|
|
|
val tags = if (!profileUpdateRequest.removeTags.isNullOrEmpty()) {
|
|
member.tags.filter { !profileUpdateRequest.removeTags.contains(it.tag.tag) }
|
|
} else {
|
|
member.tags
|
|
}.toMutableList()
|
|
|
|
if (!profileUpdateRequest.insertTags.isNullOrEmpty()) {
|
|
val accountCounselorTags = memberTagRepository.findByMember(member).map { it.tag }
|
|
profileUpdateRequest.insertTags.forEach {
|
|
val tag = memberTagRepository.findByTag(it)
|
|
if (tag != null && !accountCounselorTags.contains(tag)) {
|
|
tags.add(MemberCreatorTag(member, tag))
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tags != member.tags) {
|
|
member.tags.clear()
|
|
member.tags.addAll(tags)
|
|
}
|
|
|
|
if (profileUpdateRequest.introduce != null) {
|
|
member.introduce = profileUpdateRequest.introduce
|
|
}
|
|
|
|
if (profileUpdateRequest.youtubeUrl != null) {
|
|
member.youtubeUrl = profileUpdateRequest.youtubeUrl
|
|
}
|
|
|
|
if (profileUpdateRequest.instagramUrl != null) {
|
|
member.instagramUrl = profileUpdateRequest.instagramUrl
|
|
}
|
|
|
|
if (profileUpdateRequest.websiteUrl != null) {
|
|
member.websiteUrl = profileUpdateRequest.websiteUrl
|
|
}
|
|
|
|
if (profileUpdateRequest.blogUrl != null) {
|
|
member.blogUrl = profileUpdateRequest.blogUrl
|
|
}
|
|
|
|
if (profileUpdateRequest.isVisibleDonationRank != null) {
|
|
member.isVisibleDonationRank = profileUpdateRequest.isVisibleDonationRank
|
|
}
|
|
|
|
return ProfileResponse(member, cloudFrontHost, profileUpdateRequest.container)
|
|
}
|
|
|
|
@Transactional
|
|
fun profileImageUpdate(multipartFile: MultipartFile, user: User): String {
|
|
val member = repository.findByEmail(user.username) ?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
|
|
val metadata = ObjectMetadata()
|
|
metadata.contentLength = multipartFile.size
|
|
|
|
member.profileImage = s3Uploader.upload(
|
|
inputStream = multipartFile.inputStream,
|
|
bucket = s3Bucket,
|
|
filePath = "profile/${member.id}/${generateFileName(prefix = "${member.id}-profile")}",
|
|
metadata = metadata
|
|
)
|
|
|
|
return "$cloudFrontHost/${member.profileImage!!}"
|
|
}
|
|
|
|
@Transactional
|
|
fun forgotPassword(request: ForgotPasswordRequest) {
|
|
val member = repository.getMemberByEmail(email = request.email)
|
|
?: throw SodaException("등록되지 않은 계정입니다.\n확인 후 다시 시도해 주세요.")
|
|
|
|
val password = generatePassword(12)
|
|
member.password = passwordEncoder.encode(password)
|
|
|
|
val date = LocalDateTime.now()
|
|
.atZone(ZoneId.of("UTC"))
|
|
.withZoneSameInstant(ZoneId.of("Asia/Seoul"))
|
|
.format(DateTimeFormatter.ofPattern("yyyy년 MM월 dd일, HH:mm"))
|
|
|
|
val data = HashMap<String, String>()
|
|
data["password"] = password
|
|
data["date"] = date
|
|
|
|
val templateData = objectMapper.writeValueAsString(data)
|
|
|
|
emailService.sendTemplatedEmail(
|
|
template = "sodalive-find-password",
|
|
templateData = templateData,
|
|
receiver = request.email
|
|
)
|
|
}
|
|
|
|
fun getMemberProfile(memberId: Long, myMemberId: Long): GetMemberProfileResponse {
|
|
return repository.getMemberProfile(memberId, myMemberId)
|
|
}
|
|
|
|
private fun getOrCreateLock(memberId: Long): ReentrantReadWriteLock {
|
|
return tokenLocks.computeIfAbsent(memberId) { ReentrantReadWriteLock() }
|
|
}
|
|
|
|
@Transactional
|
|
fun updateMarketingInfo(memberId: Long, adid: String, pid: String): Boolean {
|
|
val member = repository.findByIdOrNull(id = memberId)
|
|
?: throw SodaException("로그인 정보를 확인해주세요.")
|
|
|
|
if (adid != member.adid) {
|
|
member.adid = adid
|
|
}
|
|
|
|
if (pid != member.activePid && pid.isNotBlank()) {
|
|
member.activePid = pid
|
|
member.partnerExpirationDatetime = LocalDateTime.now().plusYears(1)
|
|
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
}
|