Commit c23a71c1 authored by henrik.prangel's avatar henrik.prangel
Browse files

JUT-76 & JUT-77 & JUT-78 Implement CR suggestions

* Remove ConversationResource and move endpoints to resources where they "logically fit in"
* Move "event handling" from customer support ui to api
parent 5a4411ed
......@@ -249,6 +249,7 @@ dependencies {
implementation "org.springframework.boot:spring-boot-starter-aop"
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
testImplementation "org.testcontainers:postgresql"
implementation "org.apache.commons:commons-lang3"
implementation "org.apache.kafka:kafka-clients"
implementation 'org.springframework.kafka:spring-kafka'
implementation "org.springframework.boot:spring-boot-starter-security"
......
......@@ -17604,6 +17604,16 @@
"scheduler": "^0.19.1"
}
},
"react-textarea-autosize": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.2.0.tgz",
"integrity": "sha512-grajUlVbkx6VdtSxCgzloUIphIZF5bKr21OYMceWPKkniy7H0mRAT/AXPrRtObAe+zUePnNlBwUc4ivVjUGIjw==",
"requires": {
"@babel/runtime": "^7.10.2",
"use-composed-ref": "^1.0.0",
"use-latest": "^1.0.0"
}
},
"react-toastify": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-5.5.0.tgz",
......@@ -20906,6 +20916,11 @@
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==",
"dev": true
},
"ts-essentials": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz",
"integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w=="
},
"ts-jest": {
"version": "25.4.0",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-25.4.0.tgz",
......@@ -21388,6 +21403,27 @@
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
"dev": true
},
"use-composed-ref": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.1.0.tgz",
"integrity": "sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==",
"requires": {
"ts-essentials": "^2.0.3"
}
},
"use-isomorphic-layout-effect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.0.tgz",
"integrity": "sha512-kady5Z1O1qx5RitodCCKbpJSVEtECXYcnBnb5Q48Bz5V6gBmTu85ZcGdVwVFs8+DaOurNb/L5VdGHoQRMknghw=="
},
"use-latest": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.0.tgz",
"integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==",
"requires": {
"use-isomorphic-layout-effect": "^1.0.0"
}
},
"util": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
......
......@@ -80,11 +80,12 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.antMatchers("/api/activate").permitAll()
.antMatchers("/api/account/reset-password/init").permitAll()
.antMatchers("/api/account/reset-password/finish").permitAll()
.antMatchers("/api/conversation").permitAll()
.antMatchers("/api/conversation/user/commit").permitAll()
.antMatchers("/api/messages/vote").permitAll()
.antMatchers("/api/messages/send").permitAll()
.antMatchers("/api/messages/send/user").hasAuthority(AuthoritiesConstants.CUSTOMER_SUPPORT)
.antMatchers("/api/messages/{id}/vote").permitAll()
.antMatchers("/api/chats/{id}/needs-customer-service").permitAll()
.antMatchers("/api/feedbacks").permitAll()
.antMatchers("/api/chats/{id}/committed-admin").hasAuthority(AuthoritiesConstants.CUSTOMER_SUPPORT)
.antMatchers("/api/chats/{id}/feedbacks").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/websocket/tracker").hasAuthority(AuthoritiesConstants.ANONYMOUS)
.antMatchers("/websocket/**").permitAll()
......
......@@ -5,9 +5,9 @@ import java.time.Instant;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.*;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import static com.netgroup.riigibot.util.Utils.getLowerCaseString;
/**
* A Chat.
......@@ -58,9 +58,6 @@ public class Chat implements Serializable {
@Column(name = "needs_customer_service")
private Boolean needsCustomerService;
@Column(name = "last_responded_bot")
private String lastRespondedBot;
@Column(name = "ended")
private Instant ended;
......@@ -210,7 +207,7 @@ public class Chat implements Serializable {
}
public void setCommittedBot(String committedBot) {
this.committedBot = getLowerCaseString(committedBot);
this.committedBot = StringUtils.lowerCase(committedBot);
}
public String getCommittedAdmin() {
......@@ -221,14 +218,6 @@ public class Chat implements Serializable {
this.committedAdmin = committedAdmin;
}
public String getLastRespondedBot() {
return lastRespondedBot;
}
public void setLastRespondedBot(String lastRespondedBot) {
this.lastRespondedBot = lastRespondedBot;
}
public Boolean getNeedsCustomerService() {
return needsCustomerService;
}
......
......@@ -5,9 +5,9 @@ import java.io.Serializable;
import java.time.Instant;
import javax.persistence.*;
import javax.validation.constraints.*;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import static com.netgroup.riigibot.util.Utils.getLowerCaseString;
/**
* A Message.
......@@ -79,7 +79,7 @@ public class Message implements Serializable {
}
public String getSender() {
return getLowerCaseString(sender);
return StringUtils.lowerCase(sender);
}
public Message sender(String sender) {
......@@ -88,7 +88,7 @@ public class Message implements Serializable {
}
public void setSender(String sender) {
this.sender = getLowerCaseString(sender);
this.sender = StringUtils.lowerCase(sender);
}
public String getConfidence() {
......
......@@ -6,6 +6,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.*;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
* Spring Data repository for the Chat entity.
......@@ -13,7 +14,7 @@ import java.util.List;
@Repository
public interface ChatRepository extends JpaRepository<Chat, Long> {
Chat findBySessionId(String string);
Optional<Chat> findBySessionId(String string);
Page<Chat> findByCommittedBotIn(Pageable pageable, List<String> string);
......
......@@ -14,5 +14,9 @@ public final class AuthoritiesConstants {
public static final String RIA_USER = "ROLE_RIA";
public static final String DATA_SCIENTIST = "ROLE_DATA_SCIENTIST";
public static final String CUSTOMER_SUPPORT = "ROLE_CUSTOMER_SUPPORT";
private AuthoritiesConstants() {}
}
......@@ -33,10 +33,13 @@ public class ChatService {
private final ChatMapper chatMapper;
public ChatService(ChatRepository chatRepository, MessageRepository messageRepository, ChatMapper chatMapper) {
private final UserService userService;
public ChatService(ChatRepository chatRepository, MessageRepository messageRepository, ChatMapper chatMapper, UserService userService) {
this.chatRepository = chatRepository;
this.messageRepository = messageRepository;
this.chatMapper = chatMapper;
this.userService = userService;
}
/**
......@@ -92,6 +95,18 @@ public class ChatService {
return chatRepository.findById(id).map(chatMapper::toDto).map(this::addLastMessageText);
}
/**
* Get one chat by sessionId.
*
* @param sessionId the sessionId of the entity.
* @return the entity.
*/
@Transactional(readOnly = true)
public Optional<ChatDTO> findOneBySession(String sessionId) {
log.debug("Request to get Chat by sessionId : {}", sessionId);
return chatRepository.findBySessionId(sessionId).map(chatMapper::toDto);
}
/**
* Delete the chat by id.
*
......@@ -121,26 +136,30 @@ public class ChatService {
return save(newChat);
}
public ChatDTO getChatByMessage(MessageDTO messageDTO) {
return findOne(messageDTO.getChatId()).orElseThrow(NoSuchElementException::new);
public ChatDTO getChatById(Long chatId) {
return findOne(chatId).orElseThrow(NoSuchElementException::new);
}
public void updateChatWithMessageInformation(ChatDTO chatDTO, MessageDTO messageDTO) {
chatDTO.setLastRespondedBot(messageDTO.getSender());
if (messageDTO.getText().equals("/restart")) {
chatDTO.setCommittedBot(null);
}
if (messageDTO.getSender() == null) {
chatDTO.setLastMessageId(messageDTO.getId());
}
public ChatDTO getChatBySessionId(String sessionId) {
return findOneBySession(sessionId).orElseThrow(NoSuchElementException::new);
}
public void updateChatWithMessageInformation(ChatDTO chatDTO, MessageDTO messageDTO, String referer) {
chatDTO.setLastUserReferer(referer);
chatDTO.setLastMessageId(messageDTO.getId());
save(chatDTO);
}
public void commitBotToChat(MessageDTO messageDTO, ChatDTO chatDTO) {
log.debug("Committing responder {} to chat {}", messageDTO.getSender(), chatDTO.getId());
chatDTO.setCommittedBot(messageDTO.getSender());
save(chatDTO);
public ChatDTO updateChatCommittedBotForCustomerService(ChatDTO chatDTO, String bot) {
chatDTO.setCommittedAdmin(null);
chatDTO.setNeedsCustomerService(true);
return commitBotToChat(bot, chatDTO);
}
public ChatDTO commitBotToChat(String bot, ChatDTO chatDTO) {
log.debug("Committing bot {} to chat {}", bot, chatDTO.getId());
chatDTO.setCommittedBot(bot);
return save(chatDTO);
}
public void commitAdminToChat(ChatDTO chatDTO, Principal principal) {
......@@ -148,4 +167,26 @@ public class ChatService {
chatDTO.setCommittedAdmin(principal.getName());
save(chatDTO);
}
public void updateChatNeedsCustomerServiceToTrue(ChatDTO chatDTO) {
log.debug("Setting needs-customer-service of chat {} to true", chatDTO.getId());
chatDTO.setNeedsCustomerService(true);
save(chatDTO);
}
public ChatDTO getOrCreateChatForMessage(MessageDTO userMessage) {
ChatDTO chatDTO;
if (userMessage.getChatId() == null) {
chatDTO = createNewChatByMessage(userMessage);
userMessage.setChatId(chatDTO.getId());
} else {
chatDTO = getChatById(userMessage.getChatId());
}
return chatDTO;
}
public ChatDTO endChat(ChatDTO chatDTO) {
chatDTO.setEnded(Instant.now());
return save(chatDTO);
}
}
package com.netgroup.riigibot.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netgroup.riigibot.config.KafkaProperties;
import com.netgroup.riigibot.service.dto.ChatDTO;
import com.netgroup.riigibot.service.dto.MessageDTO;
import com.netgroup.riigibot.service.enums.UnremarkableIntent;
import com.netgroup.riigibot.web.websocket.ActivityService;
import java.time.Instant;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.NoSuchElementException;
import java.time.*;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.lang3.EnumUtils;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import javax.annotation.PostConstruct;
@Controller
public class ConversationService {
private static final Logger log = LoggerFactory.getLogger(ActivityService.class);
private final ExecutorService sseExecutorService = Executors.newCachedThreadPool();
private final KafkaProperties kafkaProperties;
private final ChatService chatService;
private final MessageService messageService;
private final List<ChatMessageCollector> chatMessageCollectors = new ArrayList<>();
private static final Integer BOT_AMOUNT = 2;
public ConversationService(ChatService chatService, MessageService messageService) {
public ConversationService(KafkaProperties kafkaProperties, ChatService chatService, MessageService messageService) {
this.kafkaProperties = kafkaProperties;
this.chatService = chatService;
this.messageService = messageService;
}
@PostConstruct
public void executeKafkaConsumer() {
List<String> topics = Collections.singletonList("rasa_events");
log.debug("Started kafka message consumer to topics: {}", topics);
Map<String, Object> consumerProps = kafkaProperties.getConsumerProps();
consumerProps.remove("topic");
sseExecutorService.execute(
() -> {
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(consumerProps);
consumer.subscribe(topics);
boolean exitLoop = false;
while (!exitLoop) {
try {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofSeconds(5));
for (ConsumerRecord<String, String> record : records) {
log.debug("Consumed message from kafka: {}", record);
ObjectMapper objectMapper = new ObjectMapper();
MessageDTO messageDTO = objectMapper.readValue(record.value(), MessageDTO.class);
processBotResponse(messageDTO);
}
} catch (Exception ex) {
log.debug("Complete with error {}", ex.getMessage(), ex);
exitLoop = false;
}
}
consumer.close();
}
);
}
public void processBotResponse(MessageDTO messageDTO) {
if (shouldCollectMessage(messageDTO)) {
ChatMessageCollector chatMessageCollector = addMessageToChatMessageCollection(messageDTO);
......@@ -41,22 +78,22 @@ public class ConversationService {
}
public boolean shouldCollectMessage(MessageDTO messageDTO) {
ChatDTO chat = chatService.getChatByMessage(messageDTO);
ChatDTO chat = chatService.getChatById(messageDTO.getChatId());
return chat != null && (getChatCollectorByChatId(messageDTO.getChatId()) != null || chat.getCommittedBot() == null);
}
public void sendMessageIfFromCommittedBot(MessageDTO messageDTO) {
ChatDTO chat = chatService.getChatByMessage(messageDTO);
ChatDTO chat = chatService.getChatById(messageDTO.getChatId());
if (chat != null && messageDTO.getSender().equals(chat.getCommittedBot())) {
messageService.saveAndSendMessage(messageDTO);
messageService.saveAndSendMessageToUserAndResponsibleCustomerSupportGroup(messageDTO);
} else {
log.debug("Bot {} not assigned to Chat: {} - ignoring message: {}", messageDTO.getSender(), chat, messageDTO);
}
}
public ChatMessageCollector addMessageToChatMessageCollection(MessageDTO messageDTO) {
ChatDTO chatDTO = chatService.getChatByMessage(messageDTO);
ChatDTO chatDTO = chatService.getChatById(messageDTO.getChatId());
ChatMessageCollector chatMessageCollector = getOrCreateChatMessageCollector(chatDTO);
chatMessageCollector.messages.add(messageDTO);
......@@ -88,27 +125,23 @@ public class ConversationService {
return;
}
try {
MessageDTO addressedBotMessage = chatMessageCollector
.messages.stream()
.filter(messageDTO -> messageDTO.getAddressedBot().equals(messageDTO.getSender()))
.findFirst()
.orElseThrow(() -> new NoSuchElementException("Could not find message from addressed bot"));
MessageDTO highestConfidenceMessage = chatMessageCollector
.messages.stream()
.max(Comparator.comparing(MessageDTO::getConfidence))
.orElseThrow(() -> new ArithmeticException("Could not reduce list of messageDTO-s to messageDTO with highest confidence"));
chatMessageCollectors.remove(chatMessageCollector);
if (isRemarkableIntent(highestConfidenceMessage.getInterpretedIntent())) {
chatService.commitBotToChat(highestConfidenceMessage, chatMessageCollector.chat);
messageService.saveAndSendMessage(highestConfidenceMessage);
return;
}
messageService.saveAndSendMessage(addressedBotMessage);
} catch (NoSuchElementException | ArithmeticException e) {
log.error("Encountered exception when committing bot to chat", e);
MessageDTO addressedBotMessage = chatMessageCollector
.messages.stream()
.filter(messageDTO -> messageDTO.getAddressedBot().equals(messageDTO.getSender()))
.findFirst()
.orElseThrow(() -> new NoSuchElementException("Could not find message from addressed bot"));
MessageDTO highestConfidenceMessage = chatMessageCollector
.messages.stream()
.max(Comparator.comparing(MessageDTO::getConfidence))
.orElseThrow(() -> new ArithmeticException("Could not reduce list of messageDTO-s to messageDTO with highest confidence"));
chatMessageCollectors.remove(chatMessageCollector);
if (isRemarkableIntent(highestConfidenceMessage.getInterpretedIntent())) {
chatService.commitBotToChat(highestConfidenceMessage.getSender(), chatMessageCollector.chat);
messageService.saveAndSendMessageToUserAndResponsibleCustomerSupportGroup(highestConfidenceMessage);
return;
}
messageService.saveAndSendMessageToUserAndResponsibleCustomerSupportGroup(addressedBotMessage);
}
private boolean isRemarkableIntent(String intent) {
......
......@@ -4,6 +4,7 @@ import com.netgroup.riigibot.domain.Message;
import com.netgroup.riigibot.repository.MessageRepository;
import com.netgroup.riigibot.service.dto.ChatDTO;
import com.netgroup.riigibot.service.dto.MessageDTO;
import com.netgroup.riigibot.service.enums.ConversationEvents;
import com.netgroup.riigibot.service.enums.VoteValues;
import com.netgroup.riigibot.service.mapper.MessageMapper;
import java.time.Instant;
......@@ -21,6 +22,8 @@ import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import static com.netgroup.riigibot.service.enums.ConversationEvents.*;
/**
* Service Implementation for managing {@link Message}.
*/
......@@ -67,15 +70,19 @@ public class MessageService {
}
message = messageRepository.save(message);
MessageDTO savedMessageDTO = messageMapper.toDto(message);
savedMessageDTO.setSessionId(messageDTO.getSessionId());
savedMessageDTO.setAddressedBot(messageDTO.getAddressedBot());
savedMessageDTO.setAuthorFirstName(messageDTO.getAuthorFirstName());
savedMessageDTO.setAuthorLoginName(messageDTO.getAuthorLoginName());
savedMessageDTO.setButtons(messageDTO.getButtons());
updateMappedMessageDTOWithUnmappedValues(savedMessageDTO, messageDTO);
return savedMessageDTO;
}
private void updateMappedMessageDTOWithUnmappedValues(MessageDTO updatedDTO, MessageDTO oldDTO) {
updatedDTO.setSessionId(oldDTO.getSessionId());
updatedDTO.setAddressedBot(oldDTO.getAddressedBot());
updatedDTO.setAuthorFirstName(oldDTO.getAuthorFirstName());
updatedDTO.setAuthorLoginName(oldDTO.getAuthorLoginName());
updatedDTO.setButtons(oldDTO.getButtons());
}
/**
* Get all the messages.
*
......@@ -115,47 +122,83 @@ public class MessageService {
return byChat_id.stream().map(messageMapper::toDto).collect(Collectors.toList());
}
public MessageDTO updateVote(MessageDTO messageWithVote) {
MessageDTO messageDTO = findOne(messageWithVote.getId()).orElseThrow(NoSuchElementException::new);
if(EnumUtils.isValidEnum(VoteValues.class, messageWithVote.getVote())) {
messageDTO.setVote(messageWithVote.getVote());
public MessageDTO updateMessageWithVoteValue(Long messageId, String voteValue) {
MessageDTO messageDTO = findOne(messageId).orElseThrow(NoSuchElementException::new);
if (EnumUtils.isValidEnum(VoteValues.class, voteValue)) {
messageDTO.setVote(voteValue);
return save(messageDTO);
} else {
throw new IllegalArgumentException("No such vote value:" + messageWithVote.getVote());
throw new IllegalArgumentException("No such vote value exists:" + voteValue);
}
}
public void sendMessageThatCustomerServiceIsClosedToChat(ChatDTO chatDTO) {
public void notifyChatThatCustomerSupportIsCurrentlyClosed(ChatDTO chatDTO) {
MessageDTO messageToSend = new MessageDTO();
messageToSend.setText(CLIENT_SUPPORT_CLOSED);
messageToSend.setChatId(chatDTO.getId());
messageToSend.setSender(chatDTO.getCommittedBot());
messageToSend.setSessionId(chatDTO.getSessionId());
saveAndSendMessage(messageToSend);
saveAndSendMessageToUserAndResponsibleCustomerSupportGroup(messageToSend);
}
public void notifyCustomerSupportGroupThatClientLeftChat(ChatDTO chatDTO) {
MessageDTO eventMessage = createNewEventMessage(chatDTO.getId(), String.valueOf(USER_LEFT_CONVERSATION));
sendMessageToUserGroup(chatDTO.getCommittedBot(), eventMessage);
}
public void notifyCustomerSupportGroupOfEndedChat(ChatDTO chatDTO) {
MessageDTO eventMessage = createNewEventMessage(chatDTO.getId(), String.valueOf(CHAT_ENDED));
sendMessageToUserGroup(chatDTO.getCommittedBot(), eventMessage);
}
public void notifyUserAndCustomerSupportOfChangedCommittedBot(String oldCommittedBot, ChatDTO updatedChat) {
orderCustomerSupportGroupToRemoveChat(oldCommittedBot, updatedChat);
notifyUserAndCustomerSupportGroupThatCommittedBotChanged(updatedChat);
}
private void orderCustomerSupportGroupToRemoveChat(String groupToRemoveFrom, ChatDTO chatToRemove) {
MessageDTO eventMessage = createNewEventMessage(chatToRemove.getId(), String.valueOf(REMOVE_CHAT));
sendMessageToUserGroup(groupToRemoveFrom, eventMessage);
}
private void notifyUserAndCustomerSupportGroupThatCommittedBotChanged(ChatDTO chatDTO) {
MessageDTO eventMessage = createNewEventMessage(chatDTO.getId(), String.valueOf(CHAT_INSTITUTION_CHANGED));
eventMessage.setSessionId(chatDTO.getSessionId());
saveAndSendMessageToUserAndResponsibleCustomerSupportGroup(eventMessage);
}
public void notifyCustomerSupportGroupOfChatRequestingAssistance(ChatDTO chatDTO) {
MessageDTO messageDTO = createNewEventMessage(chatDTO.getId(), String.valueOf(ConversationEvents.CHAT_REQUIRES_CUSTOMER_SERVICE));
sendMessageToUserGroup(chatDTO.getCommittedBot(), messageDTO);
}
public void saveAndSendMessage(MessageDTO messageDTO) {
public void saveAndSendMessageToUserAndResponsibleCustomerSupportGroup(MessageDTO messageDTO) {
MessageDTO savedMessage = save(messageDTO);
sendMessageToUser(savedMessage, savedMessage.getSessionId());
sendMessageToAdmin(savedMessage);
sendMessageToChatCommittedBotCustomerSupportGroup(savedMessage);
}
public MessageDTO sendMessageToUser(@Payload MessageDTO messageDTO, String sessionId) {
public void sendMessageToUser(@Payload MessageDTO messageDTO, String sessionId) {
log.debug("Sending message: {} to session: {}", messageDTO, sessionId);
messagingTemplate.convertAndSend("/topic/chat/" + sessionId, messageDTO);
return messageDTO;
}
public MessageDTO sendMessageToAdmin(@Payload MessageDTO messageDTO) {
log.debug("Sending message: {} to admin", messageDTO);
chatService.findOne(messageDTO.getChatId()).ifPresent(chatDTO ->
messagingTemplate.convertAndSend("/topic/admin/" + chatDTO.getCommittedBot(), messageDTO
));
return messageDTO;
public void sendMessageToChatCommittedBotCustomerSupportGroup(@Payload MessageDTO messageDTO) {
chatService.findOne(messageDTO.getChatId()).ifPresent(chatDTO -> {
sendMessageToUserGroup(chatDTO.getCommittedBot(), messageDTO);