캐릭터 챗봇 #338
| @@ -13,6 +13,7 @@ import kr.co.vividnext.sodalive.can.use.UseCanCalculate | |||||||
| import kr.co.vividnext.sodalive.can.use.UseCanCalculateRepository | import kr.co.vividnext.sodalive.can.use.UseCanCalculateRepository | ||||||
| import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus | import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus | ||||||
| import kr.co.vividnext.sodalive.can.use.UseCanRepository | import kr.co.vividnext.sodalive.can.use.UseCanRepository | ||||||
|  | import kr.co.vividnext.sodalive.chat.character.image.CharacterImage | ||||||
| import kr.co.vividnext.sodalive.common.SodaException | import kr.co.vividnext.sodalive.common.SodaException | ||||||
| import kr.co.vividnext.sodalive.content.AudioContent | import kr.co.vividnext.sodalive.content.AudioContent | ||||||
| import kr.co.vividnext.sodalive.content.order.Order | import kr.co.vividnext.sodalive.content.order.Order | ||||||
| @@ -327,4 +328,49 @@ class CanPaymentService( | |||||||
|             chargeRepository.save(charge) |             chargeRepository.save(charge) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Transactional | ||||||
|  |     fun spendCanForCharacterImage( | ||||||
|  |         memberId: Long, | ||||||
|  |         needCan: Int, | ||||||
|  |         image: CharacterImage, | ||||||
|  |         container: String | ||||||
|  |     ) { | ||||||
|  |         val member = memberRepository.findByIdOrNull(id = memberId) | ||||||
|  |             ?: throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.") | ||||||
|  |  | ||||||
|  |         val useRewardCan = spendRewardCan(member, needCan, container) | ||||||
|  |         val useChargeCan = if (needCan - useRewardCan.total > 0) { | ||||||
|  |             spendChargeCan(member, needCan = needCan - useRewardCan.total, container = container) | ||||||
|  |         } else { | ||||||
|  |             null | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (needCan - useRewardCan.total - (useChargeCan?.total ?: 0) > 0) { | ||||||
|  |             throw SodaException( | ||||||
|  |                 "${needCan - useRewardCan.total - (useChargeCan?.total ?: 0)} " + | ||||||
|  |                     "캔이 부족합니다. 충전 후 이용해 주세요." | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (!useRewardCan.verify() || useChargeCan?.verify() == false) { | ||||||
|  |             throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.") | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         val useCan = UseCan( | ||||||
|  |             canUsage = CanUsage.CHARACTER_IMAGE_PURCHASE, | ||||||
|  |             can = useChargeCan?.total ?: 0, | ||||||
|  |             rewardCan = useRewardCan.total, | ||||||
|  |             isSecret = false | ||||||
|  |         ) | ||||||
|  |         useCan.member = member | ||||||
|  |         useCan.characterImage = image | ||||||
|  |  | ||||||
|  |         useCanRepository.save(useCan) | ||||||
|  |  | ||||||
|  |         setUseCanCalculate(null, useRewardCan, useChargeCan, useCan, paymentGateway = PaymentGateway.PG) | ||||||
|  |         setUseCanCalculate(null, useRewardCan, useChargeCan, useCan, paymentGateway = PaymentGateway.POINT_CLICK_AD) | ||||||
|  |         setUseCanCalculate(null, useRewardCan, useChargeCan, useCan, paymentGateway = PaymentGateway.GOOGLE_IAP) | ||||||
|  |         setUseCanCalculate(null, useRewardCan, useChargeCan, useCan, paymentGateway = PaymentGateway.APPLE_IAP) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,8 +1,11 @@ | |||||||
| package kr.co.vividnext.sodalive.chat.character.image | package kr.co.vividnext.sodalive.chat.character.image | ||||||
|  |  | ||||||
| import kr.co.vividnext.sodalive.aws.cloudfront.ImageContentCloudFront | import kr.co.vividnext.sodalive.aws.cloudfront.ImageContentCloudFront | ||||||
|  | import kr.co.vividnext.sodalive.can.payment.CanPaymentService | ||||||
| import kr.co.vividnext.sodalive.chat.character.image.dto.CharacterImageListItemResponse | import kr.co.vividnext.sodalive.chat.character.image.dto.CharacterImageListItemResponse | ||||||
| import kr.co.vividnext.sodalive.chat.character.image.dto.CharacterImageListResponse | import kr.co.vividnext.sodalive.chat.character.image.dto.CharacterImageListResponse | ||||||
|  | import kr.co.vividnext.sodalive.chat.character.image.dto.CharacterImagePurchaseRequest | ||||||
|  | import kr.co.vividnext.sodalive.chat.character.image.dto.CharacterImagePurchaseResponse | ||||||
| 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.member.Member | import kr.co.vividnext.sodalive.member.Member | ||||||
| @@ -10,6 +13,8 @@ import org.springframework.beans.factory.annotation.Value | |||||||
| import org.springframework.data.domain.PageRequest | import org.springframework.data.domain.PageRequest | ||||||
| import org.springframework.security.core.annotation.AuthenticationPrincipal | import org.springframework.security.core.annotation.AuthenticationPrincipal | ||||||
| import org.springframework.web.bind.annotation.GetMapping | 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.RequestMapping | ||||||
| import org.springframework.web.bind.annotation.RequestParam | import org.springframework.web.bind.annotation.RequestParam | ||||||
| import org.springframework.web.bind.annotation.RestController | import org.springframework.web.bind.annotation.RestController | ||||||
| @@ -19,6 +24,7 @@ import org.springframework.web.bind.annotation.RestController | |||||||
| class CharacterImageController( | class CharacterImageController( | ||||||
|     private val imageService: CharacterImageService, |     private val imageService: CharacterImageService, | ||||||
|     private val imageCloudFront: ImageContentCloudFront, |     private val imageCloudFront: ImageContentCloudFront, | ||||||
|  |     private val canPaymentService: CanPaymentService, | ||||||
|     @Value("\${cloud.aws.cloud-front.host}") |     @Value("\${cloud.aws.cloud-front.host}") | ||||||
|     private val imageHost: String |     private val imageHost: String | ||||||
| ) { | ) { | ||||||
| @@ -67,4 +73,35 @@ class CharacterImageController( | |||||||
|             ) |             ) | ||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @PostMapping("/purchase") | ||||||
|  |     fun purchase( | ||||||
|  |         @RequestBody req: CharacterImagePurchaseRequest, | ||||||
|  |         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? | ||||||
|  |     ) = run { | ||||||
|  |         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||||
|  |         if (member.auth == null) throw SodaException("본인인증을 하셔야 합니다.") | ||||||
|  |  | ||||||
|  |         val image = imageService.getById(req.imageId) | ||||||
|  |         if (!image.isActive) throw SodaException("비활성화된 이미지입니다.") | ||||||
|  |  | ||||||
|  |         val isOwned = (image.imagePriceCan == 0L) || | ||||||
|  |             imageService.isOwnedImageByMember(image.id!!, member.id!!) | ||||||
|  |  | ||||||
|  |         if (!isOwned) { | ||||||
|  |             val needCan = image.imagePriceCan.toInt() | ||||||
|  |             if (needCan <= 0) throw SodaException("구매 가격이 잘못되었습니다.") | ||||||
|  |  | ||||||
|  |             canPaymentService.spendCanForCharacterImage( | ||||||
|  |                 memberId = member.id!!, | ||||||
|  |                 needCan = needCan, | ||||||
|  |                 image = image, | ||||||
|  |                 container = req.container | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         val expiration = 5L * 60L * 1000L // 5분 | ||||||
|  |         val signedUrl = imageCloudFront.generateSignedURL(image.imagePath, expiration) | ||||||
|  |         ApiResponse.ok(CharacterImagePurchaseResponse(imageUrl = signedUrl)) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,12 @@ | |||||||
|  | package kr.co.vividnext.sodalive.chat.character.image.dto | ||||||
|  |  | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty | ||||||
|  |  | ||||||
|  | data class CharacterImagePurchaseRequest( | ||||||
|  |     @JsonProperty("imageId") val imageId: Long, | ||||||
|  |     @JsonProperty("container") val container: String | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | data class CharacterImagePurchaseResponse( | ||||||
|  |     @JsonProperty("imageUrl") val imageUrl: String | ||||||
|  | ) | ||||||
		Reference in New Issue
	
	Block a user