package handlers import ( "errors" "net/http" "strconv" "veza-backend-api/internal/services" "github.com/gin-gonic/gin" "github.com/google/uuid" "go.uber.org/zap" ) // CommentHandler gère les opérations sur les commentaires de tracks type CommentHandler struct { commentService *services.CommentService commonHandler *CommonHandler } // NewCommentHandler crée un nouveau handler de commentaires func NewCommentHandler(commentService *services.CommentService, logger *zap.Logger) *CommentHandler { return &CommentHandler{ commentService: commentService, commonHandler: NewCommonHandler(logger), } } // CreateCommentRequest représente la requête pour créer un commentaire type CreateCommentRequest struct { Content string `json:"content" binding:"required,min=1,max=5000"` ParentID *uuid.UUID `json:"parent_id,omitempty"` // Changed to *uuid.UUID } // UpdateCommentRequest représente la requête pour mettre à jour un commentaire type UpdateCommentRequest struct { Content string `json:"content" binding:"required,min=1,max=5000"` } // CreateComment gère la création d'un commentaire sur un track func (h *CommentHandler) CreateComment(c *gin.Context) { userID, ok := GetUserIDUUID(c) if !ok { return // Erreur déjà envoyée par GetUserIDUUID } if userID == uuid.Nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) return } trackIDStr := c.Param("id") if trackIDStr == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "track id is required"}) return } trackID, err := uuid.Parse(trackIDStr) // Changed to uuid.Parse if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid track id"}) return } var req CreateCommentRequest if appErr := h.commonHandler.BindAndValidateJSON(c, &req); appErr != nil { RespondWithAppError(c, appErr) return } comment, err := h.commentService.CreateComment(c.Request.Context(), trackID, userID, req.Content, 0.0, req.ParentID) // req.ParentID is already *uuid.UUID if err != nil { if errors.Is(err, services.ErrTrackNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": "track not found"}) return } if errors.Is(err, services.ErrParentCommentNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": "parent comment not found"}) return } if errors.Is(err, services.ErrParentTrackMismatch) { c.JSON(http.StatusBadRequest, gin.H{"error": "parent comment does not belong to the same track"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusCreated, gin.H{"comment": comment}) } // GetComments gère la récupération des commentaires d'un track func (h *CommentHandler) GetComments(c *gin.Context) { trackIDStr := c.Param("id") if trackIDStr == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "track id is required"}) return } trackID, err := uuid.Parse(trackIDStr) // Changed to uuid.Parse if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid track id"}) return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20")) if page < 1 { page = 1 } if limit < 1 { limit = 20 } if limit > 100 { limit = 100 } comments, total, err := h.commentService.GetComments(c.Request.Context(), trackID, page, limit) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "comments": comments, "total": total, "page": page, "limit": limit, }) } // UpdateComment gère la mise à jour d'un commentaire func (h *CommentHandler) UpdateComment(c *gin.Context) { userID, ok := GetUserIDUUID(c) if !ok { return // Erreur déjà envoyée par GetUserIDUUID } if userID == uuid.Nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) return } commentIDStr := c.Param("id") if commentIDStr == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "comment id is required"}) return } commentID, err := uuid.Parse(commentIDStr) // Changed to uuid.Parse if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid comment id"}) return } var req UpdateCommentRequest if appErr := h.commonHandler.BindAndValidateJSON(c, &req); appErr != nil { RespondWithAppError(c, appErr) return } comment, err := h.commentService.UpdateComment(c.Request.Context(), commentID, userID, req.Content) if err != nil { if errors.Is(err, services.ErrCommentNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": "comment not found"}) return } if errors.Is(err, services.ErrForbidden) { c.JSON(http.StatusForbidden, gin.H{"error": "unauthorized: you can only edit your own comments"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"comment": comment}) } // DeleteComment gère la suppression d'un commentaire func (h *CommentHandler) DeleteComment(c *gin.Context) { userID, ok := GetUserIDUUID(c) if !ok { return // Erreur déjà envoyée par GetUserIDUUID } if userID == uuid.Nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) return } commentIDStr := c.Param("id") if commentIDStr == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "comment id is required"}) return } commentID, err := uuid.Parse(commentIDStr) // Changed to uuid.Parse if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid comment id"}) return } err = h.commentService.DeleteComment(c.Request.Context(), commentID, userID, false) // Added false for isAdmin if err != nil { if errors.Is(err, services.ErrCommentNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": "comment not found"}) return } if errors.Is(err, services.ErrForbidden) { c.JSON(http.StatusForbidden, gin.H{"error": "unauthorized: you can only delete your own comments"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"message": "comment deleted successfully"}) } // GetReplies gère la récupération des réponses d'un commentaire func (h *CommentHandler) GetReplies(c *gin.Context) { parentIDStr := c.Param("id") if parentIDStr == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "parent comment id is required"}) return } parentID, err := uuid.Parse(parentIDStr) // Changed to uuid.Parse if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid parent comment id"}) return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20")) if page < 1 { page = 1 } if limit < 1 { limit = 20 } if limit > 100 { limit = 100 } replies, total, err := h.commentService.GetReplies(c.Request.Context(), parentID, page, limit) if err != nil { if errors.Is(err, services.ErrParentCommentNotFound) { c.JSON(http.StatusNotFound, gin.H{"error": "parent comment not found"}) return } c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "replies": replies, "total": total, "page": page, "limit": limit, }) }