veza/veza-backend-api/internal/handlers/room_handler.go

226 lines
6.7 KiB
Go

package handlers
import (
"context"
"errors"
"net/http"
"strconv"
"veza-backend-api/internal/services"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"go.uber.org/zap"
)
// RoomServiceInterface defines the interface for room service operations
type RoomServiceInterface interface {
CreateRoom(ctx context.Context, userID uuid.UUID, req services.CreateRoomRequest) (*services.RoomResponse, error)
GetUserRooms(ctx context.Context, userID uuid.UUID) ([]*services.RoomResponse, error)
GetRoom(ctx context.Context, roomID uuid.UUID) (*services.RoomResponse, error)
AddMember(ctx context.Context, roomID, userID uuid.UUID) error
GetRoomHistory(ctx context.Context, roomID uuid.UUID, limit, offset int) ([]services.ChatMessageResponse, error)
}
// RoomHandler gère les opérations sur les rooms (conversations)
type RoomHandler struct {
roomService RoomServiceInterface
logger *zap.Logger
commonHandler *CommonHandler
}
// NewRoomHandler crée une nouvelle instance de RoomHandler
func NewRoomHandler(roomService RoomServiceInterface, logger *zap.Logger) *RoomHandler {
return &RoomHandler{
roomService: roomService,
logger: logger,
commonHandler: NewCommonHandler(logger),
}
}
// CreateRoom gère la création d'une nouvelle room
// POST /api/v1/conversations
func (h *RoomHandler) CreateRoom(c *gin.Context) {
// Récupérer l'ID utilisateur du contexte
userIDInterface, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
return
}
// Convertir userID en uuid.UUID
userID, ok := userIDInterface.(uuid.UUID)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user ID type in context"})
return
}
// Parser la requête
var req services.CreateRoomRequest
if appErr := h.commonHandler.BindAndValidateJSON(c, &req); appErr != nil {
RespondWithAppError(c, appErr)
return
}
// Valider le type de room si non spécifié
if req.Type == "" {
req.Type = "public"
}
// Créer la room
room, err := h.roomService.CreateRoom(c.Request.Context(), userID, req)
if err != nil {
h.logger.Error("failed to create room",
zap.Error(err),
zap.String("user_id", userID.String()),
zap.String("room_name", req.Name))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create conversation"})
return
}
h.logger.Info("room created successfully",
zap.String("room_id", room.ID.String()),
zap.String("user_id", userID.String()),
zap.String("room_name", req.Name))
RespondSuccess(c, http.StatusCreated, room)
}
// GetUserRooms récupère toutes les rooms d'un utilisateur
// GET /api/v1/conversations
func (h *RoomHandler) GetUserRooms(c *gin.Context) {
// Récupérer l'ID utilisateur du contexte
userIDInterface, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
return
}
// Convertir userID en uuid.UUID
userID, ok := userIDInterface.(uuid.UUID)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Invalid user ID type in context"})
return
}
// Récupérer les rooms
rooms, err := h.roomService.GetUserRooms(c.Request.Context(), userID)
if err != nil {
h.logger.Error("failed to get user rooms",
zap.Error(err),
zap.String("user_id", userID.String()))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch conversations"})
return
}
RespondSuccess(c, http.StatusOK, gin.H{
"conversations": rooms,
"total": len(rooms),
})
}
// GetRoom récupère une room par son ID
// GET /api/v1/conversations/:id
func (h *RoomHandler) GetRoom(c *gin.Context) {
// Récupérer l'ID de la room depuis l'URL
roomIDStr := c.Param("id")
roomID, err := uuid.Parse(roomIDStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
// Récupérer la room
room, err := h.roomService.GetRoom(c.Request.Context(), roomID)
if err != nil {
if errors.Is(err, services.ErrRoomNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "Conversation not found"})
return
}
h.logger.Error("failed to get room",
zap.Error(err),
zap.String("room_id", roomID.String()))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get conversation"})
return
}
RespondSuccess(c, http.StatusOK, room)
}
// AddMemberRequest représente une requête pour ajouter un membre à une room
type AddMemberRequest struct {
UserID uuid.UUID `json:"user_id" binding:"required"` // Changed to UUID
}
// AddMember ajoute un membre à une room
// POST /api/v1/conversations/:id/members
func (h *RoomHandler) AddMember(c *gin.Context) {
// Récupérer l'ID de la room depuis l'URL
roomIDStr := c.Param("id")
roomID, err := uuid.Parse(roomIDStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"})
return
}
// Parser la requête
var req AddMemberRequest
if appErr := h.commonHandler.BindAndValidateJSON(c, &req); appErr != nil {
RespondWithAppError(c, appErr)
return
}
// Ajouter le membre
if err := h.roomService.AddMember(c.Request.Context(), roomID, req.UserID); err != nil {
h.logger.Error("failed to add member to room",
zap.Error(err),
zap.String("room_id", roomID.String()),
zap.String("user_id", req.UserID.String()))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to add member"})
return
}
h.logger.Info("member added to room",
zap.String("room_id", roomID.String()),
zap.String("user_id", req.UserID.String()))
RespondSuccess(c, http.StatusOK, gin.H{"message": "Member added successfully"})
}
// GetRoomHistory récupère l'historique des messages d'une room
// GET /api/v1/conversations/:id/history
func (h *RoomHandler) GetRoomHistory(c *gin.Context) {
conversationIDStr := c.Param("id")
conversationID, err := uuid.Parse(conversationIDStr)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid conversation ID"})
return
}
limit := c.DefaultQuery("limit", "50")
offset := c.DefaultQuery("offset", "0")
limitInt, err := strconv.Atoi(limit)
if err != nil || limitInt <= 0 {
limitInt = 50
}
offsetInt, err := strconv.Atoi(offset)
if err != nil || offsetInt < 0 {
offsetInt = 0
}
messages, err := h.roomService.GetRoomHistory(c.Request.Context(), conversationID, limitInt, offsetInt)
if err != nil {
if errors.Is(err, services.ErrRoomNotFound) {
c.JSON(http.StatusNotFound, gin.H{"error": "Conversation not found"})
return
}
h.logger.Error("failed to get room history",
zap.Error(err),
zap.String("conversation_id", conversationID.String()))
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get conversation history"})
return
}
RespondSuccess(c, http.StatusOK, gin.H{"messages": messages})
}