Skip to content

Commit

Permalink
[FEAT] add notification table and use in deadletter
Browse files Browse the repository at this point in the history
  • Loading branch information
ohksj77 committed Mar 30, 2024
1 parent c744b22 commit 7abfa77
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.twtw.backend.domain.member.service.AuthService;
import com.twtw.backend.domain.member.service.MemberService;
import com.twtw.backend.domain.notification.dto.NotificationRequest;
import com.twtw.backend.domain.notification.entity.NotificationType;
import com.twtw.backend.domain.notification.messagequeue.FcmProducer;
import com.twtw.backend.global.constant.NotificationBody;
import com.twtw.backend.global.constant.NotificationTitle;
Expand Down Expand Up @@ -67,7 +68,8 @@ private void sendNotification(final String deviceToken, final String nickname, f
deviceToken,
NotificationTitle.FRIEND_REQUEST_TITLE.getName(),
NotificationBody.FRIEND_REQUEST_BODY.toNotificationBody(nickname),
id.toString()));
id.toString()),
NotificationType.FRIEND_REQUEST);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.twtw.backend.domain.member.service.AuthService;
import com.twtw.backend.domain.member.service.MemberService;
import com.twtw.backend.domain.notification.dto.NotificationRequest;
import com.twtw.backend.domain.notification.entity.NotificationType;
import com.twtw.backend.domain.notification.messagequeue.FcmProducer;
import com.twtw.backend.global.constant.NotificationBody;
import com.twtw.backend.global.constant.NotificationTitle;
Expand Down Expand Up @@ -137,7 +138,8 @@ private void sendNotification(final String deviceToken, final String groupName,
deviceToken,
NotificationTitle.GROUP_REQUEST_TITLE.getName(),
NotificationBody.GROUP_REQUEST_BODY.toNotificationBody(groupName),
id.toString()));
id.toString()),
NotificationType.GROUP_REQUEST);
}

