Skip to content

Commit

Permalink
Merge pull request #88 from Next-Room/feature/subscription
Browse files Browse the repository at this point in the history
  • Loading branch information
delphox60 authored Nov 18, 2023
2 parents f806a02 + 28d2518 commit b61a7bc
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static com.nextroom.nextRoomServer.exceptions.StatusCode.*;

import java.io.IOException;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -12,10 +14,10 @@
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.api.services.androidpublisher.model.SubscriptionPurchase;
import com.nextroom.nextRoomServer.dto.BaseResponse;
import com.nextroom.nextRoomServer.dto.SubscriptionDto;
import com.nextroom.nextRoomServer.util.AndroidPublisherClient;
import com.nextroom.nextRoomServer.enums.SubscriptionStatus;
import com.nextroom.nextRoomServer.service.SubscriptionService;
import com.nextroom.nextRoomServer.util.Base64Decoder;

import io.swagger.v3.oas.annotations.tags.Tag;
Expand All @@ -26,35 +28,44 @@
@RequestMapping("/api/v1/payment")
@RequiredArgsConstructor
public class PaymentController {
@PostMapping
public ResponseEntity<BaseResponse> updatePayment(
// @RequestBody Object message
@RequestBody SubscriptionDto.UpdateSubscription messageDto
) throws
Exception {
System.out.println(messageDto.getMessage());

// AndroidPublisherClient androidPublisherClient = new AndroidPublisherClient();
// SubscriptionPurchase subscriptionPurchase = androidPublisherClient.getSubscriptionPurchase("1",
// "fhcdpgkjdpngkkealpkolhaf.AO-J1OzVCAYlVXjtKwF3vymo0VO1x2S2CZnD9lDszWLd4ePJ9hV6-QkM-zTv2_gUPNeDTPZhZWFgPiuZbEal5uX80iYaloHItHPOBJ43Kv_Tu7OZdoHijtg");
private final SubscriptionService subscriptionService;

//TEST END
String decodedData = Base64Decoder.decode(messageDto.getMessage().getData());
@PostMapping("/purchase")
public ResponseEntity<BaseResponse> purchaseSubscription(
@RequestBody SubscriptionDto.PurchaseSubscription request
) throws IOException {
subscriptionService.purchaseSubscription(request.getPurchaseToken(), request.getSubscriptionId());
return ResponseEntity.ok(new BaseResponse(OK));
}

System.out.println("decodedData = " + decodedData);
@PostMapping("/rtdn")
public ResponseEntity<BaseResponse> updateSubscriptionPurchase(
@RequestBody SubscriptionDto.UpdateSubscription requestBody
) throws
Exception {
String decodedData = Base64Decoder.decode(requestBody.getMessage().getData());

Pattern pattern = Pattern.compile(
".*\"subscriptionNotification\":\\{(.*?)\\}.*"); // TODO modify test -> subscription
".*\"subscriptionNotification\":\\{(.*?)\\}.*");
Matcher matcher = pattern.matcher(decodedData);

if (matcher.find()) {
String notificationContent = matcher.group(1);
ObjectMapper objectMapper = new ObjectMapper();
SubscriptionDto.PublishedMessage publishedMessage = objectMapper.readValue(decodedData,
SubscriptionDto.PublishedMessage.class);
System.out.println(publishedMessage.getSubscriptionNotification().getPurchaseToken());
}
String notificationContent = matcher.group(1);
ObjectMapper objectMapper = new ObjectMapper();
SubscriptionDto.PublishedMessage publishedMessage = objectMapper.readValue(decodedData,
SubscriptionDto.PublishedMessage.class);
System.out.println(publishedMessage.getSubscriptionNotification().getPurchaseToken());

// TODO handle exception
Integer notificationType = publishedMessage.getSubscriptionNotification().getNotificationType();
String purchaseToken = publishedMessage.getSubscriptionNotification().getPurchaseToken();
String subscriptionId = publishedMessage.getSubscriptionNotification().getSubscriptionId();

if (Objects.equals(notificationType, SubscriptionStatus.SUBSCRIPTION_RENEWED.getStatus())) {
subscriptionService.renew(purchaseToken, subscriptionId);
} else if (Objects.equals(notificationType, SubscriptionStatus.SUBSCRIPTION_EXPIRED.getStatus())) {
subscriptionService.expire(purchaseToken);
}
return ResponseEntity.ok(new BaseResponse(OK));
}
}
}
12 changes: 10 additions & 2 deletions src/main/java/com/nextroom/nextRoomServer/domain/Subscription.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,21 @@ public class Subscription extends Timestamped {
@JoinColumn(name = "shop_id", nullable = false)
private Shop shop;

private String googleId;

@Enumerated(EnumType.STRING)
private UserStatus status;
@Enumerated(EnumType.STRING)
private SubscriptionPlan plan;
private LocalDate expiryDate;
@Column(unique = true)
private String purchaseToken;

public void renew(LocalDate expiryDate) {
this.expiryDate = expiryDate;
}

public void expire() {
this.status = UserStatus.EXPIRATION;
}

public void updateStatus(UserStatus userStatus, LocalDate expiryDate, SubscriptionPlan plan) {
this.status = userStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.nextroom.nextRoomServer.util.Timestamped;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

public class SubscriptionDto {
@Getter
Expand Down Expand Up @@ -85,4 +86,11 @@ public SubscriptionPlanResponse(EnumModel enumModel) {
this.sellPrice = enumModel.getSellPrice();
}
}

@Getter
@RequiredArgsConstructor
public static class PurchaseSubscription {
private final String purchaseToken;
private final String subscriptionId;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.nextroom.nextRoomServer.enums;

import java.util.Arrays;
import java.util.Objects;

public enum SubscriptionPlan implements EnumModel {
MINI("mini_subscription", "미니", "2개의 테마를 등록할 수 있어요", 19900, 9900),
MEDIUM("medium_subscription", "미디움", "5개의 테마를 등록할 수 있어요", 29900, 14900),
Expand Down Expand Up @@ -49,4 +52,9 @@ public Integer getSellPrice() {
return sellPrice;
}

public static SubscriptionPlan getSubscriptionPlanByPlanId(String planId) {
return Arrays.stream(SubscriptionPlan.values())
.filter(subscriptionPlan -> Objects.equals(subscriptionPlan.getId(), planId))
.toList().get(0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@

public interface SubscriptionRepository extends JpaRepository<Subscription, Long> {
Optional<Subscription> findByShopId(Long id);
Optional<Subscription> findByPurchaseToken(String purchaseToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
import static com.nextroom.nextRoomServer.enums.UserStatus.*;
import static com.nextroom.nextRoomServer.exceptions.StatusCode.*;

import java.io.IOException;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.api.services.androidpublisher.model.SubscriptionPurchaseV2;
import com.nextroom.nextRoomServer.domain.Shop;
import com.nextroom.nextRoomServer.domain.Subscription;
import com.nextroom.nextRoomServer.dto.SubscriptionDto;
Expand All @@ -22,6 +26,7 @@
import com.nextroom.nextRoomServer.repository.ShopRepository;
import com.nextroom.nextRoomServer.repository.SubscriptionRepository;
import com.nextroom.nextRoomServer.security.SecurityUtil;
import com.nextroom.nextRoomServer.util.AndroidPublisherClient;
import com.nextroom.nextRoomServer.util.Timestamped;

import lombok.RequiredArgsConstructor;
Expand All @@ -31,14 +36,22 @@
public class SubscriptionService {
private final SubscriptionRepository subscriptionRepository;
private final ShopRepository shopRepository;
private AndroidPublisherClient androidPublisherClient;

{
try {
androidPublisherClient = new AndroidPublisherClient();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

public void test() {
Shop shop = shopRepository.findByAdminCode("12321").orElseThrow(
() -> new RuntimeException("ERROR"));

Subscription entity = Subscription.builder()
.shop(shop)
.googleId("test")
.status(SUBSCRIPTION)
.plan(MINI)
.expiryDate(LocalDate.now().plusDays(30))
Expand Down Expand Up @@ -91,4 +104,50 @@ private List<SubscriptionDto.SubscriptionPlanResponse> toEnumValues(Class<? exte
.map(SubscriptionDto.SubscriptionPlanResponse::new)
.collect(Collectors.toList());
}

public void purchaseSubscription(String purchaseToken, String subscriptionId) throws IOException {
Long shopId = SecurityUtil.getRequestedShopId();
Shop shop = shopRepository.findById(shopId).orElseThrow(() -> new CustomException(TARGET_HINT_NOT_FOUND));

SubscriptionPurchaseV2 purchase = androidPublisherClient.getSubscriptionPurchase(purchaseToken);

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
ZonedDateTime zonedDateTime = ZonedDateTime.parse(purchase.getLineItems().get(0).getExpiryTime(), formatter);
LocalDate expiryDate = zonedDateTime.toLocalDate();

String planId = purchase.getLineItems().get(0).getOfferDetails().getBasePlanId();

Subscription subscription = Subscription.builder()
.shop(shop)
.status(SUBSCRIPTION)
.plan(SubscriptionPlan.getSubscriptionPlanByPlanId(planId))
.expiryDate(expiryDate)
.purchaseToken(purchaseToken)
.build();

subscriptionRepository.save(subscription);

androidPublisherClient.acknowledgePurchase(purchaseToken, subscriptionId);
}

public void renew(String purchaseToken, String subscriptionId) throws IOException {
Subscription subscription = subscriptionRepository.findByPurchaseToken(purchaseToken)
.orElseThrow(() -> new CustomException(TARGET_SHOP_NOT_FOUND));

SubscriptionPurchaseV2 purchase = androidPublisherClient.getSubscriptionPurchase(purchaseToken);

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
ZonedDateTime zonedDateTime = ZonedDateTime.parse(purchase.getLineItems().get(0).getExpiryTime(), formatter);
LocalDate expiryDate = zonedDateTime.toLocalDate();

subscription.renew(expiryDate);

androidPublisherClient.acknowledgePurchase(purchaseToken, subscriptionId);
}

public void expire(String purchaseToken) {
Subscription subscription = subscriptionRepository.findByPurchaseToken(purchaseToken)
.orElseThrow(() -> new CustomException(TARGET_SHOP_NOT_FOUND));
subscription.expire();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.androidpublisher.AndroidPublisher;
import com.google.api.services.androidpublisher.model.SubscriptionPurchaseV2;
import com.google.api.services.androidpublisher.model.SubscriptionPurchasesAcknowledgeRequest;

public class AndroidPublisherClient {

Expand Down Expand Up @@ -51,11 +52,18 @@ public AndroidPublisherClient() throws Exception {
androidPublisher = initializeAndroidPublisher();
}

public SubscriptionPurchaseV2 getSubscriptionPurchase(String subscriptionId, String purchaseToken) throws
public SubscriptionPurchaseV2 getSubscriptionPurchase(String purchaseToken) throws
IOException {
return androidPublisher
.purchases()
.subscriptionsv2()
.get(PACKAGE_NAME, purchaseToken).execute();
}

public void acknowledgePurchase(String purchaseToken, String subscriptionId) throws IOException {
SubscriptionPurchasesAcknowledgeRequest request = new SubscriptionPurchasesAcknowledgeRequest();
androidPublisher.purchases()
.subscriptions()
.acknowledge(PACKAGE_NAME, subscriptionId, purchaseToken, request);
}
}

0 comments on commit b61a7bc

Please sign in to comment.