veza/veza-backend-api/internal/api/handlers/chat_handlers.go
2025-12-03 20:29:37 +01:00

377 lines
10 KiB
Go

//go:build ignore
// +build ignore
// TODO: Réactiver chat_handlers après stabilisation du noyau et alignement des services (ChatService, MessageType, RoomType)
package handlers
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"go.uber.org/zap"
"veza-backend-api/internal/services"
)
// ChatHandlers handles chat-related API endpoints
type ChatHandlers struct {
chatService *services.ChatService
logger *zap.Logger
}
// NewChatHandlers creates new chat handlers
func NewChatHandlers(chatService *services.ChatService, logger *zap.Logger) *ChatHandlers {
return &ChatHandlers{
chatService: chatService,
logger: logger,
}
}
// InitChatHandlers initializes chat handlers
func InitChatHandlers(chatService *services.ChatService, logger *zap.Logger) {
handlers := NewChatHandlers(chatService, logger)
// Store handlers globally for route registration
ChatHandlersInstance = handlers
}
// ChatHandlersInstance holds the global chat handlers instance
var ChatHandlersInstance *ChatHandlers
// CreateMessage creates a new message in a room
func (h *ChatHandlers) CreateMessage(c *gin.Context) {
userID := c.GetInt64("user_id")
roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
var req struct {
Content string `json:"content" binding:"required"`
Type services.MessageType `json:"type"`
ParentID *int64 `json:"parent_id,omitempty"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if req.Type == "" {
req.Type = services.MessageTypeText
}
message, err := h.chatService.CreateMessage(c.Request.Context(), roomID, userID, req.Content, req.Type, req.ParentID)
if err != nil {
h.logger.Error("Failed to create message", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create message"})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"message": message,
})
}
// GetMessages retrieves messages for a room
func (h *ChatHandlers) GetMessages(c *gin.Context) {
roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50"))
beforeIDStr := c.Query("before_id")
var beforeID *int64
if beforeIDStr != "" {
if id, err := strconv.ParseInt(beforeIDStr, 10, 64); err == nil {
beforeID = &id
}
}
messages, err := h.chatService.GetMessages(c.Request.Context(), roomID, page, limit, beforeID)
if err != nil {
h.logger.Error("Failed to get messages", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get messages"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"messages": messages,
"page": page,
"limit": limit,
})
}
// AddReaction adds a reaction to a message
func (h *ChatHandlers) AddReaction(c *gin.Context) {
userID := c.GetInt64("user_id")
messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
return
}
var req struct {
Emoji string `json:"emoji" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
reaction, err := h.chatService.AddReaction(c.Request.Context(), messageID, userID, req.Emoji)
if err != nil {
h.logger.Error("Failed to add reaction", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to add reaction"})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"reaction": reaction,
})
}
// RemoveReaction removes a reaction from a message
func (h *ChatHandlers) RemoveReaction(c *gin.Context) {
userID := c.GetInt64("user_id")
messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
return
}
emoji := c.Param("emoji")
if emoji == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Emoji is required"})
return
}
err = h.chatService.RemoveReaction(c.Request.Context(), messageID, userID, emoji)
if err != nil {
h.logger.Error("Failed to remove reaction", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to remove reaction"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Reaction removed",
})
}
// CreateRoom creates a new chat room
func (h *ChatHandlers) CreateRoom(c *gin.Context) {
userID := c.GetInt64("user_id")
var req struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
Type services.RoomType `json:"type"`
IsPrivate bool `json:"is_private"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if req.Type == "" {
req.Type = services.RoomTypePublic
}
room, err := h.chatService.CreateRoom(c.Request.Context(), req.Name, req.Description, req.Type, req.IsPrivate, userID)
if err != nil {
h.logger.Error("Failed to create room", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create room"})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"room": room,
})
}
// GetRooms retrieves available rooms
func (h *ChatHandlers) GetRooms(c *gin.Context) {
userID := c.GetInt64("user_id")
includePrivate := c.DefaultQuery("include_private", "false") == "true"
rooms, err := h.chatService.GetRooms(c.Request.Context(), userID, includePrivate)
if err != nil {
h.logger.Error("Failed to get rooms", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get rooms"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"rooms": rooms,
})
}
// JoinRoom adds a user to a room
func (h *ChatHandlers) JoinRoom(c *gin.Context) {
userID := c.GetInt64("user_id")
roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
err = h.chatService.JoinRoom(c.Request.Context(), roomID, userID)
if err != nil {
h.logger.Error("Failed to join room", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to join room"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Successfully joined room",
})
}
// LeaveRoom removes a user from a room
func (h *ChatHandlers) LeaveRoom(c *gin.Context) {
userID := c.GetInt64("user_id")
roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
err = h.chatService.LeaveRoom(c.Request.Context(), roomID, userID)
if err != nil {
h.logger.Error("Failed to leave room", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to leave room"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Successfully left room",
})
}
// CreateDirectMessage creates a DM room between two users
func (h *ChatHandlers) CreateDirectMessage(c *gin.Context) {
userID := c.GetInt64("user_id")
var req struct {
UserID int64 `json:"user_id" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
room, err := h.chatService.CreateDirectMessage(c.Request.Context(), userID, req.UserID)
if err != nil {
h.logger.Error("Failed to create DM", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create direct message"})
return
}
c.JSON(http.StatusCreated, gin.H{
"success": true,
"room": room,
})
}
// SearchMessages searches for messages in a room
func (h *ChatHandlers) SearchMessages(c *gin.Context) {
roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
query := c.Query("q")
if query == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "Search query is required"})
return
}
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
messages, err := h.chatService.SearchMessages(c.Request.Context(), roomID, query, limit)
if err != nil {
h.logger.Error("Failed to search messages", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to search messages"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"messages": messages,
"query": query,
"limit": limit,
})
}
// EditMessage edits an existing message
func (h *ChatHandlers) EditMessage(c *gin.Context) {
userID := c.GetInt64("user_id")
messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
return
}
var req struct {
Content string `json:"content" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
message, err := h.chatService.EditMessage(c.Request.Context(), messageID, userID, req.Content)
if err != nil {
h.logger.Error("Failed to edit message", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to edit message"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": message,
})
}
// DeleteMessage deletes a message
func (h *ChatHandlers) DeleteMessage(c *gin.Context) {
userID := c.GetInt64("user_id")
messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"})
return
}
err = h.chatService.DeleteMessage(c.Request.Context(), messageID, userID)
if err != nil {
h.logger.Error("Failed to delete message", zap.Error(err))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete message"})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "Message deleted successfully",
})
}