시큐리티 설정
유저 API - 로그인, 회원가입, 계정정보 추가
This commit is contained in:
104
src/main/kotlin/kr/co/vividnext/sodalive/member/Member.kt
Normal file
104
src/main/kotlin/kr/co/vividnext/sodalive/member/Member.kt
Normal file
@@ -0,0 +1,104 @@
|
||||
package kr.co.vividnext.sodalive.member
|
||||
|
||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import kr.co.vividnext.sodalive.member.auth.Auth
|
||||
import kr.co.vividnext.sodalive.member.notification.MemberNotification
|
||||
import kr.co.vividnext.sodalive.member.stipulation.StipulationAgree
|
||||
import javax.persistence.CascadeType
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.EnumType
|
||||
import javax.persistence.Enumerated
|
||||
import javax.persistence.FetchType
|
||||
import javax.persistence.OneToMany
|
||||
import javax.persistence.OneToOne
|
||||
|
||||
@Entity
|
||||
data class Member(
|
||||
val email: String,
|
||||
var password: String,
|
||||
var nickname: String,
|
||||
var profileImage: String? = null,
|
||||
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
var gender: Gender = Gender.NONE,
|
||||
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
var role: MemberRole = MemberRole.USER,
|
||||
|
||||
var isActive: Boolean = true,
|
||||
|
||||
var container: String = "web"
|
||||
) : BaseEntity() {
|
||||
@OneToMany(mappedBy = "member", cascade = [CascadeType.ALL])
|
||||
val stipulationAgrees: MutableList<StipulationAgree> = mutableListOf()
|
||||
|
||||
@OneToOne(mappedBy = "member", fetch = FetchType.LAZY)
|
||||
var notification: MemberNotification? = null
|
||||
|
||||
@OneToOne(mappedBy = "member", fetch = FetchType.LAZY)
|
||||
var auth: Auth? = null
|
||||
|
||||
// 소개
|
||||
@Column(columnDefinition = "TEXT")
|
||||
var introduce = ""
|
||||
|
||||
// SNS
|
||||
var instagramUrl = ""
|
||||
var youtubeUrl = ""
|
||||
var websiteUrl = ""
|
||||
var blogUrl = ""
|
||||
|
||||
var pushToken: String? = null
|
||||
|
||||
// 화폐
|
||||
private var pgChargeCan: Int = 0
|
||||
private var pgRewardCan: Int = 0
|
||||
private var googleChargeCan: Int = 0
|
||||
private var googleRewardCan: Int = 0
|
||||
private var appleChargeCan: Int = 0
|
||||
private var appleRewardCan: Int = 0
|
||||
|
||||
fun getChargeCan(container: String): Int {
|
||||
return when (container) {
|
||||
"ios" -> appleChargeCan + pgChargeCan
|
||||
"aos" -> googleChargeCan + pgChargeCan
|
||||
else -> pgChargeCan
|
||||
}
|
||||
}
|
||||
|
||||
fun getRewardCan(container: String): Int {
|
||||
return when (container) {
|
||||
"ios" -> appleRewardCan + pgRewardCan
|
||||
"aos" -> googleRewardCan + pgRewardCan
|
||||
else -> pgRewardCan
|
||||
}
|
||||
}
|
||||
|
||||
fun charge(chargeCan: Int, rewardCan: Int, container: String) {
|
||||
when (container) {
|
||||
"ios" -> {
|
||||
appleChargeCan = chargeCan
|
||||
appleRewardCan = rewardCan
|
||||
}
|
||||
|
||||
"aos" -> {
|
||||
googleChargeCan = chargeCan
|
||||
googleRewardCan = rewardCan
|
||||
}
|
||||
|
||||
else -> {
|
||||
pgChargeCan = chargeCan
|
||||
pgRewardCan = rewardCan
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class Gender {
|
||||
MALE, FEMALE, NONE
|
||||
}
|
||||
|
||||
enum class MemberRole {
|
||||
ADMIN, BOT, USER, CREATOR, AGENT
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package kr.co.vividnext.sodalive.member
|
||||
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority
|
||||
import org.springframework.security.core.userdetails.User
|
||||
|
||||
class MemberAdapter(val member: Member) : User(
|
||||
member.email,
|
||||
member.password,
|
||||
listOf(SimpleGrantedAuthority("ROLE_${member.role.name}"))
|
||||
)
|
@@ -0,0 +1,37 @@
|
||||
package kr.co.vividnext.sodalive.member
|
||||
|
||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.member.login.LoginRequest
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.RequestPart
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/member")
|
||||
class MemberController(private val service: MemberService) {
|
||||
@PostMapping("/signup")
|
||||
fun signUp(
|
||||
@RequestPart("profileImage", required = false) profileImage: MultipartFile? = null,
|
||||
@RequestPart("request") requestString: String
|
||||
) = service.signUp(profileImage, requestString)
|
||||
|
||||
@PostMapping("/login")
|
||||
fun login(@RequestBody loginRequest: LoginRequest) = service.login(loginRequest)
|
||||
|
||||
@GetMapping("/info")
|
||||
fun getMemberInfo(
|
||||
@RequestParam container: String?,
|
||||
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
|
||||
) = run {
|
||||
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
|
||||
|
||||
ApiResponse.ok(service.getMemberInfo(member, container ?: "web"))
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package kr.co.vividnext.sodalive.member
|
||||
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
interface MemberRepository : JpaRepository<Member, Long>, MemberQueryRepository {
|
||||
fun findByEmail(email: String): Member?
|
||||
fun findByNickname(nickname: String): Member?
|
||||
}
|
||||
|
||||
interface MemberQueryRepository
|
||||
|
||||
@Repository
|
||||
class MemberQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : MemberQueryRepository
|
215
src/main/kotlin/kr/co/vividnext/sodalive/member/MemberService.kt
Normal file
215
src/main/kotlin/kr/co/vividnext/sodalive/member/MemberService.kt
Normal file
@@ -0,0 +1,215 @@
|
||||
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.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 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
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
package kr.co.vividnext.sodalive.member
|
||||
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class SignUpValidator {
|
||||
fun emailValidation(email: String): String {
|
||||
val isNotValidEmail = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$"
|
||||
.toRegex(RegexOption.IGNORE_CASE)
|
||||
.matches(email)
|
||||
.not()
|
||||
|
||||
if (isNotValidEmail) {
|
||||
return "올바른 이메일을 입력해 주세요"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
fun nicknameValidation(nickname: String): String {
|
||||
if (nickname.length < 2) {
|
||||
return "닉네임은 2자 이상 입력해 주세요."
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
fun passwordValidation(password: String): String {
|
||||
val isNotValidPassword = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d$@!%*#?&]{8,}$"
|
||||
.toRegex()
|
||||
.matches(password)
|
||||
.not()
|
||||
|
||||
if (isNotValidPassword) {
|
||||
return "영문, 숫자 포함 8자 이상의 비밀번호를 입력해 주세요."
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
}
|
30
src/main/kotlin/kr/co/vividnext/sodalive/member/auth/Auth.kt
Normal file
30
src/main/kotlin/kr/co/vividnext/sodalive/member/auth/Auth.kt
Normal file
@@ -0,0 +1,30 @@
|
||||
package kr.co.vividnext.sodalive.member.auth
|
||||
|
||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import javax.persistence.CascadeType
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.FetchType
|
||||
import javax.persistence.JoinColumn
|
||||
import javax.persistence.OneToOne
|
||||
|
||||
@Entity
|
||||
data class Auth(
|
||||
@Column(nullable = false)
|
||||
val name: String,
|
||||
@Column(nullable = false)
|
||||
val birth: String,
|
||||
@Column(columnDefinition = "TEXT", nullable = false)
|
||||
val uniqueCi: String,
|
||||
@Column(columnDefinition = "TEXT", nullable = false)
|
||||
val di: String
|
||||
) : BaseEntity() {
|
||||
@OneToOne(fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
|
||||
@JoinColumn(name = "member_id", nullable = true)
|
||||
var member: Member? = null
|
||||
set(value) {
|
||||
value?.auth = this
|
||||
field = value
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package kr.co.vividnext.sodalive.member.info
|
||||
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
|
||||
data class GetMemberInfoResponse(
|
||||
val can: Int,
|
||||
val isAuth: Boolean,
|
||||
val role: MemberRole,
|
||||
val messageNotice: Boolean?,
|
||||
val followingChannelLiveNotice: Boolean?,
|
||||
val followingChannelUploadContentNotice: Boolean?
|
||||
)
|
@@ -0,0 +1,8 @@
|
||||
package kr.co.vividnext.sodalive.member.login
|
||||
|
||||
data class LoginRequest(
|
||||
val email: String,
|
||||
val password: String,
|
||||
val isAdmin: Boolean = false,
|
||||
val isCreator: Boolean = false
|
||||
)
|
@@ -0,0 +1,9 @@
|
||||
package kr.co.vividnext.sodalive.member.login
|
||||
|
||||
data class LoginResponse(
|
||||
val userId: Long,
|
||||
val token: String,
|
||||
val nickname: String,
|
||||
val email: String,
|
||||
val profileImage: String
|
||||
)
|
@@ -0,0 +1,29 @@
|
||||
package kr.co.vividnext.sodalive.member.notification
|
||||
|
||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.FetchType
|
||||
import javax.persistence.JoinColumn
|
||||
import javax.persistence.OneToOne
|
||||
|
||||
@Entity
|
||||
data class MemberNotification(
|
||||
@Column(nullable = false)
|
||||
var uploadContent: Boolean? = true,
|
||||
|
||||
@Column(nullable = false)
|
||||
var live: Boolean? = true,
|
||||
|
||||
@Column(nullable = false)
|
||||
var message: Boolean? = true
|
||||
) : BaseEntity() {
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "member_id", nullable = false)
|
||||
var member: Member? = null
|
||||
set(value) {
|
||||
value?.notification = this
|
||||
field = value
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
package kr.co.vividnext.sodalive.member.signUp
|
||||
|
||||
import kr.co.vividnext.sodalive.member.Gender
|
||||
|
||||
data class SignUpRequest(
|
||||
val email: String,
|
||||
val password: String,
|
||||
val nickname: String,
|
||||
val gender: Gender,
|
||||
val isAgreeTermsOfService: Boolean,
|
||||
val isAgreePrivacyPolicy: Boolean,
|
||||
val container: String = "api"
|
||||
)
|
@@ -0,0 +1,14 @@
|
||||
package kr.co.vividnext.sodalive.member.stipulation
|
||||
|
||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
|
||||
@Entity
|
||||
data class Stipulation(
|
||||
@Column(nullable = false)
|
||||
val title: String,
|
||||
@Column(columnDefinition = "TEXT", nullable = false)
|
||||
var description: String,
|
||||
var isActive: Boolean = true
|
||||
) : BaseEntity()
|
@@ -0,0 +1,30 @@
|
||||
package kr.co.vividnext.sodalive.member.stipulation
|
||||
|
||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.FetchType
|
||||
import javax.persistence.JoinColumn
|
||||
import javax.persistence.ManyToOne
|
||||
|
||||
@Entity
|
||||
data class StipulationAgree(
|
||||
val isAgree: Boolean
|
||||
) : BaseEntity() {
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "member_id", nullable = false)
|
||||
var member: Member? = null
|
||||
set(value) {
|
||||
member?.stipulationAgrees?.add(this)
|
||||
field = value
|
||||
}
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "stipulation_id", nullable = false)
|
||||
var stipulation: Stipulation? = null
|
||||
}
|
||||
|
||||
object StipulationIds {
|
||||
const val TERMS_OF_SERVICE_ID = 1L
|
||||
const val PRIVACY_POLICY_ID = 2L
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package kr.co.vividnext.sodalive.member.stipulation
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
interface StipulationRepository : JpaRepository<Stipulation, Long>
|
||||
|
||||
@Repository
|
||||
interface StipulationAgreeRepository : JpaRepository<StipulationAgree, Long>
|
@@ -0,0 +1,11 @@
|
||||
package kr.co.vividnext.sodalive.member.token
|
||||
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.redis.core.RedisHash
|
||||
|
||||
@RedisHash("MemberToken")
|
||||
data class MemberToken(
|
||||
@Id
|
||||
val id: Long,
|
||||
var tokenList: List<String>
|
||||
)
|
@@ -0,0 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.member.token
|
||||
|
||||
import org.springframework.data.repository.CrudRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
interface MemberTokenRepository : CrudRepository<MemberToken, Long>
|
Reference in New Issue
Block a user