Add chat close endpoint

This commit is contained in:
2026-03-29 19:02:12 -06:00
parent c37a2fdf45
commit ab97a86977
3 changed files with 165 additions and 0 deletions

View File

@@ -96,4 +96,13 @@ public class ChatController {
chatRealtimeService.publishConversationUpdate(id);
return ResponseEntity.ok(conversation);
}
@PostMapping("/conversations/{id}/close")
@PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')")
public ResponseEntity<ConversationResponse> closeConversation(@PathVariable Long id) {
User user = getCurrentUser();
ConversationResponse conversation = chatService.closeConversation(id, user.getId(), user.getRole());
chatRealtimeService.publishConversationUpdate(id);
return ResponseEntity.ok(conversation);
}
}

View File

@@ -116,6 +116,10 @@ public class ChatService {
Conversation conversation = conversationRepository.findById(conversationId)
.orElseThrow(() -> new ResourceNotFoundException("Conversation not found"));
if (conversation.getStatus() == Conversation.ConversationStatus.CLOSED) {
throw new AccessDeniedException("Conversation is closed");
}
if (!hasConversationAccess(conversation, userId, role)) {
if (role == User.Role.CUSTOMER) {
throw new AccessDeniedException("You can only send messages to your own conversations");
@@ -149,6 +153,10 @@ public class ChatService {
Conversation conversation = conversationRepository.findById(conversationId)
.orElseThrow(() -> new ResourceNotFoundException("Conversation not found"));
if (conversation.getStatus() == Conversation.ConversationStatus.CLOSED) {
throw new AccessDeniedException("Conversation is closed");
}
if (role != User.Role.CUSTOMER || !hasConversationAccess(conversation, userId, role)) {
throw new AccessDeniedException("You can only request human takeover for your own conversations");
}
@@ -163,6 +171,28 @@ public class ChatService {
return ConversationResponse.fromEntity(conversation, lastMessage);
}
@Transactional
public ConversationResponse closeConversation(Long conversationId, Long userId, User.Role role) {
Conversation conversation = conversationRepository.findById(conversationId)
.orElseThrow(() -> new ResourceNotFoundException("Conversation not found"));
if (!hasConversationAccess(conversation, userId, role)) {
if (role == User.Role.CUSTOMER) {
throw new AccessDeniedException("You can only close your own conversations");
}
if (role == User.Role.STAFF) {
throw new AccessDeniedException("You can only close conversations assigned to you or unassigned conversations");
}
}
conversation.setStatus(Conversation.ConversationStatus.CLOSED);
conversation = 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"));