diff --git a/src/main/java/com/chat/yourway/controller/AuthenticationController.java b/src/main/java/com/chat/yourway/controller/AuthenticationController.java index 1319b1e6..0e562186 100644 --- a/src/main/java/com/chat/yourway/controller/AuthenticationController.java +++ b/src/main/java/com/chat/yourway/controller/AuthenticationController.java @@ -15,7 +15,7 @@ import com.chat.yourway.config.openapi.OpenApiExamples; import com.chat.yourway.dto.request.AuthRequestDto; import com.chat.yourway.dto.request.ContactRequestDto; -import com.chat.yourway.dto.response.ApiErrorResponseDto; +import com.chat.yourway.dto.response.error.ApiErrorResponseDto; import com.chat.yourway.dto.response.AuthResponseDto; import com.chat.yourway.security.LogoutService; import com.chat.yourway.service.interfaces.ActivateAccountService; diff --git a/src/main/java/com/chat/yourway/controller/ChangePasswordController.java b/src/main/java/com/chat/yourway/controller/ChangePasswordController.java index f86c642e..c51b9a1b 100644 --- a/src/main/java/com/chat/yourway/controller/ChangePasswordController.java +++ b/src/main/java/com/chat/yourway/controller/ChangePasswordController.java @@ -3,7 +3,7 @@ import com.chat.yourway.config.openapi.OpenApiExamples; import com.chat.yourway.dto.request.ChangePasswordDto; import com.chat.yourway.dto.request.RestorePasswordDto; -import com.chat.yourway.dto.response.ApiErrorResponseDto; +import com.chat.yourway.dto.response.error.ApiErrorResponseDto; import com.chat.yourway.service.interfaces.ChangePasswordService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; diff --git a/src/main/java/com/chat/yourway/controller/ContactController.java b/src/main/java/com/chat/yourway/controller/ContactController.java index 414059ba..45722cfc 100644 --- a/src/main/java/com/chat/yourway/controller/ContactController.java +++ b/src/main/java/com/chat/yourway/controller/ContactController.java @@ -5,7 +5,7 @@ import com.chat.yourway.config.openapi.OpenApiExamples; import com.chat.yourway.dto.request.EditContactProfileRequestDto; -import com.chat.yourway.dto.response.ApiErrorResponseDto; +import com.chat.yourway.dto.response.error.ApiErrorResponseDto; import com.chat.yourway.dto.response.ContactProfileResponseDto; import com.chat.yourway.service.interfaces.ContactService; import io.swagger.v3.oas.annotations.Operation; diff --git a/src/main/java/com/chat/yourway/controller/MessageController.java b/src/main/java/com/chat/yourway/controller/MessageController.java index 07a98d4c..43e9dc09 100644 --- a/src/main/java/com/chat/yourway/controller/MessageController.java +++ b/src/main/java/com/chat/yourway/controller/MessageController.java @@ -4,7 +4,7 @@ import static com.chat.yourway.config.openapi.OpenApiMessages.MESSAGE_NOT_FOUND; import static com.chat.yourway.config.openapi.OpenApiMessages.SUCCESSFULLY_REPORTED_MESSAGE; -import com.chat.yourway.dto.response.ApiErrorResponseDto; +import com.chat.yourway.dto.response.error.ApiErrorResponseDto; import com.chat.yourway.service.interfaces.MessageService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; diff --git a/src/main/java/com/chat/yourway/controller/TopicController.java b/src/main/java/com/chat/yourway/controller/TopicController.java index ad7f6117..ab0dcbcd 100644 --- a/src/main/java/com/chat/yourway/controller/TopicController.java +++ b/src/main/java/com/chat/yourway/controller/TopicController.java @@ -6,7 +6,7 @@ import com.chat.yourway.dto.request.TopicPrivateRequestDto; import com.chat.yourway.dto.request.TopicRequestDto; -import com.chat.yourway.dto.response.ApiErrorResponseDto; +import com.chat.yourway.dto.response.error.ApiErrorResponseDto; import com.chat.yourway.dto.response.ContactResponseDto; import com.chat.yourway.dto.response.TopicInfoResponseDto; import com.chat.yourway.dto.response.TopicResponseDto; diff --git a/src/main/java/com/chat/yourway/controller/TypingController.java b/src/main/java/com/chat/yourway/controller/TypingController.java new file mode 100644 index 00000000..abcfd8b7 --- /dev/null +++ b/src/main/java/com/chat/yourway/controller/TypingController.java @@ -0,0 +1,21 @@ +package com.chat.yourway.controller; + +import com.chat.yourway.service.interfaces.ChatTypingEventService; +import java.security.Principal; +import lombok.RequiredArgsConstructor; +import org.springframework.messaging.handler.annotation.DestinationVariable; +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.stereotype.Controller; + +@Controller +@RequiredArgsConstructor +public class TypingController { + + private final ChatTypingEventService chatTypingEventService; + + @MessageMapping("/typing/{isTyping}") + public void updateTypingEvent(@DestinationVariable boolean isTyping, Principal principal) { + String email = principal.getName(); + chatTypingEventService.updateTypingEvent(isTyping, email); + } +} diff --git a/src/main/java/com/chat/yourway/dto/response/ApiErrorResponseDto.java b/src/main/java/com/chat/yourway/dto/response/error/ApiErrorResponseDto.java similarity index 90% rename from src/main/java/com/chat/yourway/dto/response/ApiErrorResponseDto.java rename to src/main/java/com/chat/yourway/dto/response/error/ApiErrorResponseDto.java index ede0bbaa..6e19da40 100644 --- a/src/main/java/com/chat/yourway/dto/response/ApiErrorResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/error/ApiErrorResponseDto.java @@ -1,4 +1,4 @@ -package com.chat.yourway.dto.response; +package com.chat.yourway.dto.response.error; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; diff --git a/src/main/java/com/chat/yourway/dto/response/MessageErrorResponseDto.java b/src/main/java/com/chat/yourway/dto/response/error/MessageErrorResponseDto.java similarity index 87% rename from src/main/java/com/chat/yourway/dto/response/MessageErrorResponseDto.java rename to src/main/java/com/chat/yourway/dto/response/error/MessageErrorResponseDto.java index 13cd4ac3..0ad9a9a0 100644 --- a/src/main/java/com/chat/yourway/dto/response/MessageErrorResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/error/MessageErrorResponseDto.java @@ -1,4 +1,4 @@ -package com.chat.yourway.dto.response; +package com.chat.yourway.dto.response.error; import java.time.LocalDateTime; import lombok.AllArgsConstructor; diff --git a/src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java b/src/main/java/com/chat/yourway/dto/response/notification/LastMessageResponseDto.java similarity index 93% rename from src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java rename to src/main/java/com/chat/yourway/dto/response/notification/LastMessageResponseDto.java index 1f8426b9..9469a522 100644 --- a/src/main/java/com/chat/yourway/dto/response/LastMessageResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/notification/LastMessageResponseDto.java @@ -1,4 +1,4 @@ -package com.chat.yourway.dto.response; +package com.chat.yourway.dto.response.notification; import java.time.LocalDateTime; import lombok.Getter; diff --git a/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java b/src/main/java/com/chat/yourway/dto/response/notification/MessageNotificationResponseDto.java similarity index 89% rename from src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java rename to src/main/java/com/chat/yourway/dto/response/notification/MessageNotificationResponseDto.java index 3fd21933..7c73eebc 100644 --- a/src/main/java/com/chat/yourway/dto/response/MessageNotificationResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/notification/MessageNotificationResponseDto.java @@ -1,4 +1,4 @@ -package com.chat.yourway.dto.response; +package com.chat.yourway.dto.response.notification; import com.chat.yourway.model.event.EventType; import java.time.LocalDateTime; diff --git a/src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java b/src/main/java/com/chat/yourway/dto/response/notification/TopicNotificationResponseDto.java similarity index 78% rename from src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java rename to src/main/java/com/chat/yourway/dto/response/notification/TopicNotificationResponseDto.java index 744604f4..a9d79e97 100644 --- a/src/main/java/com/chat/yourway/dto/response/TopicNotificationResponseDto.java +++ b/src/main/java/com/chat/yourway/dto/response/notification/TopicNotificationResponseDto.java @@ -1,4 +1,4 @@ -package com.chat.yourway.dto.response; +package com.chat.yourway.dto.response.notification; import lombok.AllArgsConstructor; import lombok.Getter; @@ -19,5 +19,6 @@ public class TopicNotificationResponseDto { private LastMessageResponseDto lastMessage; + private TypingEventResponseDto typingEvent; } diff --git a/src/main/java/com/chat/yourway/dto/response/notification/TypingEventResponseDto.java b/src/main/java/com/chat/yourway/dto/response/notification/TypingEventResponseDto.java new file mode 100644 index 00000000..d08919c4 --- /dev/null +++ b/src/main/java/com/chat/yourway/dto/response/notification/TypingEventResponseDto.java @@ -0,0 +1,20 @@ +package com.chat.yourway.dto.response.notification; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@AllArgsConstructor +@NoArgsConstructor +@Setter +@Getter +@ToString +public class TypingEventResponseDto { + + private String email; + + private boolean isTyping; + +} diff --git a/src/main/java/com/chat/yourway/exception/handler/ApiExceptionHandler.java b/src/main/java/com/chat/yourway/exception/handler/ApiExceptionHandler.java index a965f60a..2d820887 100644 --- a/src/main/java/com/chat/yourway/exception/handler/ApiExceptionHandler.java +++ b/src/main/java/com/chat/yourway/exception/handler/ApiExceptionHandler.java @@ -6,7 +6,7 @@ import static org.springframework.http.HttpStatus.NOT_FOUND; import static org.springframework.http.HttpStatus.UNAUTHORIZED; -import com.chat.yourway.dto.response.ApiErrorResponseDto; +import com.chat.yourway.dto.response.error.ApiErrorResponseDto; import com.chat.yourway.exception.ContactAlreadySubscribedToTopicException; import com.chat.yourway.exception.ContactEmailNotExist; import com.chat.yourway.exception.ContactNotFoundException; diff --git a/src/main/java/com/chat/yourway/exception/handler/WebsocketExceptionHandler.java b/src/main/java/com/chat/yourway/exception/handler/WebsocketExceptionHandler.java index 9a81ea07..ef911e46 100644 --- a/src/main/java/com/chat/yourway/exception/handler/WebsocketExceptionHandler.java +++ b/src/main/java/com/chat/yourway/exception/handler/WebsocketExceptionHandler.java @@ -1,6 +1,6 @@ package com.chat.yourway.exception.handler; -import com.chat.yourway.dto.response.MessageErrorResponseDto; +import com.chat.yourway.dto.response.error.MessageErrorResponseDto; import com.chat.yourway.exception.MessagePermissionDeniedException; import com.chat.yourway.exception.TopicNotFoundException; import com.chat.yourway.exception.TopicSubscriberNotFoundException; diff --git a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java index 2b38f4e7..00c7c9fa 100644 --- a/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java +++ b/src/main/java/com/chat/yourway/listener/StompSubscriptionListener.java @@ -4,7 +4,8 @@ import static com.chat.yourway.model.event.EventType.SUBSCRIBED; import com.chat.yourway.config.websocket.WebsocketProperties; -import com.chat.yourway.dto.response.LastMessageResponseDto; +import com.chat.yourway.dto.response.notification.LastMessageResponseDto; +import com.chat.yourway.dto.response.notification.TypingEventResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.interfaces.ChatNotificationService; import com.chat.yourway.service.interfaces.ContactEventService; @@ -31,6 +32,7 @@ public class StompSubscriptionListener { private final ChatNotificationService chatNotificationService; private static LastMessageResponseDto lastMessageDto; + private static TypingEventResponseDto typingEvent; private static final String USER_DESTINATION = "/user"; private static final String TOPICS_DESTINATION = "/topics"; private static final String SLASH = "/"; @@ -46,9 +48,11 @@ public void handleWebSocketSubscribeListener(SessionSubscribeEvent event) { .getLastMessage(); int unreadMessages = contactEventService.getByTopicIdAndEmail(getTopicId(event), email) .getUnreadMessages(); + typingEvent = contactEventService.getByTopicIdAndEmail( + getTopicId(event), email).getTypingEvent(); var contactEvent = new ContactEvent(email, getTopicId(event), SUBSCRIBED, - getTimestamp(event), unreadMessages, lastMessageDto); + getTimestamp(event), unreadMessages, lastMessageDto, typingEvent); contactEventService.updateEventTypeByEmail(ONLINE, email); contactEventService.save(contactEvent); } @@ -75,7 +79,7 @@ public void handleWebSocketUnsubscribeListener(SessionUnsubscribeEvent event) { try { if (isTopicDestination(destination)) { var contactEvent = new ContactEvent(email, getTopicId(event), ONLINE, - getTimestamp(event), 0, lastMessageDto); + getTimestamp(event), 0, lastMessageDto, typingEvent); contactEventService.save(contactEvent); } diff --git a/src/main/java/com/chat/yourway/mapper/NotificationMapper.java b/src/main/java/com/chat/yourway/mapper/NotificationMapper.java index 591a5454..cb3738b6 100644 --- a/src/main/java/com/chat/yourway/mapper/NotificationMapper.java +++ b/src/main/java/com/chat/yourway/mapper/NotificationMapper.java @@ -1,7 +1,7 @@ package com.chat.yourway.mapper; -import com.chat.yourway.dto.response.MessageNotificationResponseDto; -import com.chat.yourway.dto.response.TopicNotificationResponseDto; +import com.chat.yourway.dto.response.notification.MessageNotificationResponseDto; +import com.chat.yourway.dto.response.notification.TopicNotificationResponseDto; import com.chat.yourway.model.event.ContactEvent; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -17,6 +17,7 @@ public interface NotificationMapper { @Mapping(target = "topicId", source = "topicId") @Mapping(target = "unreadMessages", source = "unreadMessages") @Mapping(target = "lastMessage", source = "lastMessage") + @Mapping(target = "typingEvent", source = "typingEvent") 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 8f7e9f15..f9e301ab 100644 --- a/src/main/java/com/chat/yourway/model/event/ContactEvent.java +++ b/src/main/java/com/chat/yourway/model/event/ContactEvent.java @@ -1,6 +1,7 @@ package com.chat.yourway.model.event; -import com.chat.yourway.dto.response.LastMessageResponseDto; +import com.chat.yourway.dto.response.notification.LastMessageResponseDto; +import com.chat.yourway.dto.response.notification.TypingEventResponseDto; import java.time.LocalDateTime; import lombok.Getter; import lombok.NoArgsConstructor; @@ -28,10 +29,11 @@ public class ContactEvent { private LocalDateTime timestamp; private int unreadMessages; private LastMessageResponseDto lastMessage; + private TypingEventResponseDto typingEvent; public ContactEvent(String email, Integer topicId, EventType eventType, LocalDateTime timestamp, - int unreadMessages, LastMessageResponseDto lastMessage) { + int unreadMessages, LastMessageResponseDto lastMessage, TypingEventResponseDto typingEvent) { this.id = email + "_" + topicId; this.email = email; this.topicId = topicId; @@ -39,6 +41,7 @@ public ContactEvent(String email, Integer topicId, EventType eventType, LocalDat this.timestamp = timestamp; this.unreadMessages = unreadMessages; this.lastMessage = lastMessage; + this.typingEvent = typingEvent; } } diff --git a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java index 5fac88f1..7b40e510 100644 --- a/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ChatMessageServiceImpl.java @@ -4,7 +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.notification.LastMessageResponseDto; import com.chat.yourway.dto.response.MessageResponseDto; import com.chat.yourway.service.interfaces.ChatMessageService; import com.chat.yourway.service.interfaces.ChatNotificationService; diff --git a/src/main/java/com/chat/yourway/service/ChatTypingEventServiceImpl.java b/src/main/java/com/chat/yourway/service/ChatTypingEventServiceImpl.java new file mode 100644 index 00000000..0270aa8c --- /dev/null +++ b/src/main/java/com/chat/yourway/service/ChatTypingEventServiceImpl.java @@ -0,0 +1,32 @@ +package com.chat.yourway.service; + +import com.chat.yourway.model.event.EventType; +import com.chat.yourway.service.interfaces.ChatNotificationService; +import com.chat.yourway.service.interfaces.ChatTypingEventService; +import com.chat.yourway.service.interfaces.ContactEventService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ChatTypingEventServiceImpl implements ChatTypingEventService { + + private final ContactEventService contactEventService; + private final ChatNotificationService chatNotificationService; + + @Override + public void updateTypingEvent(Boolean isTyping, String email) { + log.info("Start updateTypingEvent isTyping={}, email={}", isTyping, email); + contactEventService.updateTypingEvent(email, isTyping); + + Integer topicId = contactEventService.getAllByEmail(email).stream() + .filter(e -> e.getEventType().equals(EventType.SUBSCRIBED)) + .findFirst() + .orElseThrow() + .getTopicId(); + + chatNotificationService.updateNotificationForAllWhoSubscribedToTopic(topicId); + } +} diff --git a/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java b/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java index aace67d0..bd06a6fa 100644 --- a/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/ContactEventServiceImpl.java @@ -3,7 +3,8 @@ 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.dto.response.notification.LastMessageResponseDto; +import com.chat.yourway.dto.response.notification.TypingEventResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.model.event.EventType; import com.chat.yourway.repository.ContactEventRedisRepository; @@ -32,7 +33,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(), 0, null)); + .orElse(new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), 0, null, null)); } @Override @@ -81,4 +82,22 @@ public void updateMessageInfoForAllTopicSubscribers(Integer topicId, contactEventRedisRepository.saveAll(events); } + @Override + public void updateTypingEvent(String email, boolean isTyping) { + + Integer topicId = getAllByEmail(email).stream() + .filter(e -> e.getEventType().equals(EventType.SUBSCRIBED)) + .findFirst() + .orElseThrow() + .getTopicId(); + + getAllByTopicId(topicId) + .forEach(event -> { + event.setTypingEvent(new TypingEventResponseDto(email, isTyping)); + contactEventRedisRepository.save(event); + }); + + + } + } diff --git a/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java b/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java index 6639f943..944718c8 100644 --- a/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java +++ b/src/main/java/com/chat/yourway/service/NotificationServiceImpl.java @@ -1,7 +1,7 @@ package com.chat.yourway.service; -import com.chat.yourway.dto.response.MessageNotificationResponseDto; -import com.chat.yourway.dto.response.TopicNotificationResponseDto; +import com.chat.yourway.dto.response.notification.MessageNotificationResponseDto; +import com.chat.yourway.dto.response.notification.TopicNotificationResponseDto; import com.chat.yourway.mapper.NotificationMapper; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.interfaces.ContactEventService; diff --git a/src/main/java/com/chat/yourway/service/interfaces/ChatTypingEventService.java b/src/main/java/com/chat/yourway/service/interfaces/ChatTypingEventService.java new file mode 100644 index 00000000..66e84118 --- /dev/null +++ b/src/main/java/com/chat/yourway/service/interfaces/ChatTypingEventService.java @@ -0,0 +1,13 @@ +package com.chat.yourway.service.interfaces; + +public interface ChatTypingEventService { + + /** + * Update typing event by user email. + * + * @param isTyping typing status. + * @param email user email. + */ + void updateTypingEvent(Boolean isTyping, 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 69f225ff..63442e0e 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/ContactEventService.java @@ -1,6 +1,6 @@ package com.chat.yourway.service.interfaces; -import com.chat.yourway.dto.response.LastMessageResponseDto; +import com.chat.yourway.dto.response.notification.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.model.event.EventType; import java.util.List; @@ -18,7 +18,7 @@ public interface ContactEventService { * Get contact event by topic id and contact email. * * @param topicId topic id. - * @param email contact email. + * @param email contact email. * @return contact event. */ ContactEvent getByTopicIdAndEmail(Integer topicId, String email); @@ -44,9 +44,18 @@ public interface ContactEventService { /** * Set last message to all topic subscribers events. * - * @param topicId topic id. + * @param topicId topic id. * @param lastMessageDto last message Dto. */ - void updateMessageInfoForAllTopicSubscribers(Integer topicId, LastMessageResponseDto lastMessageDto); + void updateMessageInfoForAllTopicSubscribers(Integer topicId, + LastMessageResponseDto lastMessageDto); + + /** + * Update typing status. + * + * @param email user email. + * @param isTyping typing status. + */ + void updateTypingEvent(String email, boolean isTyping); } 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 b549bc63..35a09a31 100644 --- a/src/main/java/com/chat/yourway/service/interfaces/NotificationService.java +++ b/src/main/java/com/chat/yourway/service/interfaces/NotificationService.java @@ -1,7 +1,7 @@ package com.chat.yourway.service.interfaces; -import com.chat.yourway.dto.response.MessageNotificationResponseDto; -import com.chat.yourway.dto.response.TopicNotificationResponseDto; +import com.chat.yourway.dto.response.notification.MessageNotificationResponseDto; +import com.chat.yourway.dto.response.notification.TopicNotificationResponseDto; import java.util.List; public interface NotificationService { diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index 3548cb92..74316891 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -114,7 +114,12 @@

WebSocket Chat Test Client

const sendToPublicTopicDest = "/app/topic/public/"; const sendToPrivateTopicDest = "/app/topic/private/"; const getHistoryTopicDest = "/app/history/topic/"; + const sendIsTypingDest = "/app/typing" + const tokenType = 'Bearer'; + let typingTimer; + let isTyping = false; + let socket = null; let stompClient = null; @@ -225,6 +230,24 @@

WebSocket Chat Test Client

stompClient.send(getHistoryTopicDest + topicId, {}, request); response.innerText += ('<<< ' + request + '\n'); } + + function sendTyping(isTyping) { + stompClient.send(sendIsTypingDest + '/' + isTyping, {}); + } + + document.addEventListener('keydown', function() { + if (!isTyping) { + isTyping = true; + sendTyping(isTyping); + } + + clearTimeout(typingTimer); + typingTimer = setTimeout(function() { + isTyping = false; + sendTyping(isTyping); + }, 2000); + }); + \ No newline at end of file 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 6d2ab90f..1131c438 100644 --- a/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java +++ b/src/test/java/com/chat/yourway/integration/controller/ChatControllerTest.java @@ -11,9 +11,10 @@ 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.notification.LastMessageResponseDto; +import com.chat.yourway.dto.response.notification.MessageNotificationResponseDto; import com.chat.yourway.dto.response.MessageResponseDto; +import com.chat.yourway.dto.response.notification.TypingEventResponseDto; import com.chat.yourway.integration.controller.websocketclient.TestStompFrameHandler; import com.chat.yourway.integration.extension.PostgresExtension; import com.chat.yourway.integration.extension.RedisExtension; @@ -201,9 +202,10 @@ void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfSubscribeEvent() { lastMessageDto.setTimestamp(LocalDateTime.now()); lastMessageDto.setSentFrom("vasil@gmail.com"); lastMessageDto.setLastMessage("Hi"); + var typingEventDto = new TypingEventResponseDto("vasil@gmail.com", true); var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, - lastMessageDto); + lastMessageDto, typingEventDto); saveContactEvent(event); //Stored subscription results for testing CompletableFuture resultKeeper = new CompletableFuture<>(); @@ -232,9 +234,10 @@ void notifyTopicSubscribers_shouldNotifyTopicSubscribersIfAnyContactSubscribedTo lastMessageDto.setTimestamp(LocalDateTime.now()); lastMessageDto.setSentFrom("vasil@gmail.com"); lastMessageDto.setLastMessage("Hi"); + var typingEventDto = new TypingEventResponseDto("vasil@gmail.com", true); var event = new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, - lastMessageDto); + lastMessageDto, typingEventDto); 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 38685b4a..d30119fd 100644 --- a/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java +++ b/src/test/java/com/chat/yourway/unit/listener/StompSubscriptionListenerTest.java @@ -13,7 +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.dto.response.notification.LastMessageResponseDto; import com.chat.yourway.listener.StompSubscriptionListener; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.interfaces.ChatNotificationService; 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 7c263f01..0fcdb8d8 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,7 +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.dto.response.notification.LastMessageResponseDto; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.model.event.EventType; import com.chat.yourway.repository.ContactEventRedisRepository; @@ -42,7 +42,7 @@ void save_shouldSaveToRepository() { String email = "vasil@gmail.com"; int topicId = 1; ContactEvent contactEvent = new ContactEvent(email, topicId, ONLINE, LocalDateTime.now(), 0, - null); + null, null); // When contactEventService.save(contactEvent); @@ -58,7 +58,7 @@ void getByTopicIdAndEmail_shouldReturnContactEventFromRepository() { Integer topicId = 1; String email = "vasil@gmail.com"; ContactEvent expectedContactEvent = new ContactEvent(email, topicId, ONLINE, - LocalDateTime.now(), 0, null); + LocalDateTime.now(), 0, null, null); when(contactEventRedisRepository.findById(email + "_" + topicId)) .thenReturn(Optional.of(expectedContactEvent)); @@ -93,8 +93,8 @@ void getAllByEmail_shouldReturnContactEventsFromRepository() { // Given String email = "vasil@gmail.com"; List expectedContactEvents = Arrays.asList( - new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), 0, null), - new ContactEvent(email, 2, OFFLINE, LocalDateTime.now(), 0, null) + new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), 0, null, null), + new ContactEvent(email, 2, OFFLINE, LocalDateTime.now(), 0, null, null) ); when(contactEventRedisRepository.findAllByEmail(email)).thenReturn(expectedContactEvents); @@ -112,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(), 0, null), - new ContactEvent(email, 2, ONLINE, LocalDateTime.now(), 0, null) + new ContactEvent(email, 1, ONLINE, LocalDateTime.now(), 0, null, null), + new ContactEvent(email, 2, ONLINE, LocalDateTime.now(), 0, null, null) ); when(contactEventRedisRepository.findAllByEmail(email)).thenReturn(events); @@ -131,8 +131,8 @@ void getAllByTopicId_shouldReturnContactEventsFromRepository() { // Given Integer topicId = 1; List expectedContactEvents = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, null), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), 0, null) + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, null, null), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), 0, null, null) ); when(contactEventRedisRepository.findAllByTopicId(topicId)).thenReturn(expectedContactEvents); @@ -154,8 +154,8 @@ void setLastMessageToAllTopicSubscribers_shouldUpdateLastMessagesInRepository() lastMessageDto.setLastMessage("New message"); List events = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, null), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), 0, null) + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, null, null), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), 0, null, null) ); when(contactEventRedisRepository.findAllByTopicId(topicId)).thenReturn(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 ab82a331..3f10141f 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 @@ -8,8 +8,9 @@ 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.dto.response.notification.LastMessageResponseDto; +import com.chat.yourway.dto.response.notification.MessageNotificationResponseDto; +import com.chat.yourway.dto.response.notification.TypingEventResponseDto; import com.chat.yourway.mapper.NotificationMapper; import com.chat.yourway.model.event.ContactEvent; import com.chat.yourway.service.NotificationServiceImpl; @@ -45,10 +46,13 @@ void notifyTopicSubscribers_shouldReturnListOfNotifications() { lastMessageDto.setTimestamp(LocalDateTime.now()); lastMessageDto.setSentFrom("vasil@gmail.com"); lastMessageDto.setLastMessage("Hello"); + var typingEventDto = new TypingEventResponseDto("vasil@gmail.com", true); List events = Arrays.asList( - new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, lastMessageDto), - new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), 0, lastMessageDto) + new ContactEvent("vasil@gmail.com", topicId, ONLINE, LocalDateTime.now(), 0, lastMessageDto, + typingEventDto), + new ContactEvent("anton@gmail.com", topicId, OFFLINE, LocalDateTime.now(), 0, + lastMessageDto, typingEventDto) ); var expectedNotifications = events.stream()