From b21016718ad1ea7622a3f00ed129c62114adf8e2 Mon Sep 17 00:00:00 2001 From: Dmytro Trotsenko <106109140+Troha7@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:21:55 +0200 Subject: [PATCH 1/5] Develop (#72) * fix: fixed notification and event type * bugfix: fixed disconnect from websocket. Set time to first message. * fix: refactored and optimized notifications --- .../TopicNotificationResponseDto.java | 2 +- .../listener/StompSubscriptionListener.java | 9 +++-- .../mapper/MessageNotificationMapper.java | 16 -------- .../yourway/mapper/NotificationMapper.java | 22 ++++++++++ .../yourway/model/event/ContactEvent.java | 4 +- .../service/ChatMessageServiceImpl.java | 10 ++--- .../service/ChatNotificationServiceImpl.java | 40 +++++++++++++++++-- .../service/ContactEventServiceImpl.java | 17 +++++--- .../service/NotificationServiceImpl.java | 38 +++++++++--------- .../interfaces/ChatNotificationService.java | 16 +++++++- .../interfaces/ContactEventService.java | 2 +- .../interfaces/NotificationService.java | 14 +++++-- src/main/resources/application.properties | 2 +- .../controller/ChatControllerTest.java | 4 +- .../impl/ContactEventServiceImplTest.java | 24 ++++++----- .../impl/NotificationServiceImplTest.java | 12 +++--- 16 files changed, 153 insertions(+), 79 deletions(-) delete mode 100644 src/main/java/com/chat/yourway/mapper/MessageNotificationMapper.java create mode 100644 src/main/java/com/chat/yourway/mapper/NotificationMapper.java diff --git a/src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java b/src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java index 5de5165d..744604f4 100644 --- a/src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java @@ -13,7 +13,7 @@ @ToString public class TopicNotificationResponseDto { - private TopicResponseDto topic; + private Integer topicId; private Integer unreadMessages; diff --git a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java index bf0766cc..2b38f4e7 100644 --- a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java +++ b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java @@ -44,8 +44,11 @@ public void handleWebSocketSubscribeListener(SessionSubscribeEvent event) { if (isTopicDestination(destination)) { lastMessageDto = contactEventService.getByTopicIdAndEmail(getTopicId(event), email) .getLastMessage(); + int unreadMessages = contactEventService.getByTopicIdAndEmail(getTopicId(event), email) + .getUnreadMessages(); + var contactEvent = new ContactEvent(email, getTopicId(event), SUBSCRIBED, - getTimestamp(event), lastMessageDto); + getTimestamp(event), unreadMessages, lastMessageDto); contactEventService.updateEventTypeByEmail(ONLINE, email); contactEventService.save(contactEvent); } @@ -58,7 +61,7 @@ public void handleWebSocketSubscribeListener(SessionSubscribeEvent event) { } if (destination.equals(USER_DESTINATION + properties.getNotifyPrefix() + TOPICS_DESTINATION)) { - chatNotificationService.notifyAllPublicTopics(getEmail(event)); + chatNotificationService.notifyAllTopics(getEmail(event)); } log.info("Contact [{}] subscribe to [{}]", email, destination); @@ -72,7 +75,7 @@ public void handleWebSocketUnsubscribeListener(SessionUnsubscribeEvent event) { try { if (isTopicDestination(destination)) { var contactEvent = new ContactEvent(email, getTopicId(event), ONLINE, - getTimestamp(event), lastMessageDto); + getTimestamp(event), 0, lastMessageDto); contactEventService.save(contactEvent); } diff --git a/src/main/java/com/chat/yourway/mapper/MessageNotificationMapper.java b/src/main/java/com/chat/yourway/mapper/MessageNotificationMapper.java deleted file mode 100644 index 7a80c96e..00000000 --- a/src/main/java/com/chat/yourway/mapper/MessageNotificationMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.chat.yourway.mapper; - -import com.chat.yourway.dto.response.MessageNotificationResponseDto; -import com.chat.yourway.model.event.ContactEvent; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; - -@Mapper(componentModel = "spring") -public interface MessageNotificationMapper { - - @Mapping(target = "status", source = "eventType") - @Mapping(target = "lastRead", source = "timestamp") - @Mapping(target = "email", source = "email") - MessageNotificationResponseDto toNotificationResponseDto(ContactEvent event); - -} diff --git a/src/main/java/com/chat/yourway/mapper/NotificationMapper.java b/src/main/java/com/chat/yourway/mapper/NotificationMapper.java new file mode 100644 index 00000000..591a5454 --- /dev/null +++ b/src/main/java/com/chat/yourway/mapper/NotificationMapper.java @@ -0,0 +1,22 @@ +package com.chat.yourway.mapper; + +import com.chat.yourway.dto.response.MessageNotificationResponseDto; +import com.chat.yourway.dto.response.TopicNotificationResponseDto; +import com.chat.yourway.model.event.ContactEvent; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(componentModel = "spring") +public interface NotificationMapper { + + @Mapping(target = "status", source = "eventType") + @Mapping(target = "lastRead", source = "timestamp") + @Mapping(target = "email", source = "email") + MessageNotificationResponseDto toMessageNotificationResponseDto(ContactEvent event); + + @Mapping(target = "topicId", source = "topicId") + @Mapping(target = "unreadMessages", source = "unreadMessages") + @Mapping(target = "lastMessage", source = "lastMessage") + TopicNotificationResponseDto toTopicNotificationResponseDto(ContactEvent event); + +} 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 e782d795..8f7e9f15 100644 --- a/src/main/java/com/chat/yourway/model/event/ContactEvent.java +++ b/src/main/java/com/chat/yourway/model/event/ContactEvent.java @@ -26,16 +26,18 @@ public class ContactEvent { private Integer topicId; private EventType eventType; private LocalDateTime timestamp; + private int unreadMessages; private LastMessageResponseDto lastMessage; public ContactEvent(String email, Integer topicId, EventType eventType, LocalDateTime timestamp, - LastMessageResponseDto lastMessage) { + int unreadMessages, LastMessageResponseDto lastMessage) { this.id = email + "_" + topicId; this.email = email; this.topicId = topicId; this.eventType = eventType; this.timestamp = timestamp; + this.unreadMessages = unreadMessages; this.lastMessage = lastMessage; } diff --git a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java index 8191aee0..5fac88f1 100644 --- a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java @@ -69,16 +69,16 @@ public List sendMessageHistoryByTopicId(Integer topicId, private void sendToTopic(Integer topicId, MessageResponseDto messageDto) { var lastMessageDto = new LastMessageResponseDto(); - lastMessageDto.setTimestamp(messageDto.getTimestamp()); - lastMessageDto.setSentFrom(messageDto.getSentFrom()); - lastMessageDto.setLastMessage(messageDto.getContent()); + lastMessageDto.setTimestamp(messageDto.getTimestamp()); + lastMessageDto.setSentFrom(messageDto.getSentFrom()); + lastMessageDto.setLastMessage(messageDto.getContent()); - contactEventService.setLastMessageToAllTopicSubscribers(topicId, lastMessageDto); + contactEventService.updateMessageInfoForAllTopicSubscribers(topicId, lastMessageDto); simpMessagingTemplate.convertAndSend(toTopicDestination(topicId), messageDto); chatNotificationService.notifyTopicSubscribers(topicId); - chatNotificationService.notifyAllWhoSubscribedToTopic(topicId); + chatNotificationService.updateNotificationForAllWhoSubscribedToTopic(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 a3b5772b..c833f187 100644 --- a/src/main/java/com/chat/yourway/service/ChatNotificationServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ChatNotificationServiceImpl.java @@ -27,25 +27,57 @@ public void notifyTopicSubscribers(Integer topicId) { .forEach(n -> simpMessagingTemplate.convertAndSendToUser( n.getEmail(), toNotifyMessageDest(topicId), notifications)); - log.trace("All subscribers was notified by topic id = [{}]", topicId); + log.info("All subscribers was notified by topic id = [{}]", topicId); } @Override public void notifyAllWhoSubscribedToSameUserTopic(String userEmail) { + log.trace("Started notifyAllWhoSubscribedToSameUserTopic, user email = [{}]", userEmail); + contactEventService.getAllByEmail(userEmail) .forEach(e -> notifyTopicSubscribers(e.getTopicId())); + + log.info("All subscribers who subscribed to same topic was notified, email = [{}]", userEmail); } @Override - public void notifyAllPublicTopics(String email){ - var notifiedTopics = notificationService.notifyAllPublicTopicsByEmail(email); + public void notifyAllTopics(String email) { + log.trace("Started notifyAllTopics, email = [{}]", email); + + var notifiedTopics = notificationService.notifyAllTopicsByEmail(email); simpMessagingTemplate.convertAndSendToUser(email, toNotifyTopicsDest(), notifiedTopics); + + log.info("All topics was notified for user email = [{}]", email); } @Override public void notifyAllWhoSubscribedToTopic(Integer topicId) { + log.trace("Started notifyAllWhoSubscribedToTopic, topicId = [{}]", topicId); + + contactEventService.getAllByTopicId(topicId) + .forEach(e -> notifyAllTopics(e.getEmail())); + + log.info("All subscribed users was notified, topicId = [{}]", topicId); + } + + @Override + public void updateNotificationForAllTopics(String email) { + log.trace("Started updateNotificationForAllTopics, email = [{}]", email); + + var notifiedTopics = notificationService.updateTopicNotification(email); + simpMessagingTemplate.convertAndSendToUser(email, toNotifyTopicsDest(), notifiedTopics); + + log.info("All topics for user was notified, email = [{}]", email); + } + + @Override + public void updateNotificationForAllWhoSubscribedToTopic(Integer topicId) { + log.trace("Started updateNotificationForAllWhoSubscribedToTopic, topicId = [{}]", topicId); + contactEventService.getAllByTopicId(topicId) - .forEach(e -> notifyAllPublicTopics(e.getEmail())); + .forEach(e -> updateNotificationForAllTopics(e.getEmail())); + + log.info("Topic notifications was updated for all subscribed users, topicId = [{}]", topicId); } private String toNotifyMessageDest(Integer topicId) { diff --git a/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java b/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java index b742d8dc..aace67d0 100644 --- a/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java @@ -1,6 +1,7 @@ package com.chat.yourway.service; import static com.chat.yourway.model.event.EventType.ONLINE; +import static com.chat.yourway.model.event.EventType.SUBSCRIBED; import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; @@ -31,7 +32,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(), null)); + .orElse(new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), 0, null)); } @Override @@ -62,15 +63,21 @@ public List getAllByTopicId(Integer topicId) { } @Override - public void setLastMessageToAllTopicSubscribers(Integer topicId, LastMessageResponseDto message) { - log.trace("Started setLastMessageToAllTopicSubscribers, topic id [{}], last message [{}]", + public void updateMessageInfoForAllTopicSubscribers(Integer topicId, + LastMessageResponseDto message) { + log.trace("Started updateMessageInfoForAllTopicSubscribers, topic id [{}], last message [{}]", topicId, message); List events = getAllByTopicId(topicId).stream() - .peek(e -> e.setLastMessage(message)) + .peek(e -> { + if (!e.getEventType().equals(SUBSCRIBED)) { + e.setUnreadMessages(e.getUnreadMessages() + 1); + } + e.setLastMessage(message); + }) .toList(); - log.trace("Last message [{}] was set to all topic id [{}] subscribers", message, topicId); + log.trace("Message info [{}] was updated for all topic id [{}] subscribers", message, topicId); contactEventRedisRepository.saveAll(events); } diff --git a/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java b/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java index f23060ad..6639f943 100644 --- a/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java @@ -2,12 +2,11 @@ import com.chat.yourway.dto.response.MessageNotificationResponseDto; import com.chat.yourway.dto.response.TopicNotificationResponseDto; -import com.chat.yourway.mapper.MessageNotificationMapper; +import com.chat.yourway.mapper.NotificationMapper; 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; @@ -19,39 +18,40 @@ public class NotificationServiceImpl implements NotificationService { private final ContactEventService contactEventService; - private final TopicService topicService; private final MessageService messageService; - private final MessageNotificationMapper notificationMapper; + private final NotificationMapper notificationMapper; @Override public List notifyTopicSubscribers(Integer topicId) { log.trace("Started notifyTopicSubscribers by topic id [{}]", topicId); return contactEventService.getAllByTopicId(topicId).stream() - .map(notificationMapper::toNotificationResponseDto) + .map(notificationMapper::toMessageNotificationResponseDto) .toList(); } @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; - }) + public List notifyAllTopicsByEmail(String email) { + + return contactEventService.getAllByEmail(email).stream() + .peek(this::countUnreadMessages) + .map(notificationMapper::toTopicNotificationResponseDto) + .toList(); + } + + @Override + public List updateTopicNotification(String email) { + return contactEventService.getAllByEmail(email).stream() + .map(notificationMapper::toTopicNotificationResponseDto) .toList(); } - private int countUnreadMessages(ContactEvent event) { - return messageService.countMessagesBetweenTimestampByTopicId( + private void countUnreadMessages(ContactEvent event) { + event.setUnreadMessages(messageService.countMessagesBetweenTimestampByTopicId( event.getTopicId(), event.getEmail(), - event.getTimestamp()); + event.getTimestamp())); + contactEventService.save(event); } } 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 aef3056a..d05ff51f 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/ChatNotificationService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/ChatNotificationService.java @@ -21,7 +21,7 @@ public interface ChatNotificationService { * * @param userEmail user email. */ - void notifyAllPublicTopics(String userEmail); + void notifyAllTopics(String userEmail); /** * Notify everyone who is subscribed to the same topic. @@ -30,4 +30,18 @@ public interface ChatNotificationService { */ void notifyAllWhoSubscribedToTopic(Integer topicId); + /** + * Update topic notification for user who subscribed to the same topic. + * + * @param topicId The id of the topic. + */ + void updateNotificationForAllWhoSubscribedToTopic(Integer topicId); + + /** + * Update notification for all topics. + * + * @param email user email. + */ + void updateNotificationForAllTopics(String email); + } 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 ae199c9f..69f225ff 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java @@ -47,6 +47,6 @@ public interface ContactEventService { * @param topicId topic id. * @param lastMessageDto last message Dto. */ - void setLastMessageToAllTopicSubscribers(Integer topicId, LastMessageResponseDto lastMessageDto); + void updateMessageInfoForAllTopicSubscribers(Integer topicId, LastMessageResponseDto lastMessageDto); } 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 a14ab271..b549bc63 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/NotificationService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/NotificationService.java @@ -15,11 +15,19 @@ public interface NotificationService { List notifyTopicSubscribers(Integer topicId); /** - * Retrieves a list of notifying all public topics. + * Retrieves a list of notifying all topics. * * @param email user email. - * @return A list of public topic's information. + * @return A list of topic's information. */ - List notifyAllPublicTopicsByEmail(String email); + List notifyAllTopicsByEmail(String email); + + /** + * Update info and return a list of notifying all topics. + * + * @param email user email. + * @return A list of topic's information. + */ + List updateTopicNotification(String email); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ecf8cbc5..5573639b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -16,7 +16,7 @@ spring.data.redis.password=${REDIS_PASSWORD:admin} #Hibernate spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect -#spring.jpa.show-sql=true +spring.jpa.show-sql=false spring.jpa.properties.hibernate.format_sql=true spring.jpa.hibernate.ddl-auto=validate 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 86063ceb..6d2ab90f 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,7 @@ void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfSubscribeEvent() { lastMessageDto.setSentFrom("vasil@gmail.com"); lastMessageDto.setLastMessage("Hi"); - var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), + var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, lastMessageDto); saveContactEvent(event); //Stored subscription results for testing @@ -233,7 +233,7 @@ void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfAnyContactSubscribedTo lastMessageDto.setSentFrom("vasil@gmail.com"); lastMessageDto.setLastMessage("Hi"); - var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), + var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, lastMessageDto); saveContactEvent(event); //Stored subscription results for testing 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 da8fb7b5..7c263f01 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 @@ -41,7 +41,8 @@ void save_shouldSaveToRepository() { // Given String email = "vasil@gmail.com"; int topicId = 1; - ContactEvent contactEvent = new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), null); + ContactEvent contactEvent = new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), 0, + null); // When contactEventService.save(contactEvent); @@ -56,7 +57,8 @@ void getByTopicIdAndEmail_shouldReturnContactEventFromRepository() { // Given Integer topicId = 1; String email = "vasil@gmail.com"; - ContactEvent expectedContactEvent = new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), null); + ContactEvent expectedContactEvent = new ContactEvent(email, topicId, ONLINE, + LocalDateTime.now(), 0, null); when(contactEventRedisRepository.findById(email + "_" + topicId)) .thenReturn(Optional.of(expectedContactEvent)); @@ -91,8 +93,8 @@ void getAllByEmail_shouldReturnContactEventsFromRepository() { // Given String email = "vasil@gmail.com"; List expectedContactEvents = Arrays.asList( - new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), null), - new ContactEvent(email, 2, OFFLINE, LocalDateTime.now(), null) + new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), 0, null), + new ContactEvent(email, 2, OFFLINE, LocalDateTime.now(), 0, null) ); when(contactEventRedisRepository.findAllByEmail(email)).thenReturn(expectedContactEvents); @@ -110,8 +112,8 @@ void updateEventTypeByEmail_shouldUpdateEventTypesInRepository() { String email = "vasil@gmail.com"; EventType newEventType = OFFLINE; List events = Arrays.asList( - new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), null), - new ContactEvent(email, 2, ONLINE, LocalDateTime.now(), null) + new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), 0, null), + new ContactEvent(email, 2, ONLINE, LocalDateTime.now(), 0, null) ); when(contactEventRedisRepository.findAllByEmail(email)).thenReturn(events); @@ -129,8 +131,8 @@ void getAllByTopicId_shouldReturnContactEventsFromRepository() { // Given Integer topicId = 1; List expectedContactEvents = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), null), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), null) + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, null), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), 0, null) ); when(contactEventRedisRepository.findAllByTopicId(topicId)).thenReturn(expectedContactEvents); @@ -152,13 +154,13 @@ void setLastMessageToAllTopicSubscribers_shouldUpdateLastMessagesInRepository() lastMessageDto.setLastMessage("New message"); List events = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), null), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), null) + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, null), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), 0, null) ); when(contactEventRedisRepository.findAllByTopicId(topicId)).thenReturn(events); // When - contactEventService.setLastMessageToAllTopicSubscribers(topicId, lastMessageDto); + contactEventService.updateMessageInfoForAllTopicSubscribers(topicId, lastMessageDto); // Then events.forEach(e -> e.setLastMessage(lastMessageDto)); 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 dde09bcd..ab82a331 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,7 +10,7 @@ import com.chat.yourway.dto.response.LastMessageResponseDto; import com.chat.yourway.dto.response.MessageNotificationResponseDto; -import com.chat.yourway.mapper.MessageNotificationMapper; +import com.chat.yourway.mapper.NotificationMapper; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.NotificationServiceImpl; import com.chat.yourway.service.interfaces.ContactEventService; @@ -31,7 +31,7 @@ class NotificationServiceImplTest { private ContactEventService contactEventService; @Mock - private MessageNotificationMapper notificationMapper; + private NotificationMapper notificationMapper; @InjectMocks private NotificationServiceImpl notificationService; @@ -47,8 +47,8 @@ void notifyTopicSubscribers_shouldReturnListOfNotifications() { lastMessageDto.setLastMessage("Hello"); List events = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), lastMessageDto), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), lastMessageDto) + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, lastMessageDto), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), 0, lastMessageDto) ); var expectedNotifications = events.stream() @@ -63,7 +63,7 @@ void notifyTopicSubscribers_shouldReturnListOfNotifications() { .toList(); when(contactEventService.getAllByTopicId(topicId)).thenReturn(events); - when(notificationMapper.toNotificationResponseDto(any())) + when(notificationMapper.toMessageNotificationResponseDto(any())) .thenReturn(expectedNotifications.get(0), expectedNotifications.get(1)); // When @@ -72,7 +72,7 @@ void notifyTopicSubscribers_shouldReturnListOfNotifications() { // Then assertEquals(expectedNotifications, result, "Should return the expected list of notifications"); - verify(notificationMapper, times(2)).toNotificationResponseDto(any()); + verify(notificationMapper, times(2)).toMessageNotificationResponseDto(any()); } } From 39376dd596e55025321fd617c2c74070328dc947 Mon Sep 17 00:00:00 2001 From: Dmytro Trotsenko <106109140+Troha7@users.noreply.github.com> Date: Thu, 28 Mar 2024 22:46:45 +0200 Subject: [PATCH 2/5] Develop (#74) * fix: fixed notification and event type * bugfix: fixed disconnect from websocket. Set time to first message. * fix: refactored and optimized notifications * refactor: refactored and optimized request to get all topics --- .../yourway/controller/TopicController.java | 7 ++-- .../dto/response/TopicInfoResponseDto.java | 26 ++++++++++++++ .../com/chat/yourway/mapper/TopicMapper.java | 3 ++ .../java/com/chat/yourway/model/Topic.java | 4 +-- .../yourway/repository/TopicRepository.java | 26 +++++++------- .../yourway/service/TopicServiceImpl.java | 13 +++---- .../service/interfaces/TopicService.java | 35 +++++++++---------- .../controller/TopicControllerTest.java | 6 +--- .../service/impl/TopicServiceImplTest.java | 11 ++++-- 9 files changed, 81 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/chat/yourway/dto/response/TopicInfoResponseDto.java diff --git a/src/main/java/com/chat/yourway/controller/TopicController.java b/src/main/java/com/chat/yourway/controller/TopicController.java index 5bc7f297..ad7f6117 100644 --- a/src/main/java/com/chat/yourway/controller/TopicController.java +++ b/src/main/java/com/chat/yourway/controller/TopicController.java @@ -8,6 +8,7 @@ import com.chat.yourway.dto.request.TopicRequestDto; import com.chat.yourway.dto.response.ApiErrorResponseDto; import com.chat.yourway.dto.response.ContactResponseDto; +import com.chat.yourway.dto.response.TopicInfoResponseDto; import com.chat.yourway.dto.response.TopicResponseDto; import com.chat.yourway.service.interfaces.TopicService; import com.chat.yourway.service.interfaces.TopicSubscriberService; @@ -149,7 +150,7 @@ public TopicResponseDto findById(@PathVariable Integer id) { content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))) }) @GetMapping(path = "/all", produces = APPLICATION_JSON_VALUE) - public List findAllPublic() { + public List findAllPublic() { return topicService.findAllPublic(); } @@ -322,7 +323,7 @@ public void removeToFavouriteTopic( content = @Content(schema = @Schema(implementation = ApiErrorResponseDto.class))) }) @GetMapping(path = "/favourite", produces = APPLICATION_JSON_VALUE) - public List findAllFavouriteTopics( + public List findAllFavouriteTopics( @AuthenticationPrincipal UserDetails userDetails) { return topicService.findAllFavouriteTopics(userDetails); } @@ -333,7 +334,7 @@ public List findAllFavouriteTopics( @ApiResponse(responseCode = "200", description = SUCCESSFULLY_FOUND_TOPIC) }) @GetMapping(path = "/popular/public", produces = APPLICATION_JSON_VALUE) - public List findAllPopularPublicTopics() { + public List findAllPopularPublicTopics() { return topicService.findPopularPublicTopics(); } diff --git a/src/main/java/com/chat/yourway/dto/response/TopicInfoResponseDto.java b/src/main/java/com/chat/yourway/dto/response/TopicInfoResponseDto.java new file mode 100644 index 00000000..d1dec5db --- /dev/null +++ b/src/main/java/com/chat/yourway/dto/response/TopicInfoResponseDto.java @@ -0,0 +1,26 @@ +package com.chat.yourway.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@AllArgsConstructor +@NoArgsConstructor +@Setter +@Getter +@ToString +public class TopicInfoResponseDto { + @Schema(description = "ID", example = "1") + private Integer id; + @Schema(description = "New Topic name", example = "My programming topic") + private String topicName; + @Schema(description = "Email of Topic creator", example = "example@gmail.com") + private String createdBy; + @Schema(description = "Created time") + private LocalDateTime createdAt; + +} diff --git a/src/main/java/com/chat/yourway/mapper/TopicMapper.java b/src/main/java/com/chat/yourway/mapper/TopicMapper.java index 0d71fb5e..2dff6d6e 100644 --- a/src/main/java/com/chat/yourway/mapper/TopicMapper.java +++ b/src/main/java/com/chat/yourway/mapper/TopicMapper.java @@ -1,5 +1,6 @@ package com.chat.yourway.mapper; +import com.chat.yourway.dto.response.TopicInfoResponseDto; import com.chat.yourway.dto.response.TopicResponseDto; import com.chat.yourway.model.Topic; import java.util.List; @@ -12,6 +13,8 @@ public interface TopicMapper { TopicResponseDto toResponseDto(Topic topic); List toListResponseDto(List topics); + List toListInfoResponseDto(List topics); + @Mapping(target = "messages", ignore = true) Topic toEntity(TopicResponseDto topicResponseDto); diff --git a/src/main/java/com/chat/yourway/model/Topic.java b/src/main/java/com/chat/yourway/model/Topic.java index 0eca84d3..1e05c306 100644 --- a/src/main/java/com/chat/yourway/model/Topic.java +++ b/src/main/java/com/chat/yourway/model/Topic.java @@ -48,7 +48,7 @@ public class Topic { @Column(name = "created_at", nullable = false) private LocalDateTime createdAt; - @ManyToMany(fetch = FetchType.EAGER) + @ManyToMany(fetch = FetchType.LAZY) @JoinTable( schema = "chat", name = "topic_tag", @@ -56,7 +56,7 @@ public class Topic { inverseJoinColumns = @JoinColumn(name = "tag_id")) private Set tags; - @OneToMany(mappedBy = "topic", fetch = FetchType.EAGER, cascade = CascadeType.ALL) + @OneToMany(mappedBy = "topic", fetch = FetchType.LAZY, cascade = CascadeType.ALL) private Set topicSubscribers; @OneToMany(mappedBy = "topic", fetch = FetchType.LAZY, cascade = CascadeType.ALL) diff --git a/src/main/java/com/chat/yourway/repository/TopicRepository.java b/src/main/java/com/chat/yourway/repository/TopicRepository.java index 5c0a0b53..de34ae69 100644 --- a/src/main/java/com/chat/yourway/repository/TopicRepository.java +++ b/src/main/java/com/chat/yourway/repository/TopicRepository.java @@ -18,10 +18,10 @@ public interface TopicRepository extends JpaRepository { @Query( value = """ - SELECT * - FROM chat.topic t - WHERE to_tsvector('english', t.topic_name) @@ to_tsquery('english', :query) - """, + SELECT * + FROM chat.topic t + WHERE to_tsvector('english', t.topic_name) @@ to_tsquery('english', :query) + """, nativeQuery = true) List findAllByTopicName(String query); @@ -31,18 +31,16 @@ WHERE to_tsvector('english', t.topic_name) @@ to_tsquery('english', :query) @Query( "select t from Topic t join fetch t.topicSubscribers ts " - + "where ts.contact.email = :contactEmail and ts.isFavouriteTopic = true") + + "where ts.contact.email = :contactEmail and ts.isFavouriteTopic = true") List findAllFavouriteTopicsByContactEmail(String contactEmail); - boolean existsByIdAndIsPublic(int topicId, boolean isPublic); - @Query(nativeQuery = true, value = - "SELECT t.*, COUNT(ts.id) AS ts_count, COUNT(m.id) AS m_count " + - "FROM chat.topic t " + - "JOIN chat.topic_subscriber ts ON t.id = ts.topic_id " + - "JOIN chat.message m ON t.id = m.topic_id " + - "WHERE t.is_public = true " + - "GROUP BY t.id " + - "ORDER BY ts_count DESC, m_count DESC") + "SELECT t.*, COUNT(ts.id) AS ts_count, COUNT(m.id) AS m_count " + + "FROM chat.topic t " + + "JOIN chat.topic_subscriber ts ON t.id = ts.topic_id " + + "JOIN chat.message m ON t.id = m.topic_id " + + "WHERE t.is_public = true " + + "GROUP BY t.id " + + "ORDER BY ts_count DESC, m_count DESC") List findPopularPublicTopics(); } diff --git a/src/main/java/com/chat/yourway/service/TopicServiceImpl.java b/src/main/java/com/chat/yourway/service/TopicServiceImpl.java index 60ad4913..2470e70f 100644 --- a/src/main/java/com/chat/yourway/service/TopicServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/TopicServiceImpl.java @@ -5,6 +5,7 @@ import com.chat.yourway.dto.request.TagRequestDto; import com.chat.yourway.dto.request.TopicPrivateRequestDto; import com.chat.yourway.dto.request.TopicRequestDto; +import com.chat.yourway.dto.response.TopicInfoResponseDto; import com.chat.yourway.dto.response.TopicResponseDto; import com.chat.yourway.exception.ContactEmailNotExist; import com.chat.yourway.exception.TopicAccessException; @@ -100,13 +101,13 @@ public TopicResponseDto findByName(String name) { } @Override - public List findAllPublic() { + public List findAllPublic() { log.trace("Started findAllPublic"); List topics = topicRepository.findAllByIsPublicIsTrue(); log.trace("All public topics was found"); - return topicMapper.toListResponseDto(topics); + return topicMapper.toListInfoResponseDto(topics); } @Override @@ -173,15 +174,15 @@ public String generatePrivateName(String sendTo, String email) { } @Override - public List findAllFavouriteTopics(UserDetails userDetails) { + public List findAllFavouriteTopics(UserDetails userDetails) { String contactEmail = userDetails.getUsername(); - return topicMapper.toListResponseDto( + return topicMapper.toListInfoResponseDto( topicRepository.findAllFavouriteTopicsByContactEmail(contactEmail)); } @Override - public List findPopularPublicTopics() { - return topicMapper.toListResponseDto(topicRepository.findPopularPublicTopics()); + public List findPopularPublicTopics() { + return topicMapper.toListInfoResponseDto(topicRepository.findPopularPublicTopics()); } private Topic createOrUpdateTopic(Topic topic, TopicRequestDto topicRequestDto, String email) { diff --git a/src/main/java/com/chat/yourway/service/interfaces/TopicService.java b/src/main/java/com/chat/yourway/service/interfaces/TopicService.java index 41e1c974..3e305d8a 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/TopicService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/TopicService.java @@ -3,16 +3,15 @@ import com.chat.yourway.dto.request.TagRequestDto; import com.chat.yourway.dto.request.TopicPrivateRequestDto; import com.chat.yourway.dto.request.TopicRequestDto; +import com.chat.yourway.dto.response.TopicInfoResponseDto; import com.chat.yourway.dto.response.TopicResponseDto; import com.chat.yourway.exception.TopicAccessException; import com.chat.yourway.exception.TopicNotFoundException; import com.chat.yourway.exception.ValueNotUniqException; import com.chat.yourway.model.Tag; -import com.chat.yourway.model.Topic; -import org.springframework.security.core.userdetails.UserDetails; - import java.util.List; import java.util.Set; +import org.springframework.security.core.userdetails.UserDetails; public interface TopicService { @@ -20,7 +19,7 @@ public interface TopicService { * Creates a new topic with the specified email of the creator. * * @param topicRequestDto Request object for creating topic. - * @param email The email of the creator. + * @param email The email of the creator. * @return Created topic. * @throws ValueNotUniqException If the topic name already in use. */ @@ -31,7 +30,7 @@ public interface TopicService { * contacts. * * @param topicPrivateDto Request object for creating topic. - * @param email The email of the creator. + * @param email The email of the creator. * @return Created private topic. * @throws ValueNotUniqException If the topic name already in use. */ @@ -40,12 +39,12 @@ public interface TopicService { /** * Update an existing topic with the specified email of the creator. * - * @param topicId The ID of the topic to find. + * @param topicId The ID of the topic to find. * @param topicRequestDto Request object for creating topic. - * @param email The email of the creator. + * @param email The email of the creator. * @return Updated topic. * @throws ValueNotUniqException If the topic name already in use. - * @throws TopicAccessException if the email is not the creator of the topic. + * @throws TopicAccessException if the email is not the creator of the topic. */ TopicResponseDto update(Integer topicId, TopicRequestDto topicRequestDto, String email); @@ -72,12 +71,12 @@ public interface TopicService { * * @return A list of public topics. */ - List findAllPublic(); + List findAllPublic(); /** * Deletes a topic by ID if the specified email is the creator of the topic. * - * @param id The ID of the topic to delete. + * @param id The ID of the topic to delete. * @param email The email of the user. * @throws TopicAccessException if the email is not the creator of the topic. */ @@ -88,7 +87,7 @@ public interface TopicService { * * @param tagName The unique name of the tag for which topics are to be retrieved. * @return A list of {@link TopicResponseDto} objects associated with the given tag. An empty list - * is returned if no topics are found for the specified tag. + * is returned if no topics are found for the specified tag. */ List findTopicsByTagName(String tagName); @@ -116,7 +115,7 @@ public interface TopicService { * separated by "<->" symbol. * * @param sendTo Email address of the receiver. - * @param email Email address of the sender. + * @param email Email address of the sender. * @return Unique private topic name. */ String generatePrivateName(String sendTo, String email); @@ -125,20 +124,20 @@ public interface TopicService { * Retrieves a list of favorite topics for the specified user. * * @param userDetails The details of the user for whom favorite topics are to be retrieved. - * @return A list of {@code TopicResponseDto} objects representing the user's favorite topics. + * @return A list of {@code TopicInfoResponseDto} objects representing the user's favorite topics. */ - List findAllFavouriteTopics(UserDetails userDetails); + List findAllFavouriteTopics(UserDetails userDetails); /** * Retrieves a list of popular public topics. *

- * This method returns a list of {@code TopicResponseDto} objects representing popular topics - * that are marked as public. The popularity is determined by the number of subscribers and messages + * This method returns a list of {@code TopicResponseDto} objects representing popular topics that + * are marked as public. The popularity is determined by the number of subscribers and messages * associated with each topic. * - * @return A list of {@code TopicResponseDto} objects representing popular public topics. + * @return A list of {@code TopicInfoResponseDto} objects representing popular public topics. * @see TopicResponseDto */ - List findPopularPublicTopics(); + List findPopularPublicTopics(); } diff --git a/src/test/java/com/chat/yourway/integration/controller/TopicControllerTest.java b/src/test/java/com/chat/yourway/integration/controller/TopicControllerTest.java index 299d1673..95b3a676 100644 --- a/src/test/java/com/chat/yourway/integration/controller/TopicControllerTest.java +++ b/src/test/java/com/chat/yourway/integration/controller/TopicControllerTest.java @@ -515,11 +515,7 @@ public void findAllPublic_shouldReturnListOfAllPublicTopics() throws Exception { .andExpect(jsonPath("$[0].createdBy").value(savedTopics.get(0).getCreatedBy())) .andExpect(jsonPath("$[1].topicName").value(savedTopics.get(1).getTopicName())) .andExpect(jsonPath("$[1].createdBy").value(savedTopics.get(1).getCreatedBy())) - .andExpect(jsonPath("$[*].createdAt").isNotEmpty()) - .andExpect(jsonPath("$[0].isPublic").value(true)) - .andExpect(jsonPath("$[1].isPublic").value(true)) - .andExpect(jsonPath("$[*].tags").isArray()) - .andExpect(jsonPath("$[*].topicSubscribers").isArray()); + .andExpect(jsonPath("$[*].createdAt").isNotEmpty()); } @Test diff --git a/src/test/java/com/chat/yourway/unit/service/impl/TopicServiceImplTest.java b/src/test/java/com/chat/yourway/unit/service/impl/TopicServiceImplTest.java index 5d113a5d..3fdbcf92 100644 --- a/src/test/java/com/chat/yourway/unit/service/impl/TopicServiceImplTest.java +++ b/src/test/java/com/chat/yourway/unit/service/impl/TopicServiceImplTest.java @@ -17,6 +17,7 @@ import com.chat.yourway.dto.request.TopicPrivateRequestDto; import com.chat.yourway.dto.request.TopicRequestDto; import com.chat.yourway.dto.response.TagResponseDto; +import com.chat.yourway.dto.response.TopicInfoResponseDto; import com.chat.yourway.dto.response.TopicResponseDto; import com.chat.yourway.exception.TopicAccessException; import com.chat.yourway.exception.TopicNotFoundException; @@ -351,7 +352,7 @@ public void findAllPublic_shouldReturnListOfTopicResponseDto() { when(topicRepository.findAllByIsPublicIsTrue()).thenReturn(topics); // When - List topicResponseDtos = topicService.findAllPublic(); + List topicResponseDtos = topicService.findAllPublic(); // Then assertThat(topicResponseDtos).isNotNull(); @@ -369,7 +370,7 @@ public void findAllPublic_shouldReturnEmptyListOfTopicResponseDto() { when(topicRepository.findAllByIsPublicIsTrue()).thenReturn(emptyList); // When - List topicResponseDtos = topicService.findAllPublic(); + List topicResponseDtos = topicService.findAllPublic(); // Then assertThat(topicResponseDtos).isNotNull(); @@ -486,4 +487,10 @@ private void assertTopicEquals(Topic topic, TopicResponseDto topicResponseDto) { assertThat(topicResponseDto.getTopicSubscribers()).isNull(); } + private void assertTopicEquals(Topic topic, TopicInfoResponseDto topicResponseDto) { + assertThat(topicResponseDto.getTopicName()).isEqualTo(topic.getTopicName()); + assertThat(topicResponseDto.getCreatedBy()).isEqualTo(topic.getCreatedBy()); + assertThat(topicResponseDto.getCreatedAt()).isEqualTo(topic.getCreatedAt()); + } + } From 1a87a5efb952a9d35cd4f77d5497ded8b9e53259 Mon Sep 17 00:00:00 2001 From: gaponov Date: Mon, 6 May 2024 15:55:33 +0300 Subject: [PATCH 3/5] add nickname in message dto --- .../yourway/dto/response/MessageResponseDto.java | 2 ++ .../com/chat/yourway/mapper/MessageMapper.java | 5 +++++ src/main/java/com/chat/yourway/model/Contact.java | 6 ++++++ src/main/java/com/chat/yourway/model/Message.java | 15 +++++++++++++++ .../V0027__add_contact_id_in_message.sql | 12 ++++++++++++ 5 files changed, 40 insertions(+) create mode 100644 src/main/resources/db/migration/V0027__add_contact_id_in_message.sql diff --git a/src/main/java/com/chat/yourway/dto/response/MessageResponseDto.java b/src/main/java/com/chat/yourway/dto/response/MessageResponseDto.java index ec1e0d9b..5c10192c 100644 --- a/src/main/java/com/chat/yourway/dto/response/MessageResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/MessageResponseDto.java @@ -19,7 +19,9 @@ public class MessageResponseDto { private Integer id; private LocalDateTime timestamp; private String sentFrom; + private String sentFromNickname; private String sendTo; + private String sendToNickname; private String content; } diff --git a/src/main/java/com/chat/yourway/mapper/MessageMapper.java b/src/main/java/com/chat/yourway/mapper/MessageMapper.java index 08c2def6..d1e6cc51 100644 --- a/src/main/java/com/chat/yourway/mapper/MessageMapper.java +++ b/src/main/java/com/chat/yourway/mapper/MessageMapper.java @@ -4,10 +4,15 @@ import com.chat.yourway.model.Message; import java.util.List; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; @Mapper(componentModel = "spring") public interface MessageMapper { + @Mapping(source = "sender.nickname", target = "sentFromNickname") + @Mapping(source = "receiver.nickname", target = "sendToNickname", + defaultExpression = "java(message.getReceiver() != null ? message.getReceiver().getNickname() : null )" + ) MessageResponseDto toResponseDto(Message message); List toListResponseDto(List messages); diff --git a/src/main/java/com/chat/yourway/model/Contact.java b/src/main/java/com/chat/yourway/model/Contact.java index f7b5a383..0d0a0af4 100644 --- a/src/main/java/com/chat/yourway/model/Contact.java +++ b/src/main/java/com/chat/yourway/model/Contact.java @@ -33,16 +33,22 @@ public class Contact implements UserDetails { @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "contact_seq_gen") @SequenceGenerator(name = "contact_seq_gen", sequenceName = "chat.contact_id_seq", allocationSize = 1) private Integer id; + @Column(name = "nickname", nullable = false, unique = true) private String nickname; + @Column(name = "avatar_id", nullable = false) private Byte avatarId; + @Column(name = "email", nullable = false, unique = true) private String email; + @Column(name = "password", nullable = false, length = 2048) private String password; + @Column(name = "is_active", nullable = false) private Boolean isActive; + @Column(name = "is_private", nullable = false) private Boolean isPrivate; diff --git a/src/main/java/com/chat/yourway/model/Message.java b/src/main/java/com/chat/yourway/model/Message.java index 51c222f6..736cf251 100644 --- a/src/main/java/com/chat/yourway/model/Message.java +++ b/src/main/java/com/chat/yourway/model/Message.java @@ -29,21 +29,36 @@ @Entity @Table(schema = "chat", name = "message") public class Message { + @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "message_seq_gen") @SequenceGenerator(name = "message_seq_gen", sequenceName = "chat.message_id_seq", allocationSize = 1) private Integer id; + @Column(name = "sent_from", nullable = false) private String sentFrom; + @Column(name = "send_to") private String sendTo; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "sender_id") + private Contact sender; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "receiver_id") + private Contact receiver; + @Column(name = "content", nullable = false) private String content; + @Column(name = "timestamp", nullable = false) private LocalDateTime timestamp; + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "topic_id", referencedColumnName = "id", nullable = false) private Topic topic; + @ManyToMany(fetch = FetchType.LAZY) @JoinTable( schema = "chat", diff --git a/src/main/resources/db/migration/V0027__add_contact_id_in_message.sql b/src/main/resources/db/migration/V0027__add_contact_id_in_message.sql new file mode 100644 index 00000000..1a80e64b --- /dev/null +++ b/src/main/resources/db/migration/V0027__add_contact_id_in_message.sql @@ -0,0 +1,12 @@ +ALTER TABLE chat.message + ADD sender_id int4, + ALTER COLUMN sender_id SET DEFAULT NULL, + ADD CONSTRAINT sender_fk_contact FOREIGN KEY (sender_id) REFERENCES chat.contact (id); +ALTER TABLE chat.message + ADD receiver_id int4, + ALTER COLUMN receiver_id SET DEFAULT NULL, + ADD CONSTRAINT receiver_fk_contact FOREIGN KEY (receiver_id) REFERENCES chat.contact (id); + +UPDATE chat.message m +SET sender_id = (SELECT ID FROM chat.contact c WHERE c.email = m.sent_from), + receiver_id = (SELECT ID FROM chat.contact c WHERE c.email = m.send_to); \ No newline at end of file From 1cb26efd81f4ae5194703b2c2ec1d644961ee4e5 Mon Sep 17 00:00:00 2001 From: gaponov Date: Mon, 6 May 2024 19:25:15 +0300 Subject: [PATCH 4/5] add sender and receiver in create method --- .../java/com/chat/yourway/service/MessageServiceImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/chat/yourway/service/MessageServiceImpl.java b/src/main/java/com/chat/yourway/service/MessageServiceImpl.java index 07ca7ec1..d849cbee 100644 --- a/src/main/java/com/chat/yourway/service/MessageServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/MessageServiceImpl.java @@ -13,6 +13,7 @@ import com.chat.yourway.mapper.TopicMapper; import com.chat.yourway.model.Message; import com.chat.yourway.repository.MessageRepository; +import com.chat.yourway.service.interfaces.ContactService; import com.chat.yourway.service.interfaces.MessageService; import com.chat.yourway.service.interfaces.TopicService; import com.chat.yourway.service.interfaces.TopicSubscriberService; @@ -40,6 +41,7 @@ public class MessageServiceImpl implements MessageService { private final MessageRepository messageRepository; private final MessageMapper messageMapper; private final TopicService topicService; + private final ContactService contactService; private final TopicMapper topicMapper; private final TopicSubscriberService topicSubscriberService; @@ -55,6 +57,7 @@ public MessageResponseDto createPublic(int topicId, MessagePublicRequestDto mess Message savedMessage = messageRepository.save(Message.builder() .sentFrom(email) .sendTo("Topic id=" + topic.getId()) + .sender(contactService.findByEmail(email)) .content(message.getContent()) .timestamp(LocalDateTime.now()) .topic(topicMapper.toEntity(topic)) @@ -81,6 +84,8 @@ public MessageResponseDto createPrivate(MessagePrivateRequestDto message, String Message savedMessage = messageRepository.save(Message.builder() .sentFrom(email) .sendTo(message.getSendTo()) + .sender(contactService.findByEmail(email)) + .receiver(contactService.findByEmail(message.getSendTo())) .content(message.getContent()) .timestamp(LocalDateTime.now()) .topic(topicMapper.toEntity(topic)) From f7cb1b6b948f50eec7768f8d4df45215312dfbac Mon Sep 17 00:00:00 2001 From: gaponov Date: Mon, 6 May 2024 19:48:30 +0300 Subject: [PATCH 5/5] fix test --- .../yourway/unit/service/impl/MessageServiceImplTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/test/java/com/chat/yourway/unit/service/impl/MessageServiceImplTest.java b/src/test/java/com/chat/yourway/unit/service/impl/MessageServiceImplTest.java index abe1f3e5..04545dfc 100644 --- a/src/test/java/com/chat/yourway/unit/service/impl/MessageServiceImplTest.java +++ b/src/test/java/com/chat/yourway/unit/service/impl/MessageServiceImplTest.java @@ -24,10 +24,12 @@ import com.chat.yourway.exception.TopicSubscriberNotFoundException; import com.chat.yourway.mapper.MessageMapperImpl; import com.chat.yourway.mapper.TopicMapperImpl; +import com.chat.yourway.model.Contact; import com.chat.yourway.model.Message; import com.chat.yourway.model.Topic; import com.chat.yourway.repository.MessageRepository; import com.chat.yourway.service.MessageServiceImpl; +import com.chat.yourway.service.interfaces.ContactService; import com.chat.yourway.service.interfaces.TopicService; import com.chat.yourway.service.interfaces.TopicSubscriberService; import java.time.LocalDateTime; @@ -57,6 +59,8 @@ public class MessageServiceImplTest { @Mock TopicService topicService; @Mock + ContactService contactService; + @Mock TopicSubscriberService topicSubscriberService; @InjectMocks MessageServiceImpl messageService; @@ -159,6 +163,7 @@ public void createPublic_shouldCreatePublicMessage() { when(topicService.findById(topicId)).thenReturn(topicResponseDto); when(messageRepository.save(any(Message.class))).thenReturn(message); when(topicSubscriberService.hasContactSubscribedToTopic(sentFrom, topicId)).thenReturn(true); + when(contactService.findByEmail(anyString())).thenReturn(null); // When MessageResponseDto messageDto = messageService.createPublic(topicId, messageRequest, sentFrom); @@ -218,6 +223,7 @@ public void createPrivate_shouldCreatePrivateMessage() { when(topicService.generatePrivateName(sendTo, sentFrom)).thenReturn(topicName); when(topicService.findByName(topicName)).thenReturn(topicResponseDto); when(messageRepository.save(any(Message.class))).thenReturn(message); + when(contactService.findByEmail(anyString())).thenReturn(null); // When MessageResponseDto messageDto = messageService.createPrivate(messageRequest, sentFrom);