Add chat takeover
This commit is contained in:
@@ -86,4 +86,13 @@ public class ChatController {
|
||||
List<MessageResponse> messages = chatService.getMessages(id, user.getId(), user.getRole());
|
||||
return ResponseEntity.ok(messages);
|
||||
}
|
||||
|
||||
@PostMapping("/conversations/{id}/request-human")
|
||||
@PreAuthorize("hasRole('CUSTOMER')")
|
||||
public ResponseEntity<ConversationResponse> requestHumanTakeover(@PathVariable Long id) {
|
||||
User user = getCurrentUser();
|
||||
ConversationResponse conversation = chatService.requestHumanTakeover(id, user.getId(), user.getRole());
|
||||
chatRealtimeService.publishConversationUpdate(id);
|
||||
return ResponseEntity.ok(conversation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,19 +9,23 @@ public class ConversationResponse {
|
||||
private Long customerId;
|
||||
private Long staffId;
|
||||
private String status;
|
||||
private String mode;
|
||||
private String lastMessage;
|
||||
private LocalDateTime humanRequestedAt;
|
||||
private LocalDateTime createdAt;
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
public ConversationResponse() {
|
||||
}
|
||||
|
||||
public ConversationResponse(Long id, Long customerId, Long staffId, String status, String lastMessage, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
public ConversationResponse(Long id, Long customerId, Long staffId, String status, String mode, String lastMessage, LocalDateTime humanRequestedAt, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
this.id = id;
|
||||
this.customerId = customerId;
|
||||
this.staffId = staffId;
|
||||
this.status = status;
|
||||
this.mode = mode;
|
||||
this.lastMessage = lastMessage;
|
||||
this.humanRequestedAt = humanRequestedAt;
|
||||
this.createdAt = createdAt;
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
@@ -32,7 +36,9 @@ public class ConversationResponse {
|
||||
response.setCustomerId(conversation.getCustomerId());
|
||||
response.setStaffId(conversation.getStaffId());
|
||||
response.setStatus(conversation.getStatus().name());
|
||||
response.setMode(conversation.getMode().name());
|
||||
response.setLastMessage(lastMessage);
|
||||
response.setHumanRequestedAt(conversation.getHumanRequestedAt());
|
||||
response.setCreatedAt(conversation.getCreatedAt());
|
||||
response.setUpdatedAt(conversation.getUpdatedAt());
|
||||
return response;
|
||||
@@ -70,6 +76,14 @@ public class ConversationResponse {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(String mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public String getLastMessage() {
|
||||
return lastMessage;
|
||||
}
|
||||
@@ -78,6 +92,14 @@ public class ConversationResponse {
|
||||
this.lastMessage = lastMessage;
|
||||
}
|
||||
|
||||
public LocalDateTime getHumanRequestedAt() {
|
||||
return humanRequestedAt;
|
||||
}
|
||||
|
||||
public void setHumanRequestedAt(LocalDateTime humanRequestedAt) {
|
||||
this.humanRequestedAt = humanRequestedAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,13 @@ public class Conversation {
|
||||
@Column(length = 20, nullable = false, columnDefinition = "VARCHAR(20)")
|
||||
private ConversationStatus status = ConversationStatus.OPEN;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(length = 20, nullable = false, columnDefinition = "VARCHAR(20)")
|
||||
private ConversationMode mode = ConversationMode.AUTOMATED;
|
||||
|
||||
@Column
|
||||
private LocalDateTime humanRequestedAt;
|
||||
|
||||
@CreationTimestamp
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
@@ -36,14 +43,20 @@ public class Conversation {
|
||||
OPEN, CLOSED
|
||||
}
|
||||
|
||||
public enum ConversationMode {
|
||||
AUTOMATED, HUMAN
|
||||
}
|
||||
|
||||
public Conversation() {
|
||||
}
|
||||
|
||||
public Conversation(Long id, Long customerId, Long staffId, ConversationStatus status, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
public Conversation(Long id, Long customerId, Long staffId, ConversationStatus status, ConversationMode mode, LocalDateTime humanRequestedAt, LocalDateTime createdAt, LocalDateTime updatedAt) {
|
||||
this.id = id;
|
||||
this.customerId = customerId;
|
||||
this.staffId = staffId;
|
||||
this.status = status;
|
||||
this.mode = mode;
|
||||
this.humanRequestedAt = humanRequestedAt;
|
||||
this.createdAt = createdAt;
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
@@ -80,6 +93,22 @@ public class Conversation {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public ConversationMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(ConversationMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public LocalDateTime getHumanRequestedAt() {
|
||||
return humanRequestedAt;
|
||||
}
|
||||
|
||||
public void setHumanRequestedAt(LocalDateTime humanRequestedAt) {
|
||||
this.humanRequestedAt = humanRequestedAt;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -53,6 +54,7 @@ public class ChatService {
|
||||
Conversation conversation = new Conversation();
|
||||
conversation.setCustomerId(customer.getCustomerId());
|
||||
conversation.setStatus(Conversation.ConversationStatus.OPEN);
|
||||
conversation.setMode(Conversation.ConversationMode.AUTOMATED);
|
||||
conversation = conversationRepository.save(conversation);
|
||||
|
||||
Message message = new Message();
|
||||
@@ -132,12 +134,35 @@ public class ChatService {
|
||||
|
||||
if (role == User.Role.STAFF && conversation.getStaffId() == null) {
|
||||
conversation.setStaffId(userId);
|
||||
}
|
||||
|
||||
if (role == User.Role.STAFF) {
|
||||
conversation.setMode(Conversation.ConversationMode.HUMAN);
|
||||
conversationRepository.save(conversation);
|
||||
}
|
||||
|
||||
return MessageResponse.fromEntity(message);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ConversationResponse requestHumanTakeover(Long conversationId, Long userId, User.Role role) {
|
||||
Conversation conversation = conversationRepository.findById(conversationId)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Conversation not found"));
|
||||
|
||||
if (role != User.Role.CUSTOMER || !hasConversationAccess(conversation, userId, role)) {
|
||||
throw new AccessDeniedException("You can only request human takeover for your own conversations");
|
||||
}
|
||||
|
||||
if (conversation.getHumanRequestedAt() == null) {
|
||||
conversation.setHumanRequestedAt(LocalDateTime.now());
|
||||
}
|
||||
conversationRepository.save(conversation);
|
||||
|
||||
List<Message> messages = messageRepository.findByConversationIdOrderByTimestampAsc(conversationId);
|
||||
String lastMessage = messages.isEmpty() ? "" : messages.get(messages.size() - 1).getContent();
|
||||
return ConversationResponse.fromEntity(conversation, lastMessage);
|
||||
}
|
||||
|
||||
public List<MessageResponse> getMessages(Long conversationId, Long userId, User.Role role) {
|
||||
Conversation conversation = conversationRepository.findById(conversationId)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Conversation not found"));
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
ALTER TABLE conversation
|
||||
ADD COLUMN mode VARCHAR(20) NOT NULL DEFAULT 'AUTOMATED' AFTER status,
|
||||
ADD COLUMN humanRequestedAt TIMESTAMP NULL AFTER mode;
|
||||
|
||||
UPDATE conversation
|
||||
SET mode = CASE
|
||||
WHEN staffId IS NULL THEN 'AUTOMATED'
|
||||
ELSE 'HUMAN'
|
||||
END;
|
||||
Reference in New Issue
Block a user