Merge pull request 'test' (#142) from test into main

Reviewed-on: #142
This commit is contained in:
klaus 2024-03-21 07:45:02 +00:00
commit f0a69eb1a2
7 changed files with 128 additions and 11 deletions

View File

@ -59,6 +59,9 @@ dependencies {
// firebase admin sdk
implementation("com.google.firebase:firebase-admin:9.2.0")
// android publisher
implementation("com.google.apis:google-api-services-androidpublisher:v3-rev20240319-2.0.0")
implementation("org.apache.poi:poi-ooxml:5.2.3")
developmentOnly("org.springframework.boot:spring-boot-devtools")

View File

@ -19,7 +19,13 @@ interface AdminContentRepository : JpaRepository<AudioContent, Long>, AdminAudio
interface AdminAudioContentQueryRepository {
fun getAudioContentTotalCount(searchWord: String = ""): Int
fun getAudioContentList(offset: Long, limit: Long, searchWord: String = ""): List<GetAdminContentListItem>
fun getAudioContentList(
imageHost: String,
offset: Long,
limit: Long,
searchWord: String = ""
): List<GetAdminContentListItem>
fun getHashTagList(audioContentId: Long): List<String>
}
@ -46,7 +52,12 @@ class AdminAudioContentQueryRepositoryImpl(
.size
}
override fun getAudioContentList(offset: Long, limit: Long, searchWord: String): List<GetAdminContentListItem> {
override fun getAudioContentList(
imageHost: String,
offset: Long,
limit: Long,
searchWord: String
): List<GetAdminContentListItem> {
var where = audioContent.duration.isNotNull
.and(audioContent.member.isNotNull)
.and(audioContent.isActive.isTrue.or(audioContent.releaseDate.isNotNull))
@ -66,7 +77,7 @@ class AdminAudioContentQueryRepositoryImpl(
audioContent.detail,
audioContentCuration.title,
audioContentCuration.id.nullif(0),
audioContent.coverImage,
audioContent.coverImage.prepend("/").prepend(imageHost),
audioContent.member!!.nickname,
audioContentTheme.theme,
audioContentTheme.id,

View File

@ -23,6 +23,7 @@ class AdminContentService(
fun getAudioContentList(pageable: Pageable): GetAdminContentListResponse {
val totalCount = repository.getAudioContentTotalCount()
val audioContentAndThemeList = repository.getAudioContentList(
imageHost = coverImageHost,
offset = pageable.offset,
limit = pageable.pageSize.toLong()
)
@ -43,10 +44,6 @@ class AdminContentService(
)
it
}
.map {
it.coverImageUrl = "$coverImageHost/${it.coverImageUrl}"
it
}
.toList()
return GetAdminContentListResponse(totalCount, audioContentList)
@ -56,6 +53,7 @@ class AdminContentService(
if (searchWord.length < 2) throw SodaException("2글자 이상 입력하세요.")
val totalCount = repository.getAudioContentTotalCount(searchWord)
val audioContentAndThemeList = repository.getAudioContentList(
imageHost = coverImageHost,
offset = pageable.offset,
limit = pageable.pageSize.toLong(),
searchWord = searchWord
@ -77,10 +75,6 @@ class AdminContentService(
)
it
}
.map {
it.coverImageUrl = "$coverImageHost/${it.coverImageUrl}"
it
}
.toList()
return GetAdminContentListResponse(totalCount, audioContentList)

View File

@ -49,4 +49,22 @@ class ChargeController(private val service: ChargeService) {
@RequestBody verifyRequest: AppleVerifyRequest,
@AuthenticationPrincipal user: User
) = ApiResponse.ok(service.appleVerify(user, verifyRequest))
@PostMapping("/google")
fun googleCharge(
@RequestBody request: GoogleChargeRequest,
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run {
if (member == null) {
throw SodaException("로그인 정보를 확인해주세요.")
}
ApiResponse.ok(service.googleCharge(member, request))
}
@PostMapping("/google/verify")
fun googleVerify(
@RequestBody request: GoogleVerifyRequest,
@AuthenticationPrincipal user: User
) = ApiResponse.ok(service.googleVerify(user, request))
}

View File

@ -33,3 +33,13 @@ data class AppleChargeRequest(
data class AppleVerifyRequest(val receiptString: String, val chargeId: Long)
data class AppleVerifyResponse(val status: Int)
data class GoogleChargeRequest(
val title: String,
val chargeCan: Int,
val price: Double,
val currencyCode: String,
val paymentGateway: PaymentGateway
)
data class GoogleVerifyRequest(val productId: String, val purchaseToken: String, val chargeId: Long)

View File

@ -1,6 +1,7 @@
package kr.co.vividnext.sodalive.can.charge
import com.fasterxml.jackson.databind.ObjectMapper
import com.google.api.services.androidpublisher.AndroidPublisher
import kr.co.bootpay.Bootpay
import kr.co.vividnext.sodalive.can.CanRepository
import kr.co.vividnext.sodalive.can.charge.event.ChargeSpringEvent
@ -36,6 +37,8 @@ class ChargeService(
private val okHttpClient: OkHttpClient,
private val applicationEventPublisher: ApplicationEventPublisher,
private val androidPublisher: AndroidPublisher,
@Value("\${bootpay.application-id}")
private val bootpayApplicationId: String,
@Value("\${bootpay.private-key}")
@ -183,6 +186,53 @@ class ChargeService(
}
}
@Transactional
fun googleCharge(member: Member, request: GoogleChargeRequest): ChargeResponse {
val charge = Charge(request.chargeCan, 0)
charge.title = request.title
charge.member = member
val payment = Payment(paymentGateway = request.paymentGateway)
payment.locale = request.currencyCode
payment.price = request.price
charge.payment = payment
chargeRepository.save(charge)
return ChargeResponse(chargeId = charge.id!!)
}
fun googleVerify(user: User, request: GoogleVerifyRequest) {
val charge = chargeRepository.findByIdOrNull(request.chargeId)
?: throw SodaException("결제정보에 오류가 있습니다.")
val member = memberRepository.findByEmail(user.username)
?: throw SodaException("로그인 정보를 확인해주세요.")
if (charge.payment!!.paymentGateway == PaymentGateway.GOOGLE_IAP) {
val response = androidPublisher.purchases().products()
.get("kr.co.vividnext.sodalive", request.productId, request.purchaseToken)
.execute()
if (response.purchaseState == 0) {
charge.payment?.receiptId = response.purchaseToken
charge.payment?.method = "구글(인 앱 결제)"
charge.payment?.status = PaymentStatus.COMPLETE
member.charge(charge.chargeCan, charge.rewardCan, "aos")
applicationEventPublisher.publishEvent(
ChargeSpringEvent(
chargeId = charge.id!!,
memberId = member.id!!
)
)
} else {
throw SodaException("결제정보에 오류가 있습니다.")
}
} else {
throw SodaException("결제정보에 오류가 있습니다.")
}
}
private fun requestRealServerVerify(verifyRequest: AppleVerifyRequest): Boolean {
val body = JSONObject()
body.put("receipt-data", verifyRequest.receiptString)

View File

@ -0,0 +1,31 @@
package kr.co.vividnext.sodalive.configs
import com.google.api.client.http.javanet.NetHttpTransport
import com.google.api.client.json.gson.GsonFactory
import com.google.api.services.androidpublisher.AndroidPublisher
import com.google.api.services.androidpublisher.AndroidPublisherScopes
import com.google.auth.http.HttpCredentialsAdapter
import com.google.auth.oauth2.GoogleCredentials
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.io.FileInputStream
@Configuration
class AndroidPublisherConfig(
@Value("\${firebase.secret-key-path}")
private val secretKeyPath: String
) {
@Bean
fun androidPublisher(): AndroidPublisher {
val jsonFactory = GsonFactory.getDefaultInstance()
val httpTransport = NetHttpTransport()
val credential = GoogleCredentials.fromStream(FileInputStream(secretKeyPath))
.createScoped(listOf(AndroidPublisherScopes.ANDROIDPUBLISHER))
return AndroidPublisher.Builder(httpTransport, jsonFactory, HttpCredentialsAdapter(credential))
.setApplicationName("소다라이브")
.build()
}
}