Compare commits

..

No commits in common. "83ed4b6961377c4a9adce11e8b1a9be9d4c6c052" and "801b9934d61461c3d857dc2b59b790024f9509d6" have entirely different histories.

12 changed files with 4 additions and 214 deletions

View File

@ -66,7 +66,6 @@ dependencies {
implementation("com.google.apis:google-api-services-androidpublisher:v3-rev20240319-2.0.0") implementation("com.google.apis:google-api-services-androidpublisher:v3-rev20240319-2.0.0")
implementation("org.apache.poi:poi-ooxml:5.2.3") implementation("org.apache.poi:poi-ooxml:5.2.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
developmentOnly("org.springframework.boot:spring-boot-devtools") developmentOnly("org.springframework.boot:spring-boot-devtools")
runtimeOnly("com.h2database:h2") runtimeOnly("com.h2database:h2")

View File

@ -1,22 +0,0 @@
package kr.co.vividnext.sodalive.marketing
import kr.co.vividnext.sodalive.common.BaseEntity
import javax.persistence.Entity
import javax.persistence.EnumType
import javax.persistence.Enumerated
@Entity
data class AdMediaPartner(
val mediaGroup: String,
val pid: String,
val pidName: String,
@Enumerated(value = EnumType.STRING)
val type: AdMediaPartnerType,
val utmSource: String,
val utmMedium: String,
val isActive: Boolean = true
) : BaseEntity()
enum class AdMediaPartnerType {
SERIES, CONTENT, LIVE, CHANNEL, MAIN
}

View File

@ -1,15 +0,0 @@
package kr.co.vividnext.sodalive.marketing
import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.marketing.QAdMediaPartner.adMediaPartner
import org.springframework.stereotype.Repository
@Repository
class AdMediaPartnerRepository(private val queryFactory: JPAQueryFactory) {
fun findByPid(pid: String): AdMediaPartner? {
return queryFactory
.selectFrom(adMediaPartner)
.where(adMediaPartner.pid.eq(pid), adMediaPartner.isActive.isTrue)
.fetchFirst()
}
}

View File

@ -1,44 +0,0 @@
package kr.co.vividnext.sodalive.marketing
import java.io.Serializable
import java.time.LocalDateTime
import javax.persistence.Embeddable
import javax.persistence.EmbeddedId
import javax.persistence.Entity
import javax.persistence.EnumType
import javax.persistence.Enumerated
import javax.persistence.PreUpdate
@Entity
data class AdTrackingHistory(
@EmbeddedId
val id: AdTrackingHistoryId,
val price: Double = 0.toDouble(),
val locale: String? = null,
var updatedAt: LocalDateTime = LocalDateTime.now()
) {
@PreUpdate
fun preUpdate() {
updatedAt = LocalDateTime.now()
}
}
@Embeddable
data class AdTrackingHistoryId(
val pid: String,
val memberId: Long,
@Enumerated(value = EnumType.STRING)
val type: AdTrackingHistoryType,
val createdAt: LocalDateTime = LocalDateTime.now()
) : Serializable
enum class AdTrackingHistoryType {
// 회원가입
SIGNUP,
// 첫결제
FIRST_PAYMENT,
// 재결제
REPEAT_PAYMENT
}

View File

@ -1,5 +0,0 @@
package kr.co.vividnext.sodalive.marketing
import org.springframework.data.jpa.repository.JpaRepository
interface AdTrackingRepository : JpaRepository<AdTrackingHistory, AdTrackingHistoryId>

View File

@ -1,41 +0,0 @@
package kr.co.vividnext.sodalive.marketing
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.springframework.stereotype.Service
@Service
class AdTrackingService(
private val repository: AdTrackingRepository,
private val mediaPartnerRepository: AdMediaPartnerRepository
) {
private val coroutineScope = CoroutineScope(Dispatchers.IO)
fun saveTrackingHistory(
pid: String,
type: AdTrackingHistoryType,
memberId: Long,
price: Double? = null,
locale: String? = null
) {
coroutineScope.launch {
try {
val mediaPartner = mediaPartnerRepository.findByPid(pid)
if (mediaPartner != null) {
val id = AdTrackingHistoryId(pid = pid, memberId = memberId, type = type)
val trackingHistory = AdTrackingHistory(
id = id,
price = price ?: 0.toDouble(),
locale = locale
)
repository.save(trackingHistory)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}

View File

@ -1,6 +0,0 @@
package kr.co.vividnext.sodalive.member
data class MarketingInfoUpdateRequest(
val adid: String,
val pid: String
)

View File

@ -7,7 +7,6 @@ import kr.co.vividnext.sodalive.member.following.CreatorFollowing
import kr.co.vividnext.sodalive.member.notification.MemberNotification import kr.co.vividnext.sodalive.member.notification.MemberNotification
import kr.co.vividnext.sodalive.member.stipulation.StipulationAgree import kr.co.vividnext.sodalive.member.stipulation.StipulationAgree
import kr.co.vividnext.sodalive.member.tag.MemberCreatorTag import kr.co.vividnext.sodalive.member.tag.MemberCreatorTag
import java.time.LocalDateTime
import javax.persistence.CascadeType import javax.persistence.CascadeType
import javax.persistence.Column import javax.persistence.Column
import javax.persistence.Entity import javax.persistence.Entity
@ -30,12 +29,6 @@ data class Member(
@Enumerated(value = EnumType.STRING) @Enumerated(value = EnumType.STRING)
var role: MemberRole = MemberRole.USER, var role: MemberRole = MemberRole.USER,
@Column(nullable = true)
var activePid: String? = null,
@Column(nullable = true)
var partnerExpirationDateTime: LocalDateTime? = null,
var isVisibleDonationRank: Boolean = true, var isVisibleDonationRank: Boolean = true,
var isActive: Boolean = true, var isActive: Boolean = true,

View File

@ -2,12 +2,9 @@ package kr.co.vividnext.sodalive.member
import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.marketing.AdTrackingHistoryType
import kr.co.vividnext.sodalive.marketing.AdTrackingService
import kr.co.vividnext.sodalive.member.block.MemberBlockRequest import kr.co.vividnext.sodalive.member.block.MemberBlockRequest
import kr.co.vividnext.sodalive.member.following.CreatorFollowRequest import kr.co.vividnext.sodalive.member.following.CreatorFollowRequest
import kr.co.vividnext.sodalive.member.login.LoginRequest import kr.co.vividnext.sodalive.member.login.LoginRequest
import kr.co.vividnext.sodalive.member.login.LoginResponse
import kr.co.vividnext.sodalive.member.notification.UpdateNotificationSettingRequest import kr.co.vividnext.sodalive.member.notification.UpdateNotificationSettingRequest
import org.springframework.data.domain.Pageable import org.springframework.data.domain.Pageable
import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.security.core.annotation.AuthenticationPrincipal
@ -26,10 +23,7 @@ import org.springframework.web.multipart.MultipartFile
@RestController @RestController
@RequestMapping("/member") @RequestMapping("/member")
class MemberController( class MemberController(private val service: MemberService) {
private val service: MemberService,
private val trackingService: AdTrackingService
) {
@GetMapping("/check/email") @GetMapping("/check/email")
fun checkEmail(@RequestParam email: String) = service.duplicateCheckEmail(email) fun checkEmail(@RequestParam email: String) = service.duplicateCheckEmail(email)
@ -46,19 +40,7 @@ class MemberController(
fun signUp( fun signUp(
@RequestPart("profileImage", required = false) profileImage: MultipartFile? = null, @RequestPart("profileImage", required = false) profileImage: MultipartFile? = null,
@RequestPart("request") requestString: String @RequestPart("request") requestString: String
): ApiResponse<LoginResponse> { ) = service.signUp(profileImage, requestString)
val response = service.signUp(profileImage, requestString)
if (!response.marketingPid.isNullOrBlank()) {
trackingService.saveTrackingHistory(
pid = response.marketingPid,
type = AdTrackingHistoryType.SIGNUP,
memberId = response.memberId
)
}
return ApiResponse.ok(message = "회원가입을 축하드립니다.", data = response.loginResponse)
}
@PostMapping("/login") @PostMapping("/login")
fun login(@RequestBody loginRequest: LoginRequest) = service.login(loginRequest) fun login(@RequestBody loginRequest: LoginRequest) = service.login(loginRequest)
@ -128,22 +110,6 @@ class MemberController(
) )
} }
@PutMapping("/marketing-info/update")
fun updateMarketingInfo(
@RequestBody request: MarketingInfoUpdateRequest,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(
service.updateMarketingInfo(
memberId = member.id!!,
adid = request.adid,
pid = request.pid
)
)
}
@PutMapping("/adid/update") @PutMapping("/adid/update")
fun updateAdid( fun updateAdid(
@RequestBody request: AdidUpdateRequest, @RequestBody request: AdidUpdateRequest,

View File

@ -27,7 +27,6 @@ import kr.co.vividnext.sodalive.member.nickname.NicknameChangeLogRepository
import kr.co.vividnext.sodalive.member.notification.MemberNotificationService import kr.co.vividnext.sodalive.member.notification.MemberNotificationService
import kr.co.vividnext.sodalive.member.notification.UpdateNotificationSettingRequest import kr.co.vividnext.sodalive.member.notification.UpdateNotificationSettingRequest
import kr.co.vividnext.sodalive.member.signUp.SignUpRequest import kr.co.vividnext.sodalive.member.signUp.SignUpRequest
import kr.co.vividnext.sodalive.member.signUp.SignUpResponse
import kr.co.vividnext.sodalive.member.signUp.SignUpValidator import kr.co.vividnext.sodalive.member.signUp.SignUpValidator
import kr.co.vividnext.sodalive.member.stipulation.Stipulation import kr.co.vividnext.sodalive.member.stipulation.Stipulation
import kr.co.vividnext.sodalive.member.stipulation.StipulationAgree import kr.co.vividnext.sodalive.member.stipulation.StipulationAgree
@ -98,7 +97,7 @@ class MemberService(
fun signUp( fun signUp(
profileImage: MultipartFile?, profileImage: MultipartFile?,
requestString: String requestString: String
): SignUpResponse { ): ApiResponse<LoginResponse> {
val stipulationTermsOfService = stipulationRepository.findByIdOrNull(StipulationIds.TERMS_OF_SERVICE_ID) val stipulationTermsOfService = stipulationRepository.findByIdOrNull(StipulationIds.TERMS_OF_SERVICE_ID)
?: throw SodaException("잘못된 요청입니다\n앱 종료 후 다시 시도해 주세요.") ?: throw SodaException("잘못된 요청입니다\n앱 종료 후 다시 시도해 주세요.")
@ -118,11 +117,7 @@ class MemberService(
member.profileImage = uploadProfileImage(profileImage = profileImage, memberId = member.id!!) member.profileImage = uploadProfileImage(profileImage = profileImage, memberId = member.id!!)
agreeTermsOfServiceAndPrivacyPolicy(member, stipulationTermsOfService, stipulationPrivacyPolicy) agreeTermsOfServiceAndPrivacyPolicy(member, stipulationTermsOfService, stipulationPrivacyPolicy)
return SignUpResponse( return ApiResponse.ok(message = "회원가입을 축하드립니다.", data = login(request.email, request.password))
memberId = member.id!!,
marketingPid = request.marketingPid,
loginResponse = login(request.email, request.password)
)
} }
fun login(request: LoginRequest): ApiResponse<LoginResponse> { fun login(request: LoginRequest): ApiResponse<LoginResponse> {
@ -294,11 +289,6 @@ class MemberService(
container = request.container container = request.container
) )
if (!request.marketingPid.isNullOrBlank()) {
member.activePid = request.marketingPid
member.partnerExpirationDateTime = LocalDateTime.now().plusYears(1)
}
return repository.save(member) return repository.save(member)
} }
@ -646,19 +636,4 @@ class MemberService(
private fun getOrCreateLock(memberId: Long): ReentrantReadWriteLock { private fun getOrCreateLock(memberId: Long): ReentrantReadWriteLock {
return tokenLocks.computeIfAbsent(memberId) { ReentrantReadWriteLock() } return tokenLocks.computeIfAbsent(memberId) { ReentrantReadWriteLock() }
} }
@Transactional
fun updateMarketingInfo(memberId: Long, adid: String, pid: String) {
val member = repository.findByIdOrNull(id = memberId)
?: throw SodaException("로그인 정보를 확인해주세요.")
if (adid != member.adid) {
member.adid = adid
}
if (pid != member.activePid) {
member.activePid = pid
member.partnerExpirationDateTime = LocalDateTime.now().plusYears(1)
}
}
} }

View File

@ -7,7 +7,6 @@ data class SignUpRequest(
val password: String, val password: String,
val nickname: String, val nickname: String,
val gender: Gender, val gender: Gender,
val marketingPid: String? = null,
val isAgreeTermsOfService: Boolean, val isAgreeTermsOfService: Boolean,
val isAgreePrivacyPolicy: Boolean, val isAgreePrivacyPolicy: Boolean,
val container: String = "api" val container: String = "api"

View File

@ -1,9 +0,0 @@
package kr.co.vividnext.sodalive.member.signUp
import kr.co.vividnext.sodalive.member.login.LoginResponse
data class SignUpResponse(
val memberId: Long,
val marketingPid: String?,
val loginResponse: LoginResponse
)