diff --git a/src/main/java/com/ceos/bankids/constant/NotificationCategory.java b/src/main/java/com/ceos/bankids/constant/NotificationCategory.java new file mode 100644 index 00000000..126460b6 --- /dev/null +++ b/src/main/java/com/ceos/bankids/constant/NotificationCategory.java @@ -0,0 +1,19 @@ +package com.ceos.bankids.constant; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum NotificationCategory implements EnumMapperType { + + CHALLENGE, + LEVEL, + NOTICE, + FAMILY; + + @Override + public String getCode() { + return name(); + } +} diff --git a/src/main/java/com/ceos/bankids/controller/NotificationController.java b/src/main/java/com/ceos/bankids/controller/NotificationController.java index 15170e45..341bde8f 100644 --- a/src/main/java/com/ceos/bankids/controller/NotificationController.java +++ b/src/main/java/com/ceos/bankids/controller/NotificationController.java @@ -3,6 +3,7 @@ import com.ceos.bankids.config.CommonResponse; import com.ceos.bankids.constant.ChallengeStatus; import com.ceos.bankids.constant.ErrorCode; +import com.ceos.bankids.constant.NotificationCategory; import com.ceos.bankids.domain.Challenge; import com.ceos.bankids.domain.ChallengeUser; import com.ceos.bankids.domain.FamilyUser; @@ -10,6 +11,7 @@ import com.ceos.bankids.domain.User; import com.ceos.bankids.dto.AllSendNotificationDTO; import com.ceos.bankids.dto.NotificationDTO; +import com.ceos.bankids.dto.NotificationIsReadDTO; import com.ceos.bankids.dto.NotificationListDTO; import com.ceos.bankids.exception.ForbiddenException; import com.ceos.bankids.repository.NotificationRepository; @@ -56,16 +58,17 @@ public CommonResponse allSendNotification( String title = allSendNotificationRequest.getTitle(); String message = allSendNotificationRequest.getMessage(); + NotificationCategory notificationCategory = NotificationCategory.NOTICE; userRepository.findAll().stream() .filter(user -> user.getExpoToken() != null && !Objects.equals(user.getExpoToken(), "web")) .forEach(user -> { if (user.getNoticeOptIn()) { expoNotificationService.sendMessage(user, title, message, - allSendNotificationRequest.getNewMap()); + allSendNotificationRequest.getNewMap(), notificationCategory); } else { Notification notification = Notification.builder().user(user).title(title) - .message(message).build(); + .message(message).notificationCategory(notificationCategory).build(); notificationRepository.save(notification); } }); @@ -83,6 +86,18 @@ public CommonResponse getNotificationList( return CommonResponse.onSuccess(notificationListDTOS); } + @ApiOperation(value = "유저 안읽은 알림 있는지 확인") + @GetMapping(value = "/isRead", produces = "application/json; charset=utf-8") + public CommonResponse getNotificationIsAllRead( + @AuthenticationPrincipal User authUser) { + + log.info("api = 안읽은 알림 있는지 확인 user = {}", authUser.getId()); + NotificationIsReadDTO notificationIsReadDTO = expoNotificationService.readNotificationIsAllRead( + authUser); + return CommonResponse.onSuccess(notificationIsReadDTO); + } + + @ApiOperation(value = "유저 알림 읽음 확인") @PatchMapping(value = "/{notificationId}", produces = "application/json; charset=utf-8") public CommonResponse patchNotification(@AuthenticationPrincipal User authUser, @@ -109,9 +124,12 @@ public void notification(Challenge challenge, User authUser) { HashMap newMap = new HashMap<>(); newMap.put("challengeId", challenge.getId()); newMap.put("userId", authUser.getId()); - Boolean checkServiceOptIn = checkServiceOptIn(authUser, title, notificationBody); + NotificationCategory notificationCategory = NotificationCategory.CHALLENGE; + Boolean checkServiceOptIn = checkServiceOptIn(authUser, title, notificationBody, + notificationCategory); if (checkServiceOptIn) { - expoNotificationService.sendMessage(authUser, title, notificationBody, newMap); + expoNotificationService.sendMessage(authUser, title, notificationBody, newMap, + notificationCategory); } log.info("유저 {}의 돈길 {}의 {} 상태변경 알림", authUser.getId(), challenge.getId(), challenge.getChallengeStatus()); @@ -125,9 +143,12 @@ public void userLevelUpMinusOne(User authUser) { String notificationBody = "레벨업하기까지 \uD83D\uDD381 개\uD83D\uDD38의 돈길만 완주하면 돼요"; HashMap newMap = new HashMap<>(); newMap.put("userId", authUser.getId()); - Boolean checkServiceOptIn = checkServiceOptIn(authUser, title, notificationBody); + NotificationCategory notificationCategory = NotificationCategory.LEVEL; + Boolean checkServiceOptIn = checkServiceOptIn(authUser, title, notificationBody, + notificationCategory); if (checkServiceOptIn) { - expoNotificationService.sendMessage(authUser, title, notificationBody, newMap); + expoNotificationService.sendMessage(authUser, title, notificationBody, newMap, + notificationCategory); } log.info("유저 id = {}의 레벨업 직전 알림", authUser.getId()); } @@ -141,9 +162,12 @@ public void userLevelUpHalf(User authUser) { HashMap newMap = new HashMap<>(); newMap.put("userId", authUser.getId()); - Boolean checkServiceOptIn = checkServiceOptIn(authUser, title, notificationBody); + NotificationCategory notificationCategory = NotificationCategory.LEVEL; + Boolean checkServiceOptIn = checkServiceOptIn(authUser, title, notificationBody, + notificationCategory); if (checkServiceOptIn) { - expoNotificationService.sendMessage(authUser, title, notificationBody, newMap); + expoNotificationService.sendMessage(authUser, title, notificationBody, newMap, + notificationCategory); } log.info("유저 id = {}의 레벨업 절반 달성 알림", authUser.getId()); } @@ -158,9 +182,12 @@ public void createPendingChallengeNotification(User contractUser, ChallengeUser HashMap newMap = new HashMap<>(); newMap.put("user", challengeUser.getUser().getId()); newMap.put("challenge", challengeUser.getChallenge().getId()); - Boolean checkServiceOptIn = checkServiceOptIn(contractUser, title, notificationBody); + NotificationCategory notificationCategory = NotificationCategory.CHALLENGE; + Boolean checkServiceOptIn = checkServiceOptIn(contractUser, title, notificationBody, + notificationCategory); if (checkServiceOptIn) { - expoNotificationService.sendMessage(contractUser, title, notificationBody, newMap); + expoNotificationService.sendMessage(contractUser, title, notificationBody, newMap, + notificationCategory); } log.info("부모 유저 id = {}에게 유저 id = {} 돈길 id = {} 의 돈길 제안", contractUser.getId(), challengeUser.getUser().getId(), challengeUser.getChallenge().getId()); @@ -176,9 +203,12 @@ public void runProgressNotification(User contractUser, ChallengeUser challengeUs HashMap newMap = new HashMap<>(); newMap.put("user", challengeUser.getUser().getId()); newMap.put("challenge", challengeUser.getChallenge().getId()); - Boolean checkServiceOptIn = checkServiceOptIn(contractUser, title, notificationBody); + NotificationCategory notificationCategory = NotificationCategory.CHALLENGE; + Boolean checkServiceOptIn = checkServiceOptIn(contractUser, title, notificationBody, + notificationCategory); if (checkServiceOptIn) { - expoNotificationService.sendMessage(contractUser, title, notificationBody, newMap); + expoNotificationService.sendMessage(contractUser, title, notificationBody, newMap, + notificationCategory); } log.info("부모 유저 id = {}에게 유저 id = {}의 돈길 id = {} 돈길 걷기 알림 전송", contractUser.getId(), challengeUser.getUser().getId(), challengeUser.getChallenge().getId()); @@ -195,9 +225,12 @@ public void achieveChallengeNotification(User contractUser, ChallengeUser challe HashMap newMap = new HashMap<>(); newMap.put("user", challengeUser.getUser().getId()); newMap.put("challenge", challengeUser.getChallenge().getId()); - Boolean checkServiceOptIn = checkServiceOptIn(contractUser, title, notificationBody); + NotificationCategory notificationCategory = NotificationCategory.CHALLENGE; + Boolean checkServiceOptIn = checkServiceOptIn(contractUser, title, notificationBody, + notificationCategory); if (checkServiceOptIn) { - expoNotificationService.sendMessage(contractUser, title, notificationBody, newMap); + expoNotificationService.sendMessage(contractUser, title, notificationBody, newMap, + notificationCategory); } log.info("부모 유저 id = {}에게 유저 id = {}의 돈길 id = {} 돈길 완주 알림 전송", contractUser.getId(), challengeUser.getUser().getId(), challengeUser.getChallenge().getId()); @@ -212,9 +245,12 @@ public void kidLevelUpNotification(User contractUser, User user, Long level, Lon user.getUsername() + "님이 레벨" + level + "에서 레벨" + afterLevel + "로 올랐어요! 확인해볼까요?"; HashMap newMap = new HashMap<>(); newMap.put("user", user.getId()); - Boolean checkServiceOptIn = checkServiceOptIn(contractUser, title, notificationBody); + NotificationCategory notificationCategory = NotificationCategory.LEVEL; + Boolean checkServiceOptIn = checkServiceOptIn(contractUser, title, notificationBody, + notificationCategory); if (checkServiceOptIn) { - expoNotificationService.sendMessage(contractUser, title, notificationBody, newMap); + expoNotificationService.sendMessage(contractUser, title, notificationBody, newMap, + notificationCategory); } log.info("부모 유저 id = {}에게 유저 id = {}의 레벨업 알림 전송", contractUser.getId(), user.getId()); } @@ -228,9 +264,12 @@ public void challengeFailedNotification(User contractUser, ChallengeUser challen HashMap newMap = new HashMap<>(); newMap.put("user", challengeUser.getUser().getId()); newMap.put("challenge", challengeUser.getChallenge().getId()); - Boolean checkServiceOptIn = checkServiceOptIn(contractUser, title, notificationBody); + NotificationCategory notificationCategory = NotificationCategory.CHALLENGE; + Boolean checkServiceOptIn = checkServiceOptIn(contractUser, title, notificationBody, + notificationCategory); if (checkServiceOptIn) { - expoNotificationService.sendMessage(contractUser, title, notificationBody, newMap); + expoNotificationService.sendMessage(contractUser, title, notificationBody, newMap, + notificationCategory); } log.info("부모 유저 id = {}에게 유저 id = {}의 돈길 id = {} 돈길 실패 알림 전송", contractUser.getId(), challengeUser.getChallenge().getId(), challengeUser.getChallenge().getId()); @@ -242,21 +281,26 @@ public void newFamilyUserNotification(User newFamilyUser, List famil String title = "가족그룹\uD83D\uDC68\u200D\uD83D\uDC69\u200D\uD83D\uDC67\u200D\uD83D\uDC66에 새로 참여했어요"; String notificationBody = "누가 가족그룹에 참여했는지 확인해요!\uD83D\uDCAB"; HashMap newMap = new HashMap<>(); + NotificationCategory notificationCategory = NotificationCategory.FAMILY; // newMap.put("user", newFamilyUser.getId()); familyUserList.forEach(familyUser -> { User user = familyUser.getUser(); - Boolean checkServiceOptIn = checkServiceOptIn(user, title, notificationBody); + Boolean checkServiceOptIn = checkServiceOptIn(user, title, notificationBody, + notificationCategory); if (checkServiceOptIn) { - expoNotificationService.sendMessage(user, title, notificationBody, newMap); + expoNotificationService.sendMessage(user, title, notificationBody, newMap, + notificationCategory); } log.info("기존 가족 구성원 id = {}에게 유저 id = {}의 가족 참여 알림 전송", familyUser.getUser().getId(), newFamilyUser.getId()); }); } - private Boolean checkServiceOptIn(User user, String title, String body) { + private Boolean checkServiceOptIn(User user, String title, String body, + NotificationCategory notificationCategory) { if (!user.getServiceOptIn()) { Notification notification = Notification.builder().user(user).title(title).message(body) + .notificationCategory(notificationCategory) .build(); notificationRepository.save(notification); return false; diff --git a/src/main/java/com/ceos/bankids/domain/Notification.java b/src/main/java/com/ceos/bankids/domain/Notification.java index 5035fe56..d2e437e5 100644 --- a/src/main/java/com/ceos/bankids/domain/Notification.java +++ b/src/main/java/com/ceos/bankids/domain/Notification.java @@ -1,7 +1,10 @@ package com.ceos.bankids.domain; +import com.ceos.bankids.constant.NotificationCategory; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @@ -40,6 +43,10 @@ public class Notification extends AbstractTimestamp { @ColumnDefault(value = "false") private Boolean isRead; + @Column(nullable = false) + @Enumerated(EnumType.STRING) + private NotificationCategory notificationCategory; + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "userId", nullable = false) private User user; @@ -50,12 +57,15 @@ public Notification( String title, String message, Boolean isRead, + NotificationCategory notificationCategory, User user ) { + this.id = id; this.title = title; this.message = message; this.isRead = isRead; + this.notificationCategory = notificationCategory; this.user = user; } } diff --git a/src/main/java/com/ceos/bankids/dto/NotificationDTO.java b/src/main/java/com/ceos/bankids/dto/NotificationDTO.java index 841dc0fc..41be840e 100644 --- a/src/main/java/com/ceos/bankids/dto/NotificationDTO.java +++ b/src/main/java/com/ceos/bankids/dto/NotificationDTO.java @@ -1,5 +1,6 @@ package com.ceos.bankids.dto; +import com.ceos.bankids.constant.NotificationCategory; import com.ceos.bankids.domain.Notification; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; @@ -27,6 +28,9 @@ public class NotificationDTO { @ApiModelProperty(example = "false") private Boolean isRead; + @ApiModelProperty(example = "CHALLENGE") + private NotificationCategory notificationCategory; + @ApiModelProperty(example = "2022/07/05 05:05:05") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy/MM/dd hh:mm:ss", timezone = "Asia/Seoul") private Timestamp createdAt; @@ -36,6 +40,7 @@ public NotificationDTO(Notification notification) { this.title = notification.getTitle(); this.message = notification.getMessage(); this.isRead = notification.getIsRead(); + this.notificationCategory = notification.getNotificationCategory(); this.createdAt = notification.getCreatedAt(); } } diff --git a/src/main/java/com/ceos/bankids/dto/NotificationIsReadDTO.java b/src/main/java/com/ceos/bankids/dto/NotificationIsReadDTO.java new file mode 100644 index 00000000..3af5ba5f --- /dev/null +++ b/src/main/java/com/ceos/bankids/dto/NotificationIsReadDTO.java @@ -0,0 +1,21 @@ +package com.ceos.bankids.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@ApiModel(value = "읽지 않은 알림 확인 DTO") +@Getter +@ToString +@EqualsAndHashCode +public class NotificationIsReadDTO { + + @ApiModelProperty(example = "true") + private Boolean isAllRead; + + public NotificationIsReadDTO(Boolean isAllRead) { + this.isAllRead = isAllRead; + } +} diff --git a/src/main/java/com/ceos/bankids/repository/NotificationRepository.java b/src/main/java/com/ceos/bankids/repository/NotificationRepository.java index d78689fe..94e234fa 100644 --- a/src/main/java/com/ceos/bankids/repository/NotificationRepository.java +++ b/src/main/java/com/ceos/bankids/repository/NotificationRepository.java @@ -12,7 +12,7 @@ public interface NotificationRepository extends public List findAllByUserId(Long userId); // @Query("select n from Notification n where n.id < ") - public Page findByIdLessThanAndUserIdOrderByIdDesc(Long id, Long userId, + public Page findByIdLessThanEqualAndUserIdOrderByIdDesc(Long id, Long userId, Pageable pageRequest); public Page findByUserIdOrderByIdDesc(Long userId, Pageable pageRequest); diff --git a/src/main/java/com/ceos/bankids/service/ExpoNotificationService.java b/src/main/java/com/ceos/bankids/service/ExpoNotificationService.java index 8f88d001..690fd503 100644 --- a/src/main/java/com/ceos/bankids/service/ExpoNotificationService.java +++ b/src/main/java/com/ceos/bankids/service/ExpoNotificationService.java @@ -2,6 +2,7 @@ import com.ceos.bankids.domain.User; import com.ceos.bankids.dto.NotificationDTO; +import com.ceos.bankids.dto.NotificationIsReadDTO; import com.ceos.bankids.dto.NotificationListDTO; import org.springframework.stereotype.Service; @@ -11,4 +12,6 @@ public interface ExpoNotificationService { public NotificationListDTO readNotificationList(User user, Long lastId); public NotificationDTO updateNotification(User user, Long notificationId); + + public NotificationIsReadDTO readNotificationIsAllRead(User user); } diff --git a/src/main/java/com/ceos/bankids/service/ExpoNotificationServiceImpl.java b/src/main/java/com/ceos/bankids/service/ExpoNotificationServiceImpl.java index 0bd1e744..0bbb5bd7 100644 --- a/src/main/java/com/ceos/bankids/service/ExpoNotificationServiceImpl.java +++ b/src/main/java/com/ceos/bankids/service/ExpoNotificationServiceImpl.java @@ -1,9 +1,11 @@ package com.ceos.bankids.service; import com.ceos.bankids.constant.ErrorCode; +import com.ceos.bankids.constant.NotificationCategory; import com.ceos.bankids.domain.Notification; import com.ceos.bankids.domain.User; import com.ceos.bankids.dto.NotificationDTO; +import com.ceos.bankids.dto.NotificationIsReadDTO; import com.ceos.bankids.dto.NotificationListDTO; import com.ceos.bankids.exception.BadRequestException; import com.ceos.bankids.exception.ForbiddenException; @@ -56,12 +58,12 @@ public NotificationListDTO readNotificationList(User user, Long lastId) { return new NotificationListDTO(lastNotificationId, true, notificationDTOS); } } - List notificationDTOList = notificationRepository.findByIdLessThanAndUserIdOrderByIdDesc( + List notificationDTOList = notificationRepository.findByIdLessThanEqualAndUserIdOrderByIdDesc( lastId, user.getId(), pageRequest).stream() .map(NotificationDTO::new).collect(Collectors.toList()); NotificationDTO lastNotification = notificationDTOList.get(notificationDTOList.size() - 1); Long last = lastNotification.getId(); - if (notificationDTOList.size() <= 11L) { + if (notificationDTOList.size() == 11L) { notificationDTOList.remove(10); return new NotificationListDTO(last, false, notificationDTOList); } else { @@ -86,12 +88,28 @@ public NotificationDTO updateNotification(User user, Long notificationId) { return new NotificationDTO(notification); } + @Transactional(readOnly = true) + @Override + public NotificationIsReadDTO readNotificationIsAllRead(User user) { + + List notificationList = notificationRepository.findAllByUserId(user.getId()) + .stream() + .filter(notification -> !notification.getIsRead()).collect( + Collectors.toList()); + if (notificationList.size() == 0) { + return new NotificationIsReadDTO(true); + } else { + return new NotificationIsReadDTO(false); + } + } + @Transactional public void deleteAllNotification(User user) { notificationRepository.deleteAllByUserId(user.getId()); } - public void sendMessage(User user, String title, String body, Map data) { + public void sendMessage(User user, String title, String body, Map data, + NotificationCategory notificationCategory) { String token = user.getExpoToken(); if (token == null) { @@ -123,7 +141,7 @@ public void sendMessage(User user, String title, String body, Map allTickets = new ArrayList<>(); for (CompletableFuture> messageReplyFuture : messageRepliesFutures) {