diff --git a/src/main/java/com/example/repick/domain/clothingSales/entity/BagCollect.java b/src/main/java/com/example/repick/domain/clothingSales/entity/BagCollect.java index 64c1f21d..a18a5000 100644 --- a/src/main/java/com/example/repick/domain/clothingSales/entity/BagCollect.java +++ b/src/main/java/com/example/repick/domain/clothingSales/entity/BagCollect.java @@ -15,4 +15,11 @@ public class BagCollect extends ClothingSales{ private Address initAddress; @Column(name = "bag_quantity") private Integer bagQuantity; + + @Column(name = "notify_count") + private int notifyCount = 0; + + public void updateNotifyCount(int notifyCount) { + this.notifyCount = notifyCount; + } } diff --git a/src/main/java/com/example/repick/domain/clothingSales/repository/BagCollectRepository.java b/src/main/java/com/example/repick/domain/clothingSales/repository/BagCollectRepository.java index f4ecb38c..5ef3ef02 100644 --- a/src/main/java/com/example/repick/domain/clothingSales/repository/BagCollectRepository.java +++ b/src/main/java/com/example/repick/domain/clothingSales/repository/BagCollectRepository.java @@ -3,5 +3,5 @@ import com.example.repick.domain.clothingSales.entity.BagCollect; import org.springframework.data.jpa.repository.JpaRepository; -public interface BagCollectRepository extends JpaRepository { +public interface BagCollectRepository extends JpaRepository, BagCollectRepositoryCustom { } \ No newline at end of file diff --git a/src/main/java/com/example/repick/domain/clothingSales/repository/BagCollectRepositoryCustom.java b/src/main/java/com/example/repick/domain/clothingSales/repository/BagCollectRepositoryCustom.java new file mode 100644 index 00000000..40907c04 --- /dev/null +++ b/src/main/java/com/example/repick/domain/clothingSales/repository/BagCollectRepositoryCustom.java @@ -0,0 +1,9 @@ +package com.example.repick.domain.clothingSales.repository; + +import com.example.repick.domain.clothingSales.entity.BagCollect; + +import java.util.List; + +public interface BagCollectRepositoryCustom { + List findNotProcessedBagCollects(); +} diff --git a/src/main/java/com/example/repick/domain/clothingSales/repository/BagCollectRepositoryImpl.java b/src/main/java/com/example/repick/domain/clothingSales/repository/BagCollectRepositoryImpl.java new file mode 100644 index 00000000..8d24ed3a --- /dev/null +++ b/src/main/java/com/example/repick/domain/clothingSales/repository/BagCollectRepositoryImpl.java @@ -0,0 +1,28 @@ +package com.example.repick.domain.clothingSales.repository; + +import com.example.repick.domain.clothingSales.entity.BagCollect; +import com.example.repick.domain.clothingSales.entity.ClothingSalesStateType; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +import java.time.LocalDateTime; +import java.util.List; + +import static com.example.repick.domain.clothingSales.entity.QBagCollect.bagCollect; + +@RequiredArgsConstructor +public class BagCollectRepositoryImpl implements BagCollectRepositoryCustom { + + private final JPAQueryFactory jpaQueryFactory; + + @Override + public List findNotProcessedBagCollects() { + return jpaQueryFactory.selectFrom(bagCollect) + .where( + bagCollect.clothingSalesState.in(ClothingSalesStateType.BEFORE_COLLECTION) + .and(bagCollect.createdDate.before(LocalDateTime.now().minusDays(7))) + ) + .fetch(); + } + +} diff --git a/src/main/java/com/example/repick/domain/clothingSales/scheduler/ClothingSalesScheduler.java b/src/main/java/com/example/repick/domain/clothingSales/scheduler/ClothingSalesScheduler.java new file mode 100644 index 00000000..212d6f10 --- /dev/null +++ b/src/main/java/com/example/repick/domain/clothingSales/scheduler/ClothingSalesScheduler.java @@ -0,0 +1,35 @@ +package com.example.repick.domain.clothingSales.scheduler; + +import com.example.repick.domain.clothingSales.entity.BagCollect; +import com.example.repick.domain.clothingSales.repository.BagCollectRepository; +import com.example.repick.global.aws.PushNotificationService; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component @RequiredArgsConstructor +public class ClothingSalesScheduler { + + private final BagCollectRepository bagCollectRepository; + private final PushNotificationService pushNotificationService; + + @Scheduled(cron = "0 0 5 * * *", zone = "Asia/Seoul") + public void checkNotProcessedBagInit() { + List bagCollects = bagCollectRepository.findNotProcessedBagCollects(); + + bagCollects.forEach(bagCollect -> { + int currentNotifyCount = bagCollect.getNotifyCount() + 1; + + if (currentNotifyCount == 1) { + pushNotificationService.sendPushNotification(bagCollect.getUser().getId(), "리픽백 수거를 진행해 보세요!", "지금 바로 진행해 볼까요?"); + } else if (currentNotifyCount == 7) { + currentNotifyCount = 0; + } + + bagCollect.updateNotifyCount(currentNotifyCount); + + }); + } +} diff --git a/src/main/java/com/example/repick/global/aws/PushNotificationService.java b/src/main/java/com/example/repick/global/aws/PushNotificationService.java new file mode 100644 index 00000000..47393c6f --- /dev/null +++ b/src/main/java/com/example/repick/global/aws/PushNotificationService.java @@ -0,0 +1,42 @@ +package com.example.repick.global.aws; + +import com.example.repick.domain.fcmtoken.entity.UserFcmTokenInfo; +import com.example.repick.dynamodb.UserFcmTokenInfoRepository; +import com.example.repick.global.error.exception.CustomException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import software.amazon.awssdk.core.SdkBytes; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.lambda.LambdaClient; +import software.amazon.awssdk.services.lambda.model.InvokeRequest; + +import static com.example.repick.global.error.exception.ErrorCode.USER_NOT_FOUND; + +@Service @RequiredArgsConstructor +public class PushNotificationService { + + private final UserFcmTokenInfoRepository userFcmTokenInfoRepository; + + public void sendPushNotification(Long userId, String title, String body) { + + LambdaClient awsLambda = LambdaClient.builder() + .region(Region.AP_NORTHEAST_2) + .build(); + + UserFcmTokenInfo userFcmTokenInfo = userFcmTokenInfoRepository.findById(userId) + .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); + + String json = String.format("{\"fcmToken\": \"%s\", \"title\": \"%s\", \"body\": \"%s\"}", userFcmTokenInfo.getFcmToken(), title, body); + + SdkBytes payload = SdkBytes.fromUtf8String(json); + + InvokeRequest request = InvokeRequest.builder() + .functionName("lambda_push_notification_single") + .payload(payload) + .build(); + + awsLambda.invoke(request); + + } + +} diff --git a/src/test/java/com/example/repick/pushnotification/PushNotificationServiceTest.java b/src/test/java/com/example/repick/pushnotification/PushNotificationServiceTest.java new file mode 100644 index 00000000..db3f9b7d --- /dev/null +++ b/src/test/java/com/example/repick/pushnotification/PushNotificationServiceTest.java @@ -0,0 +1,75 @@ +package com.example.repick.pushnotification; + +import com.example.repick.domain.clothingSales.entity.BagCollect; +import com.example.repick.domain.clothingSales.repository.BagCollectRepository; +import com.example.repick.domain.fcmtoken.entity.UserFcmTokenInfo; +import com.example.repick.dynamodb.UserFcmTokenInfoRepository; +import com.example.repick.global.aws.PushNotificationService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import software.amazon.awssdk.core.SdkBytes; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.lambda.LambdaClient; +import software.amazon.awssdk.services.lambda.model.InvokeRequest; +import software.amazon.awssdk.services.lambda.model.InvokeResponse; + +import java.util.List; + +@SpringBootTest +public class PushNotificationServiceTest { + + @Autowired + private UserFcmTokenInfoRepository userFcmTokenInfoRepository; + + @Autowired + private BagCollectRepository bagCollectRepository; + + @Autowired + private PushNotificationService pushNotificationService; + + @Test + public void notificationTest() { + LambdaClient awsLambda = LambdaClient.builder() + .region(Region.AP_NORTHEAST_2) + .build(); + + String fcmToken = userFcmTokenInfoRepository.findById(3L) + .map(UserFcmTokenInfo::getFcmToken) + .orElseThrow(); + + String json = String.format("{\"fcmToken\": \"%s\", \"title\": \"test\", \"body\": \"test\"}", fcmToken); + + SdkBytes payload = SdkBytes.fromUtf8String(json); + + InvokeRequest request = InvokeRequest.builder() + .functionName("lambda_push_notification_single") + .payload(payload) + .build(); + + InvokeResponse res = awsLambda.invoke(request); + + } + + @Test + public void pushNotificationServiceCronTest() { + List bagCollects = bagCollectRepository.findNotProcessedBagCollects(); + + bagCollects.forEach(bagCollect -> { + int currentNotifyCount = bagCollect.getNotifyCount() + 1; + + if (currentNotifyCount == 1) { + pushNotificationService.sendPushNotification(bagCollect.getUser().getId(), "리픽백 수거를 진행해 보세요!", "지금 바로 진행해 볼까요?"); + } else if (currentNotifyCount == 7) { + currentNotifyCount = 0; + } + + bagCollect.updateNotifyCount(currentNotifyCount); + + bagCollectRepository.save(bagCollect); + + }); + + } + +}