diff --git a/backend/src/main/java/com/twtw/backend/domain/notification/controller/NotificationController.java b/backend/src/main/java/com/twtw/backend/domain/notification/controller/NotificationController.java new file mode 100644 index 0000000..ecbd091 --- /dev/null +++ b/backend/src/main/java/com/twtw/backend/domain/notification/controller/NotificationController.java @@ -0,0 +1,30 @@ +package com.twtw.backend.domain.notification.controller; + +import com.twtw.backend.domain.notification.messagequeue.FcmProducer; + +import lombok.RequiredArgsConstructor; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +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.RestController; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequiredArgsConstructor +@RequestMapping("notifications") +public class NotificationController { + + private final FcmProducer fcmProducer; + + @PreAuthorize("hasRole('ADMIN')") + @PostMapping + public ResponseEntity sendNotification(@RequestBody final List ids) { + fcmProducer.sendFailedNotification(ids); + return ResponseEntity.noContent().build(); + } +} diff --git a/backend/src/main/java/com/twtw/backend/domain/notification/dto/NotificationRequest.java b/backend/src/main/java/com/twtw/backend/domain/notification/dto/NotificationRequest.java index dd68f25..c010d99 100644 --- a/backend/src/main/java/com/twtw/backend/domain/notification/dto/NotificationRequest.java +++ b/backend/src/main/java/com/twtw/backend/domain/notification/dto/NotificationRequest.java @@ -5,6 +5,8 @@ import com.google.firebase.messaging.Message; import com.google.firebase.messaging.Notification; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -12,6 +14,8 @@ @Getter @ToString +@Builder +@AllArgsConstructor @NoArgsConstructor public class NotificationRequest { diff --git a/backend/src/main/java/com/twtw/backend/domain/notification/entity/Notification.java b/backend/src/main/java/com/twtw/backend/domain/notification/entity/Notification.java index 5c3fd2e..280670f 100644 --- a/backend/src/main/java/com/twtw/backend/domain/notification/entity/Notification.java +++ b/backend/src/main/java/com/twtw/backend/domain/notification/entity/Notification.java @@ -39,6 +39,9 @@ public class Notification implements Auditable { @Column(nullable = false) private String idInfo; + @Column(nullable = false) + private String deviceToken; + @Column(nullable = false) @Enumerated(EnumType.STRING) private NotificationType type; @@ -52,10 +55,12 @@ public Notification( final String title, final String body, final String idInfo, + final String deviceToken, final NotificationType type) { this.title = title; this.body = body; this.idInfo = idInfo; + this.deviceToken = deviceToken; this.type = type; } diff --git a/backend/src/main/java/com/twtw/backend/domain/notification/mapper/NotificationMapper.java b/backend/src/main/java/com/twtw/backend/domain/notification/mapper/NotificationMapper.java new file mode 100644 index 0000000..e6782ed --- /dev/null +++ b/backend/src/main/java/com/twtw/backend/domain/notification/mapper/NotificationMapper.java @@ -0,0 +1,19 @@ +package com.twtw.backend.domain.notification.mapper; + +import com.twtw.backend.domain.notification.dto.NotificationRequest; +import com.twtw.backend.domain.notification.entity.Notification; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingConstants.ComponentModel; + +@Mapper(componentModel = ComponentModel.SPRING) +public interface NotificationMapper { + + @Mapping(target = "notificationId", source = "notification.id") + @Mapping(target = "deviceToken", source = "notification.notificationType") + @Mapping(target = "title", source = "notification.title") + @Mapping(target = "body", source = "notification.body") + @Mapping(target = "id", source = "notification.idInfo") + NotificationRequest toNotificationRequest(final Notification notification); +} diff --git a/backend/src/main/java/com/twtw/backend/domain/notification/messagequeue/FcmProducer.java b/backend/src/main/java/com/twtw/backend/domain/notification/messagequeue/FcmProducer.java index e92bd94..6278ddd 100644 --- a/backend/src/main/java/com/twtw/backend/domain/notification/messagequeue/FcmProducer.java +++ b/backend/src/main/java/com/twtw/backend/domain/notification/messagequeue/FcmProducer.java @@ -3,6 +3,7 @@ import com.twtw.backend.domain.notification.dto.NotificationRequest; import com.twtw.backend.domain.notification.entity.Notification; import com.twtw.backend.domain.notification.entity.NotificationType; +import com.twtw.backend.domain.notification.mapper.NotificationMapper; import com.twtw.backend.domain.notification.repository.NotificationRepository; import com.twtw.backend.global.constant.RabbitMQConstant; @@ -11,6 +12,7 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.stereotype.Component; +import java.util.List; import java.util.UUID; @Component @@ -19,6 +21,7 @@ public class FcmProducer { private final RabbitTemplate rabbitTemplate; private final NotificationRepository notificationRepository; + private final NotificationMapper notificationMapper; public void sendNotification(final NotificationRequest request, final NotificationType type) { final UUID id = @@ -28,14 +31,25 @@ public void sendNotification(final NotificationRequest request, final Notificati request.getTitle(), request.getBody(), request.getId(), + request.getDeviceToken(), type)) .getId(); request.setNotificationId(id.toString()); + sendToQueue(request); + } + + private void sendToQueue(final NotificationRequest request) { rabbitTemplate.convertAndSend( RabbitMQConstant.NOTIFICATION_EXCHANGE.getName(), RabbitMQConstant.NOTIFICATION_ROUTING_KEY.getName(), request); } + + public void sendFailedNotification(final List ids) { + notificationRepository.findAllByIdIn(ids).stream() + .map(notificationMapper::toNotificationRequest) + .forEach(this::sendToQueue); + } } diff --git a/backend/src/main/java/com/twtw/backend/domain/notification/repository/JpaNotificationRepository.java b/backend/src/main/java/com/twtw/backend/domain/notification/repository/JpaNotificationRepository.java index 5040c97..0593250 100644 --- a/backend/src/main/java/com/twtw/backend/domain/notification/repository/JpaNotificationRepository.java +++ b/backend/src/main/java/com/twtw/backend/domain/notification/repository/JpaNotificationRepository.java @@ -4,7 +4,11 @@ import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; import java.util.UUID; public interface JpaNotificationRepository - extends JpaRepository, NotificationRepository {} + extends JpaRepository, NotificationRepository { + + List findAllByIdIn(final List ids); +} diff --git a/backend/src/main/java/com/twtw/backend/domain/notification/repository/NotificationRepository.java b/backend/src/main/java/com/twtw/backend/domain/notification/repository/NotificationRepository.java index 579f893..a1093fb 100644 --- a/backend/src/main/java/com/twtw/backend/domain/notification/repository/NotificationRepository.java +++ b/backend/src/main/java/com/twtw/backend/domain/notification/repository/NotificationRepository.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -12,4 +13,6 @@ public interface NotificationRepository { Notification save(final Notification notification); Optional findById(final UUID id); + + List findAllByIdIn(final List ids); }