public GroupInfoResponse getGroupInfoResponse(Group group) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
import com.google.firebase.messaging.Message;
import com.google.firebase.messaging.Notification;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class NotificationRequest {

private static final ApnsConfig APNS_CONFIG =
Expand All @@ -28,6 +27,16 @@ public class NotificationRequest {
private String body;
private String id;

@Setter private String notificationId;

public NotificationRequest(
final String deviceToken, final String title, final String body, final String id) {
this.deviceToken = deviceToken;
this.title = title;
this.body = body;
this.id = id;
}

public Message toMessage() {
return Message.builder()
.setApnsConfig(APNS_CONFIG)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.twtw.backend.domain.notification.entity;

import com.github.f4b6a3.ulid.UlidCreator;
import com.twtw.backend.global.audit.AuditListener;
import com.twtw.backend.global.audit.Auditable;
import com.twtw.backend.global.audit.BaseTime;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.UUID;

@Getter
@Entity
@EntityListeners(AuditListener.class)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Notification implements Auditable {

@Id
@Column(columnDefinition = "BINARY(16)")
private final UUID id = UlidCreator.getMonotonicUlid().toUuid();

@Column(nullable = false)
private String title;

@Column(nullable = false)
private String body;

@Column(nullable = false)
private String idInfo;

@Column(nullable = false)
@Enumerated(EnumType.STRING)
private NotificationType type;

private Boolean isCompleted = false;

@Setter private BaseTime baseTime;

@Builder
public Notification(
final String title,
final String body,
final String idInfo,
final NotificationType type) {
this.title = title;
this.body = body;
this.idInfo = idInfo;
this.type = type;
}

public void complete() {
this.isCompleted = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.twtw.backend.domain.notification.entity;

public enum NotificationType {
FRIEND_REQUEST, GROUP_REQUEST, DESTINATION_CHANGE, PLAN_REQUEST
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
package com.twtw.backend.domain.notification.messagequeue;

import com.google.firebase.messaging.FirebaseMessaging;
import com.rabbitmq.client.Channel;
import com.google.firebase.messaging.FirebaseMessagingException;
import com.twtw.backend.domain.notification.dto.NotificationRequest;
import com.twtw.backend.domain.notification.entity.Notification;
import com.twtw.backend.domain.notification.repository.NotificationRepository;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.UUID;

@Component
public class FcmConsumer {
private final FirebaseMessaging firebaseMessaging;
private final NotificationRepository notificationRepository;

public FcmConsumer(FirebaseMessaging firebaseMessaging) {
public FcmConsumer(
FirebaseMessaging firebaseMessaging, NotificationRepository notificationRepository) {
this.firebaseMessaging = firebaseMessaging;
this.notificationRepository = notificationRepository;
}

@Transactional
@RabbitListener(queues = "notification.queue")
public void sendNotification(
final NotificationRequest request,
final Channel channel,
@Header(AmqpHeaders.DELIVERY_TAG) final long tag)
throws IOException {
try {
firebaseMessaging.send(request.toMessage());
} catch (final Exception e) {
channel.basicNack(tag, false, false);
}
public void sendNotification(final NotificationRequest request)
throws FirebaseMessagingException {
firebaseMessaging.send(request.toMessage());

notificationRepository
.findById(UUID.fromString(request.getNotificationId()))
.ifPresent(Notification::complete);
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
package com.twtw.backend.domain.notification.messagequeue;

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.repository.NotificationRepository;
import com.twtw.backend.global.constant.RabbitMQConstant;

import lombok.RequiredArgsConstructor;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

import java.util.UUID;

@Component
@RequiredArgsConstructor
public class FcmProducer {

private final RabbitTemplate rabbitTemplate;
private final NotificationRepository notificationRepository;

public void sendNotification(final NotificationRequest request, final NotificationType type) {
final UUID id =
notificationRepository
.save(
new Notification(
request.getTitle(),
request.getBody(),
request.getId(),
type))
.getId();

request.setNotificationId(id.toString());

public void sendNotification(final NotificationRequest request) {
rabbitTemplate.convertAndSend(
RabbitMQConstant.NOTIFICATION_EXCHANGE.getName(),
RabbitMQConstant.NOTIFICATION_ROUTING_KEY.getName(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.twtw.backend.domain.notification.repository;

import com.twtw.backend.domain.notification.entity.Notification;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.UUID;

public interface JpaNotificationRepository extends JpaRepository<Notification, UUID>, NotificationRepository {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.twtw.backend.domain.notification.repository;

import com.twtw.backend.domain.notification.entity.Notification;

import org.springframework.stereotype.Repository;

import java.util.Optional;
import java.util.UUID;

@Repository
public interface NotificationRepository {
Notification save(final Notification notification);
Optional<Notification> findById(final UUID id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.twtw.backend.domain.member.service.AuthService;
import com.twtw.backend.domain.member.service.MemberService;
import com.twtw.backend.domain.notification.dto.NotificationRequest;
import com.twtw.backend.domain.notification.entity.NotificationType;
import com.twtw.backend.domain.notification.messagequeue.FcmProducer;
import com.twtw.backend.domain.place.entity.Place;
import com.twtw.backend.domain.place.service.PlaceService;
Expand Down Expand Up @@ -113,7 +114,8 @@ private void sendRequestNotification(
deviceToken,
NotificationTitle.PLAN_REQUEST_TITLE.getName(),
NotificationBody.PLAN_REQUEST_BODY.toNotificationBody(planName),
id.toString()));
id.toString()),
NotificationType.PLAN_REQUEST);
}

public void outPlan(PlanMemberRequest request) {
Expand Down Expand Up @@ -223,7 +225,8 @@ private void sendDestinationNotification(
NotificationTitle.DESTINATION_CHANGE_TITLE.getName(),
NotificationBody.DESTINATION_CHANGE_BODY.toNotificationBody(
destinationName),
id.toString()));
id.toString()),
NotificationType.DESTINATION_CHANGE);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
package com.twtw.backend.support.exclude;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;

import com.twtw.backend.domain.notification.messagequeue.FcmProducer;
import com.twtw.backend.support.testcontainer.ContainerTestConfig;

import org.junit.jupiter.api.BeforeEach;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ContextConfiguration;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;

@ContextConfiguration(initializers = ContainerTestConfig.class)
public abstract class ExcludeTest {

@MockBean private FcmProducer fcmProducer;

@BeforeEach
void setUp() {
doNothing().when(fcmProducer).sendNotification(any());
doNothing().when(fcmProducer).sendNotification(any(), any());
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
package com.twtw.backend.support.service;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;

import com.twtw.backend.domain.member.entity.Member;
import com.twtw.backend.domain.member.repository.MemberRepository;
import com.twtw.backend.domain.member.service.AuthService;
import com.twtw.backend.domain.notification.messagequeue.FcmProducer;
import com.twtw.backend.fixture.member.MemberEntityFixture;
import com.twtw.backend.support.stub.StubConfig;
import com.twtw.backend.support.testcontainer.ContainerTestConfig;

import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ContextConfiguration;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;

@ServiceTest
@ContextConfiguration(
initializers = {ContainerTestConfig.class},
Expand All @@ -33,6 +32,6 @@ public void setup() {
loginUser = memberRepository.save(MemberEntityFixture.LOGIN_MEMBER.toEntity());
when(authService.getMemberByJwt()).thenReturn(loginUser);
when(authService.getMemberIdValue()).thenReturn(loginUser.getId().toString());
doNothing().when(fcmProducer).sendNotification(any());
doNothing().when(fcmProducer).sendNotification(any(), any());
}
}

0 comments on commit 7abfa77

Please sign in to comment.