From 478c6b81f9de6482aca05a3f4c6b01d03cb2a3f8 Mon Sep 17 00:00:00 2001 From: Dmytro Trotsenko Date: Thu, 7 Mar 2024 22:21:02 +0200 Subject: [PATCH 1/3] feat: updated MessageNotificationResponseDto changed lastMessage field type to LastMessageResponseDto --- .../dto/response/LastMessageResponseDto.java | 36 +++++++++++++++++++ .../MessageNotificationResponseDto.java | 2 +- .../listener/StompSubscriptionListener.java | 9 ++--- .../yourway/model/event/ContactEvent.java | 15 +++----- .../service/ChatMessageServiceImpl.java | 8 ++++- .../service/ContactEventServiceImpl.java | 5 +-- .../interfaces/ContactEventService.java | 5 +-- .../controller/ChatControllerTest.java | 15 ++++++-- .../StompSubscriptionListenerTest.java | 11 ++++-- .../impl/ContactEventServiceImplTest.java | 32 +++++++++-------- .../impl/NotificationServiceImplTest.java | 10 ++++-- 11 files changed, 106 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java diff --git a/src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java b/src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java new file mode 100644 index 00000000..1f8426b9 --- /dev/null +++ b/src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java @@ -0,0 +1,36 @@ +package com.chat.yourway.dto.response; + +import java.time.LocalDateTime; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@NoArgsConstructor +@Getter +@Setter +@ToString +public class LastMessageResponseDto { + + private static final int MAX_LENGTH = 20; + + private LocalDateTime timestamp; + private String sentFrom; + private String lastMessage; + + public LastMessageResponseDto(LocalDateTime timestamp, String sentFrom, String lastMessage) { + this.timestamp = timestamp; + this.sentFrom = sentFrom; + this.lastMessage = lastMessage; + } + + public void setLastMessage(String lastMessage) { + if (lastMessage.length() <= MAX_LENGTH) { + this.lastMessage = lastMessage; + } else { + this.lastMessage = lastMessage.substring(0, MAX_LENGTH) + "..."; + } + + } + +} diff --git a/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java b/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java index 4d5f2475..baf05554 100644 --- a/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java @@ -20,6 +20,6 @@ public class MessageNotificationResponseDto { private EventType status; private Integer unreadMessages; private LocalDateTime lastRead; - private String lastMessage; + private LastMessageResponseDto lastMessage; } diff --git a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java index b30518a9..9d205b91 100644 --- a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java +++ b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java @@ -4,6 +4,7 @@ import static com.chat.yourway.model.event.EventType.UNSUBSCRIBED; import com.chat.yourway.config.websocket.WebsocketProperties; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.interfaces.ChatNotificationService; import com.chat.yourway.service.interfaces.ContactEventService; @@ -29,7 +30,7 @@ public class StompSubscriptionListener { private final ContactEventService contactEventService; private final ChatNotificationService chatNotificationService; - private static String lastMessage; + private static LastMessageResponseDto lastMessageDto; private static final String USER_DESTINATION = "/user"; private static final String SLASH = "/"; @@ -40,10 +41,10 @@ public void handleWebSocketSubscribeListener(SessionSubscribeEvent event) { try { if (isTopicDestination(destination)) { - lastMessage = contactEventService.getByTopicIdAndEmail(getTopicId(event), email) + lastMessageDto = contactEventService.getByTopicIdAndEmail(getTopicId(event), email) .getLastMessage(); var contactEvent = new ContactEvent(email, getTopicId(event), SUBSCRIBED, - getTimestamp(event), lastMessage); + getTimestamp(event), lastMessageDto); contactEventService.save(contactEvent); } @@ -64,7 +65,7 @@ public void handleWebSocketUnsubscribeListener(SessionUnsubscribeEvent event) { try { if (isTopicDestination(destination)) { var contactEvent = new ContactEvent(email, getTopicId(event), UNSUBSCRIBED, - getTimestamp(event), lastMessage); + getTimestamp(event), lastMessageDto); contactEventService.save(contactEvent); } diff --git a/src/main/java/com/chat/yourway/model/event/ContactEvent.java b/src/main/java/com/chat/yourway/model/event/ContactEvent.java index c67a8da2..e782d795 100644 --- a/src/main/java/com/chat/yourway/model/event/ContactEvent.java +++ b/src/main/java/com/chat/yourway/model/event/ContactEvent.java @@ -1,5 +1,6 @@ package com.chat.yourway.model.event; +import com.chat.yourway.dto.response.LastMessageResponseDto; import java.time.LocalDateTime; import lombok.Getter; import lombok.NoArgsConstructor; @@ -25,11 +26,11 @@ public class ContactEvent { private Integer topicId; private EventType eventType; private LocalDateTime timestamp; - private String lastMessage; + private LastMessageResponseDto lastMessage; - private static final int MAX_LENGTH = 20; - public ContactEvent(String email, Integer topicId, EventType eventType, LocalDateTime timestamp, String lastMessage) { + public ContactEvent(String email, Integer topicId, EventType eventType, LocalDateTime timestamp, + LastMessageResponseDto lastMessage) { this.id = email + "_" + topicId; this.email = email; this.topicId = topicId; @@ -38,12 +39,4 @@ public ContactEvent(String email, Integer topicId, EventType eventType, LocalDat this.lastMessage = lastMessage; } - public void setLastMessage(String lastMessage) { - if (lastMessage.length() <= MAX_LENGTH) { - this.lastMessage = lastMessage; - } else { - this.lastMessage = lastMessage.substring(0, MAX_LENGTH) + "..."; - } - - } } diff --git a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java index 46e43832..26c1b9d9 100644 --- a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java @@ -4,6 +4,7 @@ import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; import com.chat.yourway.dto.request.PageRequestDto; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.service.interfaces.ChatMessageService; import com.chat.yourway.service.interfaces.ChatNotificationService; @@ -67,7 +68,12 @@ public List sendMessageHistoryByTopicId(Integer topicId, } private void sendToTopic(Integer topicId, MessageResponseDto messageDto) { - contactEventService.setLastMessageToAllTopicSubscribers(topicId, messageDto.getContent()); + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(messageDto.getTimestamp()); + lastMessageDto.setSentFrom(messageDto.getSentFrom()); + lastMessageDto.setLastMessage(messageDto.getContent()); + + contactEventService.setLastMessageToAllTopicSubscribers(topicId, lastMessageDto); simpMessagingTemplate.convertAndSend(toTopicDestination(topicId), messageDto); chatNotificationService.notifyTopicSubscribers(topicId); } diff --git a/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java b/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java index 9003f7ce..b742d8dc 100644 --- a/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java @@ -2,6 +2,7 @@ import static com.chat.yourway.model.event.EventType.ONLINE; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.model.event.EventType; import com.chat.yourway.repository.ContactEventRedisRepository; @@ -30,7 +31,7 @@ public ContactEvent getByTopicIdAndEmail(Integer topicId, String email) { log.trace("Started getByTopicIdAndEmail, topicId [{}], email [{}]", topicId, email); return contactEventRedisRepository.findById(email + "_" + topicId) - .orElse(new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), "")); + .orElse(new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), null)); } @Override @@ -61,7 +62,7 @@ public List getAllByTopicId(Integer topicId) { } @Override - public void setLastMessageToAllTopicSubscribers(Integer topicId, String message) { + public void setLastMessageToAllTopicSubscribers(Integer topicId, LastMessageResponseDto message) { log.trace("Started setLastMessageToAllTopicSubscribers, topic id [{}], last message [{}]", topicId, message); diff --git a/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java b/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java index 3fcc52e7..ae199c9f 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java @@ -1,5 +1,6 @@ package com.chat.yourway.service.interfaces; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.model.event.EventType; import java.util.List; @@ -44,8 +45,8 @@ public interface ContactEventService { * Set last message to all topic subscribers events. * * @param topicId topic id. - * @param message last message. + * @param lastMessageDto last message Dto. */ - void setLastMessageToAllTopicSubscribers(Integer topicId, String message); + void setLastMessageToAllTopicSubscribers(Integer topicId, LastMessageResponseDto lastMessageDto); } diff --git a/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java b/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java index f53e9ce7..761d16bc 100644 --- a/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java +++ b/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java @@ -11,6 +11,7 @@ import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; import com.chat.yourway.dto.request.PageRequestDto; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.dto.response.MessageNotificationResponseDto; import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.integration.controller.websocketclient.TestStompFrameHandler; @@ -196,7 +197,12 @@ void getMessages_shouldReturnReceivedMessagesHistoryFromTopic() { void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfSubscribeEvent() { // Given int topicId = 12; - var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), "Hi"); + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(LocalDateTime.now()); + lastMessageDto.setSentFrom("vasil@gmail.com"); + lastMessageDto.setLastMessage("Hi"); + + var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), lastMessageDto); saveContactEvent(event); //Stored subscription results for testing CompletableFuture resultKeeper = new CompletableFuture<>(); @@ -223,7 +229,12 @@ void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfSubscribeEvent() { void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfAnyContactSubscribedToTopic() { // Given int topicId = 12; - var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), "Hi"); + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(LocalDateTime.now()); + lastMessageDto.setSentFrom("vasil@gmail.com"); + lastMessageDto.setLastMessage("Hi"); + + var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), lastMessageDto); saveContactEvent(event); //Stored subscription results for testing CompletableFuture resultKeeper = new CompletableFuture<>(); diff --git a/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java b/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java index 8a717ba9..481ce221 100644 --- a/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java +++ b/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java @@ -13,6 +13,7 @@ import static org.springframework.messaging.simp.stomp.StompCommand.UNSUBSCRIBE; import com.chat.yourway.config.websocket.WebsocketProperties; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.listener.StompSubscriptionListener; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.interfaces.ChatNotificationService; @@ -68,9 +69,13 @@ public void handleWebSocketSubscribeListener_shouldSaveEvent() { int topicId = 1; String destination = "/topic/" + topicId; - String lastMessage = "Hello"; + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(LocalDateTime.now()); + lastMessageDto.setSentFrom("vasil@gmail.com"); + lastMessageDto.setLastMessage("Hello"); + ContactEvent contactEvent = new ContactEvent(); - contactEvent.setLastMessage(lastMessage); + contactEvent.setLastMessage(lastMessageDto); var event = createSubscribeEvent(destination, getPrincipal(email, password)); @@ -87,7 +92,7 @@ public void handleWebSocketSubscribeListener_shouldSaveEvent() { assertThat(capturedEvent.getEmail()).isEqualTo(email); assertThat(capturedEvent.getTimestamp()).isInstanceOfAny(LocalDateTime.class); assertThat(capturedEvent.getEventType()).isEqualTo(SUBSCRIBED); - assertThat(capturedEvent.getLastMessage()).isEqualTo(lastMessage); + assertThat(capturedEvent.getLastMessage()).isEqualTo(lastMessageDto); } @Test diff --git a/src/test/java/com/chat/yourway/unit/service/impl/ContactEventServiceImplTest.java b/src/test/java/com/chat/yourway/unit/service/impl/ContactEventServiceImplTest.java index b3d24c1a..da8fb7b5 100644 --- a/src/test/java/com/chat/yourway/unit/service/impl/ContactEventServiceImplTest.java +++ b/src/test/java/com/chat/yourway/unit/service/impl/ContactEventServiceImplTest.java @@ -7,6 +7,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.model.event.EventType; import com.chat.yourway.repository.ContactEventRedisRepository; @@ -40,7 +41,7 @@ void save_shouldSaveToRepository() { // Given String email = "vasil@gmail.com"; int topicId = 1; - ContactEvent contactEvent = new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), ""); + ContactEvent contactEvent = new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), null); // When contactEventService.save(contactEvent); @@ -55,8 +56,7 @@ void getByTopicIdAndEmail_shouldReturnContactEventFromRepository() { // Given Integer topicId = 1; String email = "vasil@gmail.com"; - ContactEvent expectedContactEvent = new ContactEvent(email, topicId, ONLINE, - LocalDateTime.now(), ""); + ContactEvent expectedContactEvent = new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), null); when(contactEventRedisRepository.findById(email + "_" + topicId)) .thenReturn(Optional.of(expectedContactEvent)); @@ -91,8 +91,8 @@ void getAllByEmail_shouldReturnContactEventsFromRepository() { // Given String email = "vasil@gmail.com"; List expectedContactEvents = Arrays.asList( - new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), ""), - new ContactEvent(email, 2, OFFLINE, LocalDateTime.now(), "") + new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), null), + new ContactEvent(email, 2, OFFLINE, LocalDateTime.now(), null) ); when(contactEventRedisRepository.findAllByEmail(email)).thenReturn(expectedContactEvents); @@ -110,8 +110,8 @@ void updateEventTypeByEmail_shouldUpdateEventTypesInRepository() { String email = "vasil@gmail.com"; EventType newEventType = OFFLINE; List events = Arrays.asList( - new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), ""), - new ContactEvent(email, 2, ONLINE, LocalDateTime.now(), "") + new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), null), + new ContactEvent(email, 2, ONLINE, LocalDateTime.now(), null) ); when(contactEventRedisRepository.findAllByEmail(email)).thenReturn(events); @@ -129,8 +129,8 @@ void getAllByTopicId_shouldReturnContactEventsFromRepository() { // Given Integer topicId = 1; List expectedContactEvents = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), ""), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), "") + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), null), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), null) ); when(contactEventRedisRepository.findAllByTopicId(topicId)).thenReturn(expectedContactEvents); @@ -146,18 +146,22 @@ void getAllByTopicId_shouldReturnContactEventsFromRepository() { void setLastMessageToAllTopicSubscribers_shouldUpdateLastMessagesInRepository() { // Given Integer topicId = 1; - String newMessage = "New message"; + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(LocalDateTime.now()); + lastMessageDto.setSentFrom("vasil@gmail.com"); + lastMessageDto.setLastMessage("New message"); + List events = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), ""), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), "") + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), null), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), null) ); when(contactEventRedisRepository.findAllByTopicId(topicId)).thenReturn(events); // When - contactEventService.setLastMessageToAllTopicSubscribers(topicId, newMessage); + contactEventService.setLastMessageToAllTopicSubscribers(topicId, lastMessageDto); // Then - events.forEach(e -> e.setLastMessage(newMessage)); + events.forEach(e -> e.setLastMessage(lastMessageDto)); verify(contactEventRedisRepository, times(1)).saveAll(events); } diff --git a/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java b/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java index 51bd13a5..ae4094f6 100644 --- a/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java +++ b/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java @@ -10,6 +10,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.dto.response.MessageNotificationResponseDto; import com.chat.yourway.mapper.MessageNotificationMapper; import com.chat.yourway.model.event.ContactEvent; @@ -46,9 +47,14 @@ class NotificationServiceImplTest { void notifyTopicSubscribers_shouldReturnListOfNotificationsWithUnreadMessageCounts() { // Given Integer topicId = 1; + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(LocalDateTime.now()); + lastMessageDto.setSentFrom("vasil@gmail.com"); + lastMessageDto.setLastMessage("Hello"); + List events = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), "Hello"), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), "Hello") + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), lastMessageDto), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), lastMessageDto) ); var expectedNotifications = events.stream() From 3db283ad05b0f2fc55452da4cd3715e3a1d848c4 Mon Sep 17 00:00:00 2001 From: Dmytro Trotsenko Date: Thu, 7 Mar 2024 22:21:02 +0200 Subject: [PATCH 2/3] feat: updated MessageNotificationResponseDto changed lastMessage field type to LastMessageResponseDto --- .../dto/response/LastMessageResponseDto.java | 36 +++++++++++++++++++ .../MessageNotificationResponseDto.java | 2 +- .../listener/StompSubscriptionListener.java | 9 ++--- .../yourway/model/event/ContactEvent.java | 15 +++----- .../service/ChatMessageServiceImpl.java | 8 ++++- .../service/ContactEventServiceImpl.java | 5 +-- .../interfaces/ContactEventService.java | 5 +-- .../controller/ChatControllerTest.java | 15 ++++++-- .../StompSubscriptionListenerTest.java | 11 ++++-- .../impl/ContactEventServiceImplTest.java | 32 +++++++++-------- .../impl/NotificationServiceImplTest.java | 10 ++++-- 11 files changed, 106 insertions(+), 42 deletions(-) create mode 100644 src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java diff --git a/src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java b/src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java new file mode 100644 index 00000000..1f8426b9 --- /dev/null +++ b/src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java @@ -0,0 +1,36 @@ +package com.chat.yourway.dto.response; + +import java.time.LocalDateTime; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@NoArgsConstructor +@Getter +@Setter +@ToString +public class LastMessageResponseDto { + + private static final int MAX_LENGTH = 20; + + private LocalDateTime timestamp; + private String sentFrom; + private String lastMessage; + + public LastMessageResponseDto(LocalDateTime timestamp, String sentFrom, String lastMessage) { + this.timestamp = timestamp; + this.sentFrom = sentFrom; + this.lastMessage = lastMessage; + } + + public void setLastMessage(String lastMessage) { + if (lastMessage.length() <= MAX_LENGTH) { + this.lastMessage = lastMessage; + } else { + this.lastMessage = lastMessage.substring(0, MAX_LENGTH) + "..."; + } + + } + +} diff --git a/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java b/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java index 4d5f2475..baf05554 100644 --- a/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java @@ -20,6 +20,6 @@ public class MessageNotificationResponseDto { private EventType status; private Integer unreadMessages; private LocalDateTime lastRead; - private String lastMessage; + private LastMessageResponseDto lastMessage; } diff --git a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java index b30518a9..9d205b91 100644 --- a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java +++ b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java @@ -4,6 +4,7 @@ import static com.chat.yourway.model.event.EventType.UNSUBSCRIBED; import com.chat.yourway.config.websocket.WebsocketProperties; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.interfaces.ChatNotificationService; import com.chat.yourway.service.interfaces.ContactEventService; @@ -29,7 +30,7 @@ public class StompSubscriptionListener { private final ContactEventService contactEventService; private final ChatNotificationService chatNotificationService; - private static String lastMessage; + private static LastMessageResponseDto lastMessageDto; private static final String USER_DESTINATION = "/user"; private static final String SLASH = "/"; @@ -40,10 +41,10 @@ public void handleWebSocketSubscribeListener(SessionSubscribeEvent event) { try { if (isTopicDestination(destination)) { - lastMessage = contactEventService.getByTopicIdAndEmail(getTopicId(event), email) + lastMessageDto = contactEventService.getByTopicIdAndEmail(getTopicId(event), email) .getLastMessage(); var contactEvent = new ContactEvent(email, getTopicId(event), SUBSCRIBED, - getTimestamp(event), lastMessage); + getTimestamp(event), lastMessageDto); contactEventService.save(contactEvent); } @@ -64,7 +65,7 @@ public void handleWebSocketUnsubscribeListener(SessionUnsubscribeEvent event) { try { if (isTopicDestination(destination)) { var contactEvent = new ContactEvent(email, getTopicId(event), UNSUBSCRIBED, - getTimestamp(event), lastMessage); + getTimestamp(event), lastMessageDto); contactEventService.save(contactEvent); } diff --git a/src/main/java/com/chat/yourway/model/event/ContactEvent.java b/src/main/java/com/chat/yourway/model/event/ContactEvent.java index c67a8da2..e782d795 100644 --- a/src/main/java/com/chat/yourway/model/event/ContactEvent.java +++ b/src/main/java/com/chat/yourway/model/event/ContactEvent.java @@ -1,5 +1,6 @@ package com.chat.yourway.model.event; +import com.chat.yourway.dto.response.LastMessageResponseDto; import java.time.LocalDateTime; import lombok.Getter; import lombok.NoArgsConstructor; @@ -25,11 +26,11 @@ public class ContactEvent { private Integer topicId; private EventType eventType; private LocalDateTime timestamp; - private String lastMessage; + private LastMessageResponseDto lastMessage; - private static final int MAX_LENGTH = 20; - public ContactEvent(String email, Integer topicId, EventType eventType, LocalDateTime timestamp, String lastMessage) { + public ContactEvent(String email, Integer topicId, EventType eventType, LocalDateTime timestamp, + LastMessageResponseDto lastMessage) { this.id = email + "_" + topicId; this.email = email; this.topicId = topicId; @@ -38,12 +39,4 @@ public ContactEvent(String email, Integer topicId, EventType eventType, LocalDat this.lastMessage = lastMessage; } - public void setLastMessage(String lastMessage) { - if (lastMessage.length() <= MAX_LENGTH) { - this.lastMessage = lastMessage; - } else { - this.lastMessage = lastMessage.substring(0, MAX_LENGTH) + "..."; - } - - } } diff --git a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java index 46e43832..26c1b9d9 100644 --- a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java @@ -4,6 +4,7 @@ import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; import com.chat.yourway.dto.request.PageRequestDto; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.service.interfaces.ChatMessageService; import com.chat.yourway.service.interfaces.ChatNotificationService; @@ -67,7 +68,12 @@ public List sendMessageHistoryByTopicId(Integer topicId, } private void sendToTopic(Integer topicId, MessageResponseDto messageDto) { - contactEventService.setLastMessageToAllTopicSubscribers(topicId, messageDto.getContent()); + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(messageDto.getTimestamp()); + lastMessageDto.setSentFrom(messageDto.getSentFrom()); + lastMessageDto.setLastMessage(messageDto.getContent()); + + contactEventService.setLastMessageToAllTopicSubscribers(topicId, lastMessageDto); simpMessagingTemplate.convertAndSend(toTopicDestination(topicId), messageDto); chatNotificationService.notifyTopicSubscribers(topicId); } diff --git a/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java b/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java index 9003f7ce..b742d8dc 100644 --- a/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java @@ -2,6 +2,7 @@ import static com.chat.yourway.model.event.EventType.ONLINE; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.model.event.EventType; import com.chat.yourway.repository.ContactEventRedisRepository; @@ -30,7 +31,7 @@ public ContactEvent getByTopicIdAndEmail(Integer topicId, String email) { log.trace("Started getByTopicIdAndEmail, topicId [{}], email [{}]", topicId, email); return contactEventRedisRepository.findById(email + "_" + topicId) - .orElse(new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), "")); + .orElse(new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), null)); } @Override @@ -61,7 +62,7 @@ public List getAllByTopicId(Integer topicId) { } @Override - public void setLastMessageToAllTopicSubscribers(Integer topicId, String message) { + public void setLastMessageToAllTopicSubscribers(Integer topicId, LastMessageResponseDto message) { log.trace("Started setLastMessageToAllTopicSubscribers, topic id [{}], last message [{}]", topicId, message); diff --git a/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java b/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java index 3fcc52e7..ae199c9f 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java @@ -1,5 +1,6 @@ package com.chat.yourway.service.interfaces; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.model.event.EventType; import java.util.List; @@ -44,8 +45,8 @@ public interface ContactEventService { * Set last message to all topic subscribers events. * * @param topicId topic id. - * @param message last message. + * @param lastMessageDto last message Dto. */ - void setLastMessageToAllTopicSubscribers(Integer topicId, String message); + void setLastMessageToAllTopicSubscribers(Integer topicId, LastMessageResponseDto lastMessageDto); } diff --git a/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java b/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java index f53e9ce7..761d16bc 100644 --- a/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java +++ b/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java @@ -11,6 +11,7 @@ import com.chat.yourway.dto.request.MessagePrivateRequestDto; import com.chat.yourway.dto.request.MessagePublicRequestDto; import com.chat.yourway.dto.request.PageRequestDto; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.dto.response.MessageNotificationResponseDto; import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.integration.controller.websocketclient.TestStompFrameHandler; @@ -196,7 +197,12 @@ void getMessages_shouldReturnReceivedMessagesHistoryFromTopic() { void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfSubscribeEvent() { // Given int topicId = 12; - var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), "Hi"); + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(LocalDateTime.now()); + lastMessageDto.setSentFrom("vasil@gmail.com"); + lastMessageDto.setLastMessage("Hi"); + + var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), lastMessageDto); saveContactEvent(event); //Stored subscription results for testing CompletableFuture resultKeeper = new CompletableFuture<>(); @@ -223,7 +229,12 @@ void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfSubscribeEvent() { void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfAnyContactSubscribedToTopic() { // Given int topicId = 12; - var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), "Hi"); + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(LocalDateTime.now()); + lastMessageDto.setSentFrom("vasil@gmail.com"); + lastMessageDto.setLastMessage("Hi"); + + var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), lastMessageDto); saveContactEvent(event); //Stored subscription results for testing CompletableFuture resultKeeper = new CompletableFuture<>(); diff --git a/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java b/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java index 8a717ba9..481ce221 100644 --- a/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java +++ b/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java @@ -13,6 +13,7 @@ import static org.springframework.messaging.simp.stomp.StompCommand.UNSUBSCRIBE; import com.chat.yourway.config.websocket.WebsocketProperties; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.listener.StompSubscriptionListener; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.interfaces.ChatNotificationService; @@ -68,9 +69,13 @@ public void handleWebSocketSubscribeListener_shouldSaveEvent() { int topicId = 1; String destination = "/topic/" + topicId; - String lastMessage = "Hello"; + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(LocalDateTime.now()); + lastMessageDto.setSentFrom("vasil@gmail.com"); + lastMessageDto.setLastMessage("Hello"); + ContactEvent contactEvent = new ContactEvent(); - contactEvent.setLastMessage(lastMessage); + contactEvent.setLastMessage(lastMessageDto); var event = createSubscribeEvent(destination, getPrincipal(email, password)); @@ -87,7 +92,7 @@ public void handleWebSocketSubscribeListener_shouldSaveEvent() { assertThat(capturedEvent.getEmail()).isEqualTo(email); assertThat(capturedEvent.getTimestamp()).isInstanceOfAny(LocalDateTime.class); assertThat(capturedEvent.getEventType()).isEqualTo(SUBSCRIBED); - assertThat(capturedEvent.getLastMessage()).isEqualTo(lastMessage); + assertThat(capturedEvent.getLastMessage()).isEqualTo(lastMessageDto); } @Test diff --git a/src/test/java/com/chat/yourway/unit/service/impl/ContactEventServiceImplTest.java b/src/test/java/com/chat/yourway/unit/service/impl/ContactEventServiceImplTest.java index b3d24c1a..da8fb7b5 100644 --- a/src/test/java/com/chat/yourway/unit/service/impl/ContactEventServiceImplTest.java +++ b/src/test/java/com/chat/yourway/unit/service/impl/ContactEventServiceImplTest.java @@ -7,6 +7,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.model.event.EventType; import com.chat.yourway.repository.ContactEventRedisRepository; @@ -40,7 +41,7 @@ void save_shouldSaveToRepository() { // Given String email = "vasil@gmail.com"; int topicId = 1; - ContactEvent contactEvent = new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), ""); + ContactEvent contactEvent = new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), null); // When contactEventService.save(contactEvent); @@ -55,8 +56,7 @@ void getByTopicIdAndEmail_shouldReturnContactEventFromRepository() { // Given Integer topicId = 1; String email = "vasil@gmail.com"; - ContactEvent expectedContactEvent = new ContactEvent(email, topicId, ONLINE, - LocalDateTime.now(), ""); + ContactEvent expectedContactEvent = new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), null); when(contactEventRedisRepository.findById(email + "_" + topicId)) .thenReturn(Optional.of(expectedContactEvent)); @@ -91,8 +91,8 @@ void getAllByEmail_shouldReturnContactEventsFromRepository() { // Given String email = "vasil@gmail.com"; List expectedContactEvents = Arrays.asList( - new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), ""), - new ContactEvent(email, 2, OFFLINE, LocalDateTime.now(), "") + new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), null), + new ContactEvent(email, 2, OFFLINE, LocalDateTime.now(), null) ); when(contactEventRedisRepository.findAllByEmail(email)).thenReturn(expectedContactEvents); @@ -110,8 +110,8 @@ void updateEventTypeByEmail_shouldUpdateEventTypesInRepository() { String email = "vasil@gmail.com"; EventType newEventType = OFFLINE; List events = Arrays.asList( - new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), ""), - new ContactEvent(email, 2, ONLINE, LocalDateTime.now(), "") + new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), null), + new ContactEvent(email, 2, ONLINE, LocalDateTime.now(), null) ); when(contactEventRedisRepository.findAllByEmail(email)).thenReturn(events); @@ -129,8 +129,8 @@ void getAllByTopicId_shouldReturnContactEventsFromRepository() { // Given Integer topicId = 1; List expectedContactEvents = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), ""), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), "") + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), null), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), null) ); when(contactEventRedisRepository.findAllByTopicId(topicId)).thenReturn(expectedContactEvents); @@ -146,18 +146,22 @@ void getAllByTopicId_shouldReturnContactEventsFromRepository() { void setLastMessageToAllTopicSubscribers_shouldUpdateLastMessagesInRepository() { // Given Integer topicId = 1; - String newMessage = "New message"; + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(LocalDateTime.now()); + lastMessageDto.setSentFrom("vasil@gmail.com"); + lastMessageDto.setLastMessage("New message"); + List events = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), ""), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), "") + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), null), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), null) ); when(contactEventRedisRepository.findAllByTopicId(topicId)).thenReturn(events); // When - contactEventService.setLastMessageToAllTopicSubscribers(topicId, newMessage); + contactEventService.setLastMessageToAllTopicSubscribers(topicId, lastMessageDto); // Then - events.forEach(e -> e.setLastMessage(newMessage)); + events.forEach(e -> e.setLastMessage(lastMessageDto)); verify(contactEventRedisRepository, times(1)).saveAll(events); } diff --git a/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java b/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java index 51bd13a5..ae4094f6 100644 --- a/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java +++ b/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java @@ -10,6 +10,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.dto.response.MessageNotificationResponseDto; import com.chat.yourway.mapper.MessageNotificationMapper; import com.chat.yourway.model.event.ContactEvent; @@ -46,9 +47,14 @@ class NotificationServiceImplTest { void notifyTopicSubscribers_shouldReturnListOfNotificationsWithUnreadMessageCounts() { // Given Integer topicId = 1; + var lastMessageDto = new LastMessageResponseDto(); + lastMessageDto.setTimestamp(LocalDateTime.now()); + lastMessageDto.setSentFrom("vasil@gmail.com"); + lastMessageDto.setLastMessage("Hello"); + List events = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), "Hello"), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), "Hello") + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), lastMessageDto), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), lastMessageDto) ); var expectedNotifications = events.stream() From a20d914d80c0088eefa6f5fc01923a0676b74a2d Mon Sep 17 00:00:00 2001 From: Dmytro Trotsenko Date: Sun, 10 Mar 2024 21:10:58 +0200 Subject: [PATCH 3/3] feat: refactored and create endpoint /user/specific/notify/topics for return TopicNotificationResponseDto --- .../yourway/controller/ChatController.java | 1 - .../MessageNotificationResponseDto.java | 4 +-- .../TopicNotificationResponseDto.java | 23 +++++++++++++ .../listener/StompSubscriptionListener.java | 6 ++++ .../mapper/MessageNotificationMapper.java | 1 - .../service/ChatMessageServiceImpl.java | 3 ++ .../service/ChatNotificationServiceImpl.java | 20 +++++++++-- .../service/NotificationServiceImpl.java | 33 ++++++++++++++----- .../interfaces/ChatNotificationService.java | 14 ++++++++ .../interfaces/NotificationService.java | 9 +++++ src/main/resources/static/index.html | 24 ++++++++++++++ .../controller/ChatControllerTest.java | 10 +++--- .../impl/NotificationServiceImplTest.java | 17 ++-------- 13 files changed, 128 insertions(+), 37 deletions(-) create mode 100644 src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java diff --git a/src/main/java/com/chat/yourway/controller/ChatController.java b/src/main/java/com/chat/yourway/controller/ChatController.java index fa9d0385..278e5b6e 100644 --- a/src/main/java/com/chat/yourway/controller/ChatController.java +++ b/src/main/java/com/chat/yourway/controller/ChatController.java @@ -40,5 +40,4 @@ public List getTopicHistory(@DestinationVariable Integer top String email = principal.getName(); return chatMessageService.sendMessageHistoryByTopicId(topicId, pageRequestDto, email); } - } diff --git a/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java b/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java index baf05554..3fd21933 100644 --- a/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java @@ -15,11 +15,9 @@ @ToString public class MessageNotificationResponseDto { - private String email; private Integer topicId; + private String email; private EventType status; - private Integer unreadMessages; private LocalDateTime lastRead; - private LastMessageResponseDto lastMessage; } diff --git a/src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java b/src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java new file mode 100644 index 00000000..5de5165d --- /dev/null +++ b/src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java @@ -0,0 +1,23 @@ +package com.chat.yourway.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@AllArgsConstructor +@NoArgsConstructor +@Setter +@Getter +@ToString +public class TopicNotificationResponseDto { + + private TopicResponseDto topic; + + private Integer unreadMessages; + + private LastMessageResponseDto lastMessage; + + +} diff --git a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java index 9d205b91..2fae796c 100644 --- a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java +++ b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java @@ -32,6 +32,7 @@ public class StompSubscriptionListener { private static LastMessageResponseDto lastMessageDto; private static final String USER_DESTINATION = "/user"; + private static final String TOPICS_DESTINATION = "/topics"; private static final String SLASH = "/"; @EventListener @@ -49,11 +50,16 @@ public void handleWebSocketSubscribeListener(SessionSubscribeEvent event) { } chatNotificationService.notifyTopicSubscribers(getTopicId(event)); + chatNotificationService.notifyAllWhoSubscribedToTopic(getTopicId(event)); } catch (NumberFormatException e) { log.warn("Contact [{}] subscribe to destination [{}] without topic id", email, destination); } + if (destination.equals(USER_DESTINATION + properties.getNotifyPrefix() + TOPICS_DESTINATION)) { + chatNotificationService.notifyAllPublicTopics(getEmail(event)); + } + log.info("Contact [{}] subscribe to [{}]", email, destination); } diff --git a/src/main/java/com/chat/yourway/mapper/MessageNotificationMapper.java b/src/main/java/com/chat/yourway/mapper/MessageNotificationMapper.java index 3dd01734..7a80c96e 100644 --- a/src/main/java/com/chat/yourway/mapper/MessageNotificationMapper.java +++ b/src/main/java/com/chat/yourway/mapper/MessageNotificationMapper.java @@ -8,7 +8,6 @@ @Mapper(componentModel = "spring") public interface MessageNotificationMapper { - @Mapping(target = "unreadMessages", ignore = true, defaultValue = "0") @Mapping(target = "status", source = "eventType") @Mapping(target = "lastRead", source = "timestamp") @Mapping(target = "email", source = "email") diff --git a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java index 26c1b9d9..8191aee0 100644 --- a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java @@ -74,8 +74,11 @@ private void sendToTopic(Integer topicId, MessageResponseDto messageDto) { lastMessageDto.setLastMessage(messageDto.getContent()); contactEventService.setLastMessageToAllTopicSubscribers(topicId, lastMessageDto); + simpMessagingTemplate.convertAndSend(toTopicDestination(topicId), messageDto); + chatNotificationService.notifyTopicSubscribers(topicId); + chatNotificationService.notifyAllWhoSubscribedToTopic(topicId); } private String toTopicDestination(Integer topicId) { diff --git a/src/main/java/com/chat/yourway/service/ChatNotificationServiceImpl.java b/src/main/java/com/chat/yourway/service/ChatNotificationServiceImpl.java index 7f3fe517..a3b5772b 100644 --- a/src/main/java/com/chat/yourway/service/ChatNotificationServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ChatNotificationServiceImpl.java @@ -25,7 +25,7 @@ public void notifyTopicSubscribers(Integer topicId) { var notifications = notificationService.notifyTopicSubscribers(topicId); notifications .forEach(n -> simpMessagingTemplate.convertAndSendToUser( - n.getEmail(), toNotifyDestination(topicId), notifications)); + n.getEmail(), toNotifyMessageDest(topicId), notifications)); log.trace("All subscribers was notified by topic id = [{}]", topicId); } @@ -36,8 +36,24 @@ public void notifyAllWhoSubscribedToSameUserTopic(String userEmail) { .forEach(e -> notifyTopicSubscribers(e.getTopicId())); } - private String toNotifyDestination(Integer topicId) { + @Override + public void notifyAllPublicTopics(String email){ + var notifiedTopics = notificationService.notifyAllPublicTopicsByEmail(email); + simpMessagingTemplate.convertAndSendToUser(email, toNotifyTopicsDest(), notifiedTopics); + } + + @Override + public void notifyAllWhoSubscribedToTopic(Integer topicId) { + contactEventService.getAllByTopicId(topicId) + .forEach(e -> notifyAllPublicTopics(e.getEmail())); + } + + private String toNotifyMessageDest(Integer topicId) { return properties.getNotifyPrefix() + "/" + topicId; } + private String toNotifyTopicsDest() { + return properties.getNotifyPrefix() + "/topics"; + } + } diff --git a/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java b/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java index aa9c24c3..f23060ad 100644 --- a/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java @@ -1,11 +1,13 @@ package com.chat.yourway.service; import com.chat.yourway.dto.response.MessageNotificationResponseDto; +import com.chat.yourway.dto.response.TopicNotificationResponseDto; import com.chat.yourway.mapper.MessageNotificationMapper; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.interfaces.ContactEventService; import com.chat.yourway.service.interfaces.MessageService; import com.chat.yourway.service.interfaces.NotificationService; +import com.chat.yourway.service.interfaces.TopicService; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -16,27 +18,40 @@ @Slf4j public class NotificationServiceImpl implements NotificationService { - private final MessageService messageService; private final ContactEventService contactEventService; + private final TopicService topicService; + private final MessageService messageService; private final MessageNotificationMapper notificationMapper; + @Override public List notifyTopicSubscribers(Integer topicId) { log.trace("Started notifyTopicSubscribers by topic id [{}]", topicId); - List events = contactEventService.getAllByTopicId(topicId).stream() + return contactEventService.getAllByTopicId(topicId).stream() + .map(notificationMapper::toNotificationResponseDto) .toList(); + } - return events.stream() - .map(notificationMapper::toNotificationResponseDto) - .peek(n -> n.setUnreadMessages(countUnreadMessages(n))) + @Override + public List notifyAllPublicTopicsByEmail(String email) { + + return topicService.findAllPublic().stream() + .map(topic -> { + var event = contactEventService.getByTopicIdAndEmail(topic.getId(), email); + var topicNotificationDto = new TopicNotificationResponseDto(); + topicNotificationDto.setTopic(topic); + topicNotificationDto.setUnreadMessages(countUnreadMessages(event)); + topicNotificationDto.setLastMessage(event.getLastMessage()); + return topicNotificationDto; + }) .toList(); } - private int countUnreadMessages(MessageNotificationResponseDto notification) { + private int countUnreadMessages(ContactEvent event) { return messageService.countMessagesBetweenTimestampByTopicId( - notification.getTopicId(), - notification.getEmail(), - notification.getLastRead()); + event.getTopicId(), + event.getEmail(), + event.getTimestamp()); } } diff --git a/src/main/java/com/chat/yourway/service/interfaces/ChatNotificationService.java b/src/main/java/com/chat/yourway/service/interfaces/ChatNotificationService.java index 9a05be4b..aef3056a 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/ChatNotificationService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/ChatNotificationService.java @@ -16,4 +16,18 @@ public interface ChatNotificationService { */ void notifyAllWhoSubscribedToSameUserTopic(String userEmail); + /** + * Notify all topics for chat events. + * + * @param userEmail user email. + */ + void notifyAllPublicTopics(String userEmail); + + /** + * Notify everyone who is subscribed to the same topic. + * + * @param topicId The id of the topic. + */ + void notifyAllWhoSubscribedToTopic(Integer topicId); + } diff --git a/src/main/java/com/chat/yourway/service/interfaces/NotificationService.java b/src/main/java/com/chat/yourway/service/interfaces/NotificationService.java index 683cc6f2..a14ab271 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/NotificationService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/NotificationService.java @@ -1,6 +1,7 @@ package com.chat.yourway.service.interfaces; import com.chat.yourway.dto.response.MessageNotificationResponseDto; +import com.chat.yourway.dto.response.TopicNotificationResponseDto; import java.util.List; public interface NotificationService { @@ -13,4 +14,12 @@ public interface NotificationService { */ List notifyTopicSubscribers(Integer topicId); + /** + * Retrieves a list of notifying all public topics. + * + * @param email user email. + * @return A list of public topic's information. + */ + List notifyAllPublicTopicsByEmail(String email); + } diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 75ee8e62..3548cb92 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -50,6 +50,15 @@

WebSocket Chat Test Client


+

+ Get all topics [/user/specific/notify/topics] +

+ +
+ +
+
+

Get message history [/app/history/topic/{id}]

@@ -101,6 +110,7 @@

WebSocket Chat Test Client

const subToTopicDest = '/topic/'; const subToError = '/user/specific/error'; const subToNotificationDest = '/user/specific/notify/'; + const subToAllTopicsDest = '/user/specific/notify/topics'; const sendToPublicTopicDest = "/app/topic/public/"; const sendToPrivateTopicDest = "/app/topic/private/"; const getHistoryTopicDest = "/app/history/topic/"; @@ -117,6 +127,7 @@

WebSocket Chat Test Client

console.log('Connected: ' + frame); subscribeToError(); + subscribeToAllTopics(); }); } @@ -154,6 +165,11 @@

WebSocket Chat Test Client

response.innerText = JSON.stringify(notificationMessage); } + function showAllTopics(topics) { + let response = document.getElementById('topics'); + response.innerText = JSON.stringify(topics); + } + function subscribeToNotificationFromTopic(topicId) { stompClient.subscribe(subToNotificationDest + topicId, function (messages) { let notificationMessage = JSON.parse(messages.body); @@ -170,6 +186,14 @@

WebSocket Chat Test Client

}); } + function subscribeToAllTopics() { + stompClient.subscribe(subToAllTopicsDest, function (messages) { + let topics = JSON.parse(messages.body); + console.log(topics); + showAllTopics(topics); + }); + } + function sendToPublicTopic() { let topicId = document.getElementById('subscribeToTopic').value; let message = document.getElementById('message').value; diff --git a/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java b/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java index 761d16bc..86063ceb 100644 --- a/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java +++ b/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java @@ -202,7 +202,8 @@ void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfSubscribeEvent() { lastMessageDto.setSentFrom("vasil@gmail.com"); lastMessageDto.setLastMessage("Hi"); - var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), lastMessageDto); + var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), + lastMessageDto); saveContactEvent(event); //Stored subscription results for testing CompletableFuture resultKeeper = new CompletableFuture<>(); @@ -218,9 +219,7 @@ void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfSubscribeEvent() { assertThat(notifications).extracting("email").contains("vasil@gmail.com"); assertThat(notifications).extracting("topicId").contains(topicId); assertThat(notifications).extracting("status").contains(ONLINE); - assertThat(notifications).extracting("unreadMessages").isNotNull(); assertThat(notifications).extracting("lastRead").isNotNull(); - assertThat(notifications).extracting("lastMessage").isNotNull(); } @Test @@ -234,7 +233,8 @@ void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfAnyContactSubscribedTo lastMessageDto.setSentFrom("vasil@gmail.com"); lastMessageDto.setLastMessage("Hi"); - var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), lastMessageDto); + var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), + lastMessageDto); saveContactEvent(event); //Stored subscription results for testing CompletableFuture resultKeeper = new CompletableFuture<>(); @@ -253,9 +253,7 @@ void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfAnyContactSubscribedTo assertThat(notifications).extracting("email").contains("vasil@gmail.com"); assertThat(notifications).extracting("topicId").contains(topicId); assertThat(notifications).extracting("status").contains(SUBSCRIBED); - assertThat(notifications).extracting("unreadMessages").contains(0); assertThat(notifications).extracting("lastRead").isNotNull(); - assertThat(notifications).extracting("lastMessage").isNotNull(); } //----------------------------------- diff --git a/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java b/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java index ae4094f6..dde09bcd 100644 --- a/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java +++ b/src/test/java/com/chat/yourway/unit/service/impl/NotificationServiceImplTest.java @@ -4,8 +4,6 @@ import static com.chat.yourway.model.event.EventType.ONLINE; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -16,7 +14,6 @@ import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.NotificationServiceImpl; import com.chat.yourway.service.interfaces.ContactEventService; -import com.chat.yourway.service.interfaces.MessageService; import java.time.LocalDateTime; import java.util.Arrays; import java.util.List; @@ -30,9 +27,6 @@ @ExtendWith(MockitoExtension.class) class NotificationServiceImplTest { - @Mock - private MessageService messageService; - @Mock private ContactEventService contactEventService; @@ -43,8 +37,8 @@ class NotificationServiceImplTest { private NotificationServiceImpl notificationService; @Test - @DisplayName("notifyTopicSubscribers should return a list of notifications with unread message counts") - void notifyTopicSubscribers_shouldReturnListOfNotificationsWithUnreadMessageCounts() { + @DisplayName("notifyTopicSubscribers should return a list of notifications") + void notifyTopicSubscribers_shouldReturnListOfNotifications() { // Given Integer topicId = 1; var lastMessageDto = new LastMessageResponseDto(); @@ -64,8 +58,6 @@ void notifyTopicSubscribers_shouldReturnListOfNotificationsWithUnreadMessageCoun messageNotification.setTopicId(e.getTopicId()); messageNotification.setStatus(e.getEventType()); messageNotification.setLastRead(e.getTimestamp()); - messageNotification.setUnreadMessages(1); - messageNotification.setLastMessage(e.getLastMessage()); return messageNotification; }) .toList(); @@ -73,9 +65,6 @@ void notifyTopicSubscribers_shouldReturnListOfNotificationsWithUnreadMessageCoun when(contactEventService.getAllByTopicId(topicId)).thenReturn(events); when(notificationMapper.toNotificationResponseDto(any())) .thenReturn(expectedNotifications.get(0), expectedNotifications.get(1)); - when(messageService.countMessagesBetweenTimestampByTopicId(eq(topicId), anyString(), - any(LocalDateTime.class))) - .thenReturn(1, 1); // When List result = notificationService.notifyTopicSubscribers( @@ -84,8 +73,6 @@ void notifyTopicSubscribers_shouldReturnListOfNotificationsWithUnreadMessageCoun // Then assertEquals(expectedNotifications, result, "Should return the expected list of notifications"); verify(notificationMapper, times(2)).toNotificationResponseDto(any()); - verify(messageService, times(2)).countMessagesBetweenTimestampByTopicId(eq(topicId), - anyString(), any(LocalDateTime.class)); } }