From d806437105dd0c720abaa6f880e9e3f04bc11d29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=A4=80?= <sanbonai06@naver.com>
Date: Tue, 6 Sep 2022 19:23:54 +0900
Subject: [PATCH] =?UTF-8?q?feat:=20=EC=95=8C=EB=A6=BC=20=EA=B4=80=EB=A0=A8?=
 =?UTF-8?q?=20API=202=EA=B0=9C=20=EC=B6=94=EA=B0=80=20#189?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/ceos/bankids/constant/ErrorCode.java  |  3 ++
 .../controller/NotificationController.java    | 27 ++++++++++++
 .../com/ceos/bankids/domain/Notification.java | 10 ++++-
 .../com/ceos/bankids/dto/NotificationDTO.java | 41 +++++++++++++++++++
 .../repository/NotificationRepository.java    |  2 +
 .../service/ExpoNotificationService.java      |  6 +++
 .../service/ExpoNotificationServiceImpl.java  | 30 ++++++++++++++
 7 files changed, 118 insertions(+), 1 deletion(-)
 create mode 100644 src/main/java/com/ceos/bankids/dto/NotificationDTO.java

diff --git a/src/main/java/com/ceos/bankids/constant/ErrorCode.java b/src/main/java/com/ceos/bankids/constant/ErrorCode.java
index 8f2603ce..f9c26488 100644
--- a/src/main/java/com/ceos/bankids/constant/ErrorCode.java
+++ b/src/main/java/com/ceos/bankids/constant/ErrorCode.java
@@ -61,6 +61,9 @@ public enum ErrorCode implements EnumMapperType {
     NOTIFICATION_MESSAGE_ERROR("E500-70001"),
     NOTIFICATION_SERVICE_ERROR("E500-70002"),
     NOTIFICATION_ACCESSCODE_ERROR("E500-70003"),
+    NOT_EXIST_NOTIFICATION_ERROR("E400-70004"),
+    ALREADY_READ_NOTIFICATION_ERROR("E400-70005"),
+    NOT_MATCH_NOTIFICATION_USER_ERROR("E403-70006"),
 
     // Notice
     NOT_EXIST_NOTICE_ERROR("E400-90001"),
diff --git a/src/main/java/com/ceos/bankids/controller/NotificationController.java b/src/main/java/com/ceos/bankids/controller/NotificationController.java
index cede7c0e..f2713451 100644
--- a/src/main/java/com/ceos/bankids/controller/NotificationController.java
+++ b/src/main/java/com/ceos/bankids/controller/NotificationController.java
@@ -7,6 +7,7 @@
 import com.ceos.bankids.domain.FamilyUser;
 import com.ceos.bankids.domain.User;
 import com.ceos.bankids.dto.AllSendNotificationDTO;
+import com.ceos.bankids.dto.NotificationDTO;
 import com.ceos.bankids.repository.UserRepository;
 import com.ceos.bankids.service.ExpoNotificationServiceImpl;
 import com.ceos.bankids.service.NoticeServiceImpl;
@@ -18,6 +19,9 @@
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PatchMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -51,6 +55,29 @@ public CommonResponse<String> allSendNotification(
         return CommonResponse.onSuccess("NOTIFICATION SUCCESS");
     }
 
+    @ApiOperation(value = "유저 알림 리스트 가져오기")
+    @GetMapping(produces = "application/json; charset=utf-8")
+    public CommonResponse<List<NotificationDTO>> getNotificationList(
+        @AuthenticationPrincipal User authUser) {
+
+        log.info("api = 유저 알림 리스트 가져오기 user = {}", authUser.getUsername());
+        List<NotificationDTO> notificationListDTOS = expoNotificationService.readNotificationList(
+            authUser);
+        return CommonResponse.onSuccess(notificationListDTOS);
+    }
+
+    @ApiOperation(value = "유저 알림 읽음 확인")
+    @PatchMapping(value = "/{notificationId}", produces = "application/json; charset=utf-8")
+    public CommonResponse<NotificationDTO> patchNotification(@AuthenticationPrincipal User authUser,
+        @PathVariable Long notificationId) {
+
+        log.info("api = 유저 알림 읽음 처리 user = {} notification = {}", authUser.getUsername(),
+            notificationId);
+        NotificationDTO notificationDTO = expoNotificationService.updateNotification(authUser,
+            notificationId);
+        return CommonResponse.onSuccess(notificationDTO);
+    }
+
     @Async
     @ApiOperation(value = "돈길 상태 변경 알림")
     public void notification(Challenge challenge, User authUser) {
diff --git a/src/main/java/com/ceos/bankids/domain/Notification.java b/src/main/java/com/ceos/bankids/domain/Notification.java
index 5cc36b94..5035fe56 100644
--- a/src/main/java/com/ceos/bankids/domain/Notification.java
+++ b/src/main/java/com/ceos/bankids/domain/Notification.java
@@ -14,6 +14,8 @@
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
+import org.hibernate.annotations.ColumnDefault;
+import org.hibernate.annotations.DynamicInsert;
 
 @Getter
 @Setter
@@ -21,6 +23,7 @@
 @Table(name = "Notification")
 @NoArgsConstructor
 @EqualsAndHashCode(of = "id")
+@DynamicInsert
 public class Notification extends AbstractTimestamp {
 
     @Id
@@ -33,6 +36,10 @@ public class Notification extends AbstractTimestamp {
     @Column
     private String message;
 
+    @Column(nullable = false)
+    @ColumnDefault(value = "false")
+    private Boolean isRead;
+
     @ManyToOne(fetch = FetchType.LAZY)
     @JoinColumn(name = "userId", nullable = false)
     private User user;
@@ -42,12 +49,13 @@ public Notification(
         Long id,
         String title,
         String message,
-        Challenge challenge,
+        Boolean isRead,
         User user
     ) {
         this.id = id;
         this.title = title;
         this.message = message;
+        this.isRead = isRead;
         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
new file mode 100644
index 00000000..34eedaef
--- /dev/null
+++ b/src/main/java/com/ceos/bankids/dto/NotificationDTO.java
@@ -0,0 +1,41 @@
+package com.ceos.bankids.dto;
+
+import com.ceos.bankids.domain.Notification;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.sql.Timestamp;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+@ApiModel(value = "알림 리스트로 줄 때 DTO")
+@Getter
+@ToString
+@EqualsAndHashCode
+public class NotificationDTO {
+
+    @ApiModelProperty(example = "1")
+    private Long id;
+
+    @ApiModelProperty(example = "알림 제목")
+    private String title;
+
+    @ApiModelProperty(example = "알림 내용")
+    private String message;
+
+    @ApiModelProperty(example = "false")
+    private Boolean isRead;
+
+    @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;
+
+    public NotificationDTO(Notification notification) {
+        this.id = notification.getId();
+        this.title = notification.getTitle();
+        this.message = notification.getMessage();
+        this.isRead = notification.getIsRead();
+        this.createdAt = notification.getCreatedAt();
+    }
+}
diff --git a/src/main/java/com/ceos/bankids/repository/NotificationRepository.java b/src/main/java/com/ceos/bankids/repository/NotificationRepository.java
index 0172c001..6c93fa07 100644
--- a/src/main/java/com/ceos/bankids/repository/NotificationRepository.java
+++ b/src/main/java/com/ceos/bankids/repository/NotificationRepository.java
@@ -1,10 +1,12 @@
 package com.ceos.bankids.repository;
 
 import com.ceos.bankids.domain.Notification;
+import java.util.List;
 import org.springframework.data.jpa.repository.JpaRepository;
 
 
 public interface NotificationRepository extends
     JpaRepository<Notification, Long> {
 
+    public List<Notification> findAllByUserId(Long userId);
 }
diff --git a/src/main/java/com/ceos/bankids/service/ExpoNotificationService.java b/src/main/java/com/ceos/bankids/service/ExpoNotificationService.java
index fe7ec116..420e23f4 100644
--- a/src/main/java/com/ceos/bankids/service/ExpoNotificationService.java
+++ b/src/main/java/com/ceos/bankids/service/ExpoNotificationService.java
@@ -1,8 +1,14 @@
 package com.ceos.bankids.service;
 
+import com.ceos.bankids.domain.User;
+import com.ceos.bankids.dto.NotificationDTO;
+import java.util.List;
 import org.springframework.stereotype.Service;
 
 @Service
 public interface ExpoNotificationService {
 
+    public List<NotificationDTO> readNotificationList(User user);
+
+    public NotificationDTO updateNotification(User user, Long notificationId);
 }
diff --git a/src/main/java/com/ceos/bankids/service/ExpoNotificationServiceImpl.java b/src/main/java/com/ceos/bankids/service/ExpoNotificationServiceImpl.java
index f09b5cbb..1d9d717b 100644
--- a/src/main/java/com/ceos/bankids/service/ExpoNotificationServiceImpl.java
+++ b/src/main/java/com/ceos/bankids/service/ExpoNotificationServiceImpl.java
@@ -3,7 +3,9 @@
 import com.ceos.bankids.constant.ErrorCode;
 import com.ceos.bankids.domain.Notification;
 import com.ceos.bankids.domain.User;
+import com.ceos.bankids.dto.NotificationDTO;
 import com.ceos.bankids.exception.BadRequestException;
+import com.ceos.bankids.exception.ForbiddenException;
 import com.ceos.bankids.exception.InternalServerException;
 import com.ceos.bankids.repository.NotificationRepository;
 import io.github.jav.exposerversdk.ExpoPushMessage;
@@ -15,6 +17,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.stream.Collectors;
@@ -22,6 +25,7 @@
 import lombok.extern.slf4j.Slf4j;
 import org.hibernate.exception.GenericJDBCException;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 @Slf4j
 @Service
@@ -30,6 +34,32 @@ public class ExpoNotificationServiceImpl implements ExpoNotificationService {
 
     private final NotificationRepository notificationRepository;
 
+    @Transactional
+    @Override
+    public List<NotificationDTO> readNotificationList(User user) {
+        return notificationRepository.findAllByUserId(user.getId())
+            .stream().map(NotificationDTO::new)
+            .collect(
+                Collectors.toList());
+    }
+
+    @Transactional
+    @Override
+    public NotificationDTO updateNotification(User user, Long notificationId) {
+        Notification notification = notificationRepository.findById(notificationId).orElseThrow(
+            () -> new BadRequestException(ErrorCode.NOT_EXIST_NOTIFICATION_ERROR.getErrorCode()));
+        if (notification.getIsRead()) {
+            throw new BadRequestException(ErrorCode.ALREADY_READ_NOTIFICATION_ERROR.getErrorCode());
+        }
+        if (!Objects.equals(notification.getUser().getId(), user.getId())) {
+            throw new ForbiddenException(
+                ErrorCode.NOT_MATCH_NOTIFICATION_USER_ERROR.getErrorCode());
+        }
+        notification.setIsRead(true);
+        notificationRepository.save(notification);
+        return new NotificationDTO(notification);
+    }
+
     public void sendMessage(User user, String title, String body, Map<String, Object> data) {
 
         String token = user.getExpoToken();