Commit 555ad55a authored by henrik.prangel's avatar henrik.prangel
Browse files

JUT-100 Integrate elasticsearch with api

 * Send messages and chats to elasticsearch
parent c18e3947
......@@ -265,6 +265,7 @@ dependencies {
implementation "org.springframework.security:spring-security-data"
implementation "org.springframework.security:spring-security-web"
implementation "org.springframework.security:spring-security-messaging"
implementation "org.springframework.data:spring-data-elasticsearch"
implementation "io.jsonwebtoken:jjwt-api"
if (!project.hasProperty("gae")) {
runtimeOnly "io.jsonwebtoken:jjwt-impl"
......
package com.netgroup.riigibot.config;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
@Configuration
@ConfigurationProperties(prefix = "elasticsearch")
public class ElasticSearchConfiguration extends AbstractElasticsearchConfiguration {
private String endpoints = "localhost";
public String getEndpoints() {
return endpoints;
}
public void setEndpoints(String endpoint) {
this.endpoints = endpoint;
}
@Override
@Bean
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(endpoints)
.build();
return RestClients.create(clientConfiguration).rest();
}
@Bean
public ElasticsearchOperations elasticsearchTemplate() {
return new ElasticsearchRestTemplate(elasticsearchClient());
}
}
package com.netgroup.riigibot.domain.elastic;
import org.springframework.data.elasticsearch.annotations.Document;
import javax.persistence.*;
import java.time.Instant;
@Document(indexName = "chat", type = "")
public class ElasticChat {
@Id
private Long id;
private String topic;
private Instant created;
private Instant updated;
private Instant deleted;
private String committedBot;
private String committedAdmin;
private Boolean needsCustomerService;
private Instant ended;
private Boolean hasBeenLabeled;
private String lastUserReferer;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTopic() {
return topic;
}
public void setTopic(String topic) {
this.topic = topic;
}
public Instant getCreated() {
return created;
}
public void setCreated(Instant created) {
this.created = created;
}
public Instant getUpdated() {
return updated;
}
public void setUpdated(Instant updated) {
this.updated = updated;
}
public Instant getDeleted() {
return deleted;
}
public void setDeleted(Instant deleted) {
this.deleted = deleted;
}
public String getCommittedBot() {
return committedBot;
}
public void setCommittedBot(String committedBot) {
this.committedBot = committedBot;
}
public String getCommittedAdmin() {
return committedAdmin;
}
public void setCommittedAdmin(String committedAdmin) {
this.committedAdmin = committedAdmin;
}
public Boolean getNeedsCustomerService() {
return needsCustomerService;
}
public void setNeedsCustomerService(Boolean needsCustomerService) {
this.needsCustomerService = needsCustomerService;
}
public Instant getEnded() {
return ended;
}
public void setEnded(Instant ended) {
this.ended = ended;
}
public Boolean getHasBeenLabeled() {
return hasBeenLabeled;
}
public void setHasBeenLabeled(Boolean hasBeenLabeled) {
this.hasBeenLabeled = hasBeenLabeled;
}
public String getLastUserReferer() {
return lastUserReferer;
}
public void setLastUserReferer(String lastUserReferer) {
this.lastUserReferer = lastUserReferer;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof ElasticChat)) {
return false;
}
return id != null && id.equals(((ElasticChat) o).id);
}
@Override
public int hashCode() {
return 31;
}
}
package com.netgroup.riigibot.domain.elastic;
import org.springframework.data.elasticsearch.annotations.Document;
import javax.persistence.*;
import java.time.Instant;
@Document(indexName = "chat_message", type = "")
public class ElasticMessage {
@Id
private Long id;
private String text;
private String sender;
private String confidence;
private Instant created;
private Instant updated;
private Instant deleted;
private String interpretedIntent;
private String vote;
private Long chatId;
private Long authorId;
private Boolean validated;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getConfidence() {
return confidence;
}
public void setConfidence(String confidence) {
this.confidence = confidence;
}
public Instant getCreated() {
return created;
}
public void setCreated(Instant created) {
this.created = created;
}
public Instant getUpdated() {
return updated;
}
public void setUpdated(Instant updated) {
this.updated = updated;
}
public Instant getDeleted() {
return deleted;
}
public void setDeleted(Instant deleted) {
this.deleted = deleted;
}
public String getInterpretedIntent() {
return interpretedIntent;
}
public void setInterpretedIntent(String interpretedIntent) {
this.interpretedIntent = interpretedIntent;
}
public String getVote() {
return vote;
}
public void setVote(String vote) {
this.vote = vote;
}
public Long getChatId() {
return chatId;
}
public void setChatId(Long chatId) {
this.chatId = chatId;
}
public Long getAuthorId() {
return authorId;
}
public void setAuthorId(Long authorId) {
this.authorId = authorId;
}
public Boolean getValidated() {
return validated;
}
public void setValidated(Boolean validated) {
this.validated = validated;
}
@Override
public int hashCode() {
return 31;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ElasticMessage)) {
return false;
}
return id != null && id.equals(((ElasticMessage) obj).id);
}
}
package com.netgroup.riigibot.repository;
import com.netgroup.riigibot.domain.elastic.ElasticChat;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ElasticChatRepository extends ElasticsearchRepository<ElasticChat, Long> {
}
package com.netgroup.riigibot.repository;
import com.netgroup.riigibot.domain.elastic.ElasticMessage;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ElasticMessageRepository extends ElasticsearchRepository<ElasticMessage, Long> {
}
......@@ -35,11 +35,15 @@ public class ChatService {
private final UserService userService;
public ChatService(ChatRepository chatRepository, MessageRepository messageRepository, ChatMapper chatMapper, UserService userService) {
private final ElasticService elasticService;
public ChatService(ChatRepository chatRepository, MessageRepository messageRepository, ChatMapper chatMapper,
UserService userService, ElasticService elasticService) {
this.chatRepository = chatRepository;
this.messageRepository = messageRepository;
this.chatMapper = chatMapper;
this.userService = userService;
this.elasticService = elasticService;
}
/**
......@@ -133,7 +137,9 @@ public class ChatService {
public ChatDTO createNewChatByMessage(MessageDTO messageDTO) {
ChatDTO newChat = new ChatDTO();
newChat.setSessionId(messageDTO.getSessionId());
return save(newChat);
ChatDTO savedChat = save(newChat);
elasticService.indexChat(savedChat);
return savedChat;
}
public ChatDTO getChatById(Long chatId) {
......@@ -147,7 +153,8 @@ public class ChatService {
public void updateChatWithMessageInformation(ChatDTO chatDTO, MessageDTO messageDTO, String referer) {
chatDTO.setLastUserReferer(referer);
chatDTO.setLastMessageId(messageDTO.getId());
save(chatDTO);
ChatDTO savedChat = save(chatDTO);
elasticService.indexChat(savedChat);
}
public ChatDTO updateChatCommittedBotForCustomerService(ChatDTO chatDTO, String bot) {
......@@ -159,19 +166,23 @@ public class ChatService {
public ChatDTO commitBotToChat(String bot, ChatDTO chatDTO) {
log.debug("Committing bot {} to chat {}", bot, chatDTO.getId());
chatDTO.setCommittedBot(bot);
return save(chatDTO);
ChatDTO savedChat = save(chatDTO);
elasticService.indexChat(savedChat);
return savedChat;
}
public void commitAdminToChat(ChatDTO chatDTO, Principal principal) {
log.debug("Committing admin {} to chat {}", principal.getName(), chatDTO.getId());
chatDTO.setCommittedAdmin(principal.getName());
save(chatDTO);
ChatDTO savedChat = save(chatDTO);
elasticService.indexChat(savedChat);
}
public void updateChatNeedsCustomerServiceToTrue(ChatDTO chatDTO) {
log.debug("Setting needs-customer-service of chat {} to true", chatDTO.getId());
chatDTO.setNeedsCustomerService(true);
save(chatDTO);
ChatDTO savedChat = save(chatDTO);
elasticService.indexChat(savedChat);
}
public ChatDTO getOrCreateChatForMessage(MessageDTO userMessage) {
......@@ -187,6 +198,8 @@ public class ChatService {
public ChatDTO endChat(ChatDTO chatDTO) {
chatDTO.setEnded(Instant.now());
return save(chatDTO);
ChatDTO savedChat = save(chatDTO);
elasticService.indexChat(savedChat);
return savedChat;
}
}
package com.netgroup.riigibot.service;
import com.netgroup.riigibot.repository.ElasticChatRepository;
import com.netgroup.riigibot.repository.ElasticMessageRepository;
import com.netgroup.riigibot.domain.elastic.ElasticChat;
import com.netgroup.riigibot.domain.elastic.ElasticMessage;
import com.netgroup.riigibot.service.dto.ChatDTO;
import com.netgroup.riigibot.service.dto.MessageDTO;
import com.netgroup.riigibot.service.mapper.elastic.ElasticChatMapper;
import com.netgroup.riigibot.service.mapper.elastic.ElasticMessageMapper;
import org.springframework.stereotype.Controller;
@Controller
public class ElasticService {
private final ElasticMessageRepository elasticMessageRepository;
private final ElasticChatRepository elasticChatRepository;
private final ElasticMessageMapper elasticMessageMapper;
private final ElasticChatMapper elasticChatMapper;
public ElasticService(ElasticMessageRepository elasticMessageRepository, ElasticChatRepository elasticChatRepository,
ElasticMessageMapper elasticMessageMapper, ElasticChatMapper elasticChatMapper) {
this.elasticMessageRepository = elasticMessageRepository;
this.elasticChatRepository = elasticChatRepository;
this.elasticMessageMapper = elasticMessageMapper;
this.elasticChatMapper = elasticChatMapper;
}
public MessageDTO indexMessage(MessageDTO messageDTO) {
ElasticMessage message = elasticMessageMapper.toEntity(messageDTO);
message = elasticMessageRepository.save(message);
return elasticMessageMapper.toDto(message);
}
public ChatDTO indexChat(ChatDTO chatDTO) {
ElasticChat chat = elasticChatMapper.toEntity(chatDTO);
chat = elasticChatRepository.save(chat);
return elasticChatMapper.toDto(chat);
}
}
......@@ -47,12 +47,15 @@ public class MessageService {
private final ChatService chatService;
private final ElasticService elasticService;
public MessageService(MessageRepository messageRepository, MessageMapper messageMapper,
SimpMessageSendingOperations messagingTemplate, ChatService chatService) {
SimpMessageSendingOperations messagingTemplate, ChatService chatService, ElasticService elasticService) {
this.messageRepository = messageRepository;
this.messageMapper = messageMapper;
this.messagingTemplate = messagingTemplate;
this.chatService = chatService;
this.elasticService = elasticService;
}
/**
......@@ -174,6 +177,7 @@ public class MessageService {
public void saveAndSendMessageToUserAndResponsibleCustomerSupportGroup(MessageDTO messageDTO) {
MessageDTO savedMessage = save(messageDTO);
elasticService.indexMessage(savedMessage);
sendMessageToUser(savedMessage, savedMessage.getSessionId());
sendMessageToChatCommittedBotCustomerSupportGroup(savedMessage);
}
......
package com.netgroup.riigibot.service.mapper.elastic;
import com.netgroup.riigibot.domain.elastic.ElasticChat;
import com.netgroup.riigibot.service.dto.ChatDTO;
import com.netgroup.riigibot.service.mapper.EntityMapper;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
/**
* Mapper for the entity {@link com.netgroup.riigibot.domain.elastic.ElasticChat} and its DTO counterpart {@link ChatDTO}.
*/
@Mapper(componentModel = "spring", uses = {})
public interface ElasticChatMapper extends EntityMapper<ChatDTO, ElasticChat> {
ElasticChat toEntity(ChatDTO chatDTO);
@Mapping(target = "lastMessageText", ignore = true)
@Mapping(target = "messages", ignore = true)
@Mapping(target = "lastMessageId", ignore = true)
@Mapping(target = "sessionId", ignore = true)
ChatDTO toDto(ElasticChat chat);
}
package com.netgroup.riigibot.service.mapper.elastic;
import com.netgroup.riigibot.domain.elastic.ElasticMessage;
import com.netgroup.riigibot.service.dto.MessageDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
/**
* Mapper for the entity {@link ElasticMessage} and its DTO counterpart {@link MessageDTO}.
*/
@Mapper(componentModel = "spring", uses = {})
public interface ElasticMessageMapper {
ElasticMessage toEntity(MessageDTO messageDTO);
@Mapping(target = "sessionId", ignore = true)
@Mapping(target = "buttons", ignore = true)
@Mapping(target = "authorFirstName", ignore = true)
@Mapping(target = "authorLoginName", ignore = true)
@Mapping(target = "addressedBot", ignore = true)
MessageDTO toDto(ElasticMessage message);
}
......@@ -2,6 +2,7 @@ package com.netgroup.riigibot.web.rest;
import com.netgroup.riigibot.config.KafkaProperties;
import com.netgroup.riigibot.service.ChatService;
import com.netgroup.riigibot.service.ElasticService;
import com.netgroup.riigibot.service.MessageService;
import com.netgroup.riigibot.service.dto.ChatDTO;
import com.netgroup.riigibot.service.dto.MessageDTO;
......@@ -43,11 +44,13 @@ public class MessageResource {
private final KafkaProducer<String, MessageDTO> producer;
private final MessageService messageService;
private final ChatService chatService;
private final ElasticService elasticService;
public MessageResource(KafkaProperties kafkaProperties, MessageService messageService, ChatService chatService) {
public MessageResource(KafkaProperties kafkaProperties, MessageService messageService, ChatService chatService, ElasticService elasticService) {
this.producer = new KafkaProducer<>(kafkaProperties.getProducerProps());
this.messageService = messageService;
this.chatService = chatService;
this.elasticService = elasticService;
}
/**
......@@ -169,6 +172,7 @@ public class MessageResource {
chatService.updateChatWithMessageInformation(chatDTO, savedUserMessage, referer);
messageService.sendMessageToChatCommittedBotCustomerSupportGroup(savedUserMessage);
elasticService.indexMessage(savedUserMessage);
if (!chatService.isChatHandledByCustomerSupport(chatDTO)) {
log.debug(
"Request to send message {} with key {} to Kafka topic 'user_events'",
......
......@@ -175,3 +175,5 @@ kafka:
# ===================================================================
# application:
elasticsearch:
endpoints: 10.1.15.26
package com.netgroup.riigibot.config;
import com.netgroup.riigibot.repository.ElasticChatRepository;
import com.netgroup.riigibot.repository.ElasticMessageRepository;