Erweiterungen
This commit is contained in:
@@ -29,6 +29,7 @@ import com.vaadin.flow.router.Route;
|
|||||||
import com.vaadin.flow.router.RouteParameters;
|
import com.vaadin.flow.router.RouteParameters;
|
||||||
import com.vaadin.flow.shared.Registration;
|
import com.vaadin.flow.shared.Registration;
|
||||||
import de.assecutor.votianlt.model.AppUser;
|
import de.assecutor.votianlt.model.AppUser;
|
||||||
|
import de.assecutor.votianlt.model.Job;
|
||||||
import de.assecutor.votianlt.model.Message;
|
import de.assecutor.votianlt.model.Message;
|
||||||
import de.assecutor.votianlt.model.MessageContentType;
|
import de.assecutor.votianlt.model.MessageContentType;
|
||||||
import de.assecutor.votianlt.model.MessageOrigin;
|
import de.assecutor.votianlt.model.MessageOrigin;
|
||||||
@@ -154,6 +155,8 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
|
|||||||
this.jobNumberContext = filteredMessages.stream().map(Message::getJobNumber)
|
this.jobNumberContext = filteredMessages.stream().map(Message::getJobNumber)
|
||||||
.filter(value -> value != null && !value.isBlank()).findFirst().orElse(null);
|
.filter(value -> value != null && !value.isBlank()).findFirst().orElse(null);
|
||||||
|
|
||||||
|
ensureJobContextForConversation(filteredMessages);
|
||||||
|
|
||||||
String conversationTitle = resolveConversationTitle(filteredMessages, conversationId);
|
String conversationTitle = resolveConversationTitle(filteredMessages, conversationId);
|
||||||
|
|
||||||
HorizontalLayout headerLayout = createHeaderLayout(clientName, conversationTitle);
|
HorizontalLayout headerLayout = createHeaderLayout(clientName, conversationTitle);
|
||||||
@@ -763,6 +766,8 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
|
|||||||
String sender = Optional.ofNullable(securityService.getCurrentUsername()).filter(name -> !name.isBlank())
|
String sender = Optional.ofNullable(securityService.getCurrentUsername()).filter(name -> !name.isBlank())
|
||||||
.orElse("System");
|
.orElse("System");
|
||||||
|
|
||||||
|
ensureJobContextForConversation(currentMessages);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Message saved;
|
Message saved;
|
||||||
if (jobConversation) {
|
if (jobConversation) {
|
||||||
@@ -843,6 +848,60 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
|
|||||||
return value.replaceAll("[^a-zA-Z0-9_-]", "_").toLowerCase();
|
return value.replaceAll("[^a-zA-Z0-9_-]", "_").toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ensureJobContextForConversation(List<Message> messages) {
|
||||||
|
if (!jobConversation) {
|
||||||
|
jobIdContext = null;
|
||||||
|
jobNumberContext = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String token = extractJobConversationToken();
|
||||||
|
if (token == null || token.isBlank()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobIdContext == null && ObjectId.isValid(token)) {
|
||||||
|
try {
|
||||||
|
jobIdContext = new ObjectId(token);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
log.debug("Conversation token {} could not be converted to ObjectId", token, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messages != null && (jobNumberContext == null || jobNumberContext.isBlank())) {
|
||||||
|
jobNumberContext = messages.stream()
|
||||||
|
.map(Message::getJobNumber)
|
||||||
|
.filter(value -> value != null && !value.isBlank())
|
||||||
|
.findFirst()
|
||||||
|
.orElse(jobNumberContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobIdContext == null || jobNumberContext == null || jobNumberContext.isBlank()) {
|
||||||
|
Optional<Job> jobOptional = messageService.findJobByIdentifier(token);
|
||||||
|
if (jobOptional.isEmpty() && jobNumberContext != null && !jobNumberContext.isBlank()) {
|
||||||
|
jobOptional = messageService.findJobByIdentifier(jobNumberContext);
|
||||||
|
}
|
||||||
|
if (jobOptional.isPresent()) {
|
||||||
|
Job job = jobOptional.get();
|
||||||
|
jobIdContext = Optional.ofNullable(job.getId()).orElse(jobIdContext);
|
||||||
|
jobNumberContext = Optional.ofNullable(job.getJobNumber())
|
||||||
|
.filter(value -> !value.isBlank())
|
||||||
|
.orElse(jobNumberContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobNumberContext == null || jobNumberContext.isBlank()) {
|
||||||
|
jobNumberContext = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractJobConversationToken() {
|
||||||
|
if (!jobConversation || conversationId == null || !conversationId.startsWith("job-")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return conversationId.length() > 4 ? conversationId.substring(4) : "";
|
||||||
|
}
|
||||||
|
|
||||||
private String resolveConversationTitle(List<Message> messages, String conversationId) {
|
private String resolveConversationTitle(List<Message> messages, String conversationId) {
|
||||||
if (conversationId == null) {
|
if (conversationId == null) {
|
||||||
return "Konversation";
|
return "Konversation";
|
||||||
@@ -946,7 +1005,9 @@ public class MessageDetailsView extends Main implements BeforeEnterObserver {
|
|||||||
if (currentMessages != null) {
|
if (currentMessages != null) {
|
||||||
// Add new message to the list
|
// Add new message to the list
|
||||||
currentMessages.add(message);
|
currentMessages.add(message);
|
||||||
|
|
||||||
|
ensureJobContextForConversation(currentMessages);
|
||||||
|
|
||||||
// Re-render all messages with the new message included
|
// Re-render all messages with the new message included
|
||||||
renderMessages();
|
renderMessages();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package de.assecutor.votianlt.service;
|
package de.assecutor.votianlt.service;
|
||||||
|
|
||||||
|
import de.assecutor.votianlt.model.Job;
|
||||||
import de.assecutor.votianlt.model.Message;
|
import de.assecutor.votianlt.model.Message;
|
||||||
import de.assecutor.votianlt.model.MessageContentType;
|
import de.assecutor.votianlt.model.MessageContentType;
|
||||||
import de.assecutor.votianlt.model.MessageOrigin;
|
import de.assecutor.votianlt.model.MessageOrigin;
|
||||||
@@ -8,6 +9,7 @@ import de.assecutor.votianlt.dto.ChatMessageInboundPayload;
|
|||||||
import de.assecutor.votianlt.dto.ChatMessageOutboundPayload;
|
import de.assecutor.votianlt.dto.ChatMessageOutboundPayload;
|
||||||
import de.assecutor.votianlt.event.MessageReceivedEvent;
|
import de.assecutor.votianlt.event.MessageReceivedEvent;
|
||||||
import de.assecutor.votianlt.mqtt.MqttPublisher;
|
import de.assecutor.votianlt.mqtt.MqttPublisher;
|
||||||
|
import de.assecutor.votianlt.repository.JobRepository;
|
||||||
import de.assecutor.votianlt.repository.MessageRepository;
|
import de.assecutor.votianlt.repository.MessageRepository;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
@@ -23,12 +25,14 @@ import java.util.Optional;
|
|||||||
public class MessageService {
|
public class MessageService {
|
||||||
|
|
||||||
private final MessageRepository messageRepository;
|
private final MessageRepository messageRepository;
|
||||||
|
private final JobRepository jobRepository;
|
||||||
private final MqttPublisher mqttPublisher;
|
private final MqttPublisher mqttPublisher;
|
||||||
private final ApplicationEventPublisher eventPublisher;
|
private final ApplicationEventPublisher eventPublisher;
|
||||||
|
|
||||||
public MessageService(MessageRepository messageRepository, MqttPublisher mqttPublisher,
|
public MessageService(MessageRepository messageRepository, JobRepository jobRepository,
|
||||||
ApplicationEventPublisher eventPublisher) {
|
MqttPublisher mqttPublisher, ApplicationEventPublisher eventPublisher) {
|
||||||
this.messageRepository = messageRepository;
|
this.messageRepository = messageRepository;
|
||||||
|
this.jobRepository = jobRepository;
|
||||||
this.mqttPublisher = mqttPublisher;
|
this.mqttPublisher = mqttPublisher;
|
||||||
this.eventPublisher = eventPublisher;
|
this.eventPublisher = eventPublisher;
|
||||||
}
|
}
|
||||||
@@ -66,7 +70,9 @@ public class MessageService {
|
|||||||
|
|
||||||
public Message sendJobMessageToClient(String content, String sender, String receiver,
|
public Message sendJobMessageToClient(String content, String sender, String receiver,
|
||||||
MessageContentType contentType, ObjectId jobId, String jobNumber) {
|
MessageContentType contentType, ObjectId jobId, String jobNumber) {
|
||||||
Message message = new Message(content, sender, receiver, MessageOrigin.SERVER, contentType, jobId, jobNumber);
|
JobContext context = resolveJobContext(jobId, jobNumber);
|
||||||
|
Message message = new Message(content, sender, receiver, MessageOrigin.SERVER, contentType,
|
||||||
|
context.jobId(), context.jobNumber());
|
||||||
message = saveMessage(message);
|
message = saveMessage(message);
|
||||||
publishMessageToMqtt(message, receiver);
|
publishMessageToMqtt(message, receiver);
|
||||||
return message;
|
return message;
|
||||||
@@ -79,8 +85,9 @@ public class MessageService {
|
|||||||
Message message;
|
Message message;
|
||||||
MessageContentType contentType = payload.contentType();
|
MessageContentType contentType = payload.contentType();
|
||||||
if (payload.hasJobContext()) {
|
if (payload.hasJobContext()) {
|
||||||
|
JobContext context = resolveJobContext(payload.jobId(), payload.jobNumber());
|
||||||
message = new Message(payload.content(), payload.sender(), payload.receiver(),
|
message = new Message(payload.content(), payload.sender(), payload.receiver(),
|
||||||
MessageOrigin.CLIENT, contentType, payload.jobId(), payload.jobNumber());
|
MessageOrigin.CLIENT, contentType, context.jobId(), context.jobNumber());
|
||||||
} else {
|
} else {
|
||||||
message = new Message(payload.content(), payload.sender(), payload.receiver(),
|
message = new Message(payload.content(), payload.sender(), payload.receiver(),
|
||||||
MessageOrigin.CLIENT, contentType);
|
MessageOrigin.CLIENT, contentType);
|
||||||
@@ -222,4 +229,102 @@ public class MessageService {
|
|||||||
messageRepository.deleteById(messageId);
|
messageRepository.deleteById(messageId);
|
||||||
log.info("Deleted message {}", messageId);
|
log.info("Deleted message {}", messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Job> findJobByIdentifier(String identifier) {
|
||||||
|
if (identifier == null || identifier.isBlank()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Job> jobOptional = Optional.empty();
|
||||||
|
if (ObjectId.isValid(identifier)) {
|
||||||
|
try {
|
||||||
|
jobOptional = jobRepository.findById(new ObjectId(identifier));
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
log.debug("Identifier {} could not be parsed as ObjectId: {}", identifier, ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobOptional.isPresent()) {
|
||||||
|
return jobOptional;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lookupJobByNumber(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JobContext resolveJobContext(ObjectId jobId, String jobNumber) {
|
||||||
|
ObjectId resolvedJobId = jobId;
|
||||||
|
String resolvedJobNumber = jobNumber;
|
||||||
|
|
||||||
|
Optional<Job> jobOptional = lookupJob(jobId, jobNumber);
|
||||||
|
if (jobOptional.isPresent()) {
|
||||||
|
Job job = jobOptional.get();
|
||||||
|
resolvedJobId = job.getId();
|
||||||
|
resolvedJobNumber = Optional.ofNullable(job.getJobNumber()).orElse(resolvedJobNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JobContext(resolvedJobId, resolvedJobNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<Job> lookupJob(ObjectId jobId, String jobNumber) {
|
||||||
|
Optional<Job> jobOptional = Optional.empty();
|
||||||
|
|
||||||
|
if (jobId != null) {
|
||||||
|
jobOptional = jobRepository.findById(jobId);
|
||||||
|
if (jobOptional.isPresent()) {
|
||||||
|
return jobOptional;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobNumber == null || jobNumber.isBlank()) {
|
||||||
|
return jobOptional;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobOptional = jobRepository.findByJobNumber(jobNumber);
|
||||||
|
if (jobOptional.isPresent()) {
|
||||||
|
return jobOptional;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lookupJobByNumber(jobNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<Job> lookupJobByNumber(String candidate) {
|
||||||
|
if (candidate == null || candidate.isBlank()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
String normalizedCandidate = normalizeJobToken(candidate);
|
||||||
|
|
||||||
|
Optional<Job> jobOptional = jobRepository.findByJobNumber(candidate);
|
||||||
|
if (jobOptional.isPresent()) {
|
||||||
|
return jobOptional;
|
||||||
|
}
|
||||||
|
|
||||||
|
String relaxedCandidate = candidate.replace('_', ' ');
|
||||||
|
if (!relaxedCandidate.equals(candidate)) {
|
||||||
|
jobOptional = jobRepository.findByJobNumber(relaxedCandidate);
|
||||||
|
if (jobOptional.isPresent()) {
|
||||||
|
return jobOptional;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Job> fuzzyMatches = jobRepository.findByJobNumberContainingIgnoreCase(relaxedCandidate);
|
||||||
|
if (fuzzyMatches.isEmpty() && !relaxedCandidate.equals(candidate)) {
|
||||||
|
fuzzyMatches = jobRepository.findByJobNumberContainingIgnoreCase(candidate);
|
||||||
|
}
|
||||||
|
if (fuzzyMatches.isEmpty()) {
|
||||||
|
fuzzyMatches = jobRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fuzzyMatches.stream()
|
||||||
|
.filter(job -> normalizeJobToken(job.getJobNumber()).equalsIgnoreCase(normalizedCandidate))
|
||||||
|
.findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeJobToken(String value) {
|
||||||
|
return value == null ? "" : value.replaceAll("[^a-zA-Z0-9_-]", "_");
|
||||||
|
}
|
||||||
|
|
||||||
|
private record JobContext(ObjectId jobId, String jobNumber) {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user