diff --git a/veza-backend-api/internal/core/track/handler.go b/veza-backend-api/internal/core/track/handler.go index 74e9e563f..54dcf847b 100644 --- a/veza-backend-api/internal/core/track/handler.go +++ b/veza-backend-api/internal/core/track/handler.go @@ -16,7 +16,6 @@ import ( "gorm.io/gorm" "veza-backend-api/internal/models" "veza-backend-api/internal/services" - "veza-backend-api/internal/services" "veza-backend-api/internal/validators" "veza-backend-api/internal/response" ) @@ -88,13 +87,13 @@ func (h *TrackHandler) SetHistoryService(historyService *services.TrackHistorySe func (h *TrackHandler) UploadTrack(c *gin.Context) { userID := c.MustGet("user_id").(uuid.UUID) if userID == uuid.Nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + response.Unauthorized(c, "unauthorized") return } fileHeader, err := c.FormFile("file") if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "no file provided"}) + response.BadRequest(c, "no file provided") return } @@ -104,7 +103,7 @@ func (h *TrackHandler) UploadTrack(c *gin.Context) { // Mapper les erreurs vers des messages utilisateur spécifiques errorMessage := h.mapTrackError(err) statusCode := h.getErrorStatusCode(err) - c.JSON(statusCode, gin.H{"error": errorMessage}) + response.Error(c, statusCode, errorMessage) return } @@ -118,7 +117,7 @@ func (h *TrackHandler) UploadTrack(c *gin.Context) { } } - c.JSON(http.StatusCreated, gin.H{"track": track}) + response.Created(c, gin.H{"track": track}) } // GetUploadStatus récupère le statut d'upload d'un track @@ -137,7 +136,7 @@ func (h *TrackHandler) UploadTrack(c *gin.Context) { func (h *TrackHandler) GetUploadStatus(c *gin.Context) { trackIDStr := c.Param("id") if trackIDStr == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "track id is required"}) + response.BadRequest(c, "track id is required") return } @@ -148,14 +147,14 @@ func (h *TrackHandler) GetUploadStatus(c *gin.Context) { trackID, err := uuid.Parse(trackIDStr) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid track id"}) + response.BadRequest(c, "invalid track id") return } // Vérifier que l'utilisateur est autorisé à voir ce track userID := c.MustGet("user_id").(uuid.UUID) if userID == uuid.Nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + response.Unauthorized(c, "unauthorized") return } @@ -180,11 +179,11 @@ func (h *TrackHandler) GetUploadStatus(c *gin.Context) { progress, err := h.trackUploadService.GetUploadProgress(c.Request.Context(), trackID) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get upload progress"}) + response.InternalServerError(c, "failed to get upload progress") return } - c.JSON(http.StatusOK, gin.H{"progress": progress}) + response.Success(c, gin.H{"progress": progress}) } // InitiateChunkedUploadRequest représente la requête pour initialiser un upload par chunks @@ -209,7 +208,7 @@ type InitiateChunkedUploadRequest struct { func (h *TrackHandler) InitiateChunkedUpload(c *gin.Context) { userID := c.MustGet("user_id").(uuid.UUID) if userID == uuid.Nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + response.Unauthorized(c, "unauthorized") return } @@ -218,13 +217,11 @@ func (h *TrackHandler) InitiateChunkedUpload(c *gin.Context) { // GO-013: Utiliser validator pour messages d'erreur plus clairs validator := validators.NewValidator() if validationErrs := validator.Validate(&req); len(validationErrs) > 0 { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "Validation failed", - "errors": validationErrs, - }) + // Using BadRequest for validation errors + response.Error(c, http.StatusBadRequest, fmt.Sprintf("Validation failed: %v", validationErrs)) return } - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + response.BadRequest(c, err.Error()) return } @@ -232,11 +229,11 @@ func (h *TrackHandler) InitiateChunkedUpload(c *gin.Context) { // InitiateChunkedUpload retourne un string (uploadID) donc pas de souci d'int64 uploadID, err := h.chunkService.InitiateChunkedUpload(userID, req.TotalChunks, req.TotalSize, req.Filename) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + response.InternalServerError(c, err.Error()) return } - c.JSON(http.StatusOK, gin.H{ + response.Success(c, gin.H{ "upload_id": uploadID, "message": "upload initiated successfully", }) @@ -271,36 +268,36 @@ type UploadChunkRequest struct { func (h *TrackHandler) UploadChunk(c *gin.Context) { userID := c.MustGet("user_id").(uuid.UUID) if userID == uuid.Nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + response.Unauthorized(c, "unauthorized") return } var req UploadChunkRequest if err := c.ShouldBind(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + response.BadRequest(c, err.Error()) return } fileHeader, err := c.FormFile("chunk") if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "no chunk file provided"}) + response.BadRequest(c, "no chunk file provided") return } // Sauvegarder le chunk if err := h.chunkService.SaveChunk(c.Request.Context(), req.UploadID, req.ChunkNumber, req.TotalChunks, fileHeader); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + response.BadRequest(c, err.Error()) return } // Récupérer la progression receivedChunks, progress, err := h.chunkService.GetUploadProgress(req.UploadID) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + response.InternalServerError(c, err.Error()) return } - c.JSON(http.StatusOK, gin.H{ + response.Success(c, gin.H{ "message": "chunk uploaded successfully", "upload_id": req.UploadID, "received_chunks": receivedChunks, @@ -329,7 +326,7 @@ type CompleteChunkedUploadRequest struct { func (h *TrackHandler) CompleteChunkedUpload(c *gin.Context) { userID := c.MustGet("user_id").(uuid.UUID) if userID == uuid.Nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + response.Unauthorized(c, "unauthorized") return } @@ -338,20 +335,17 @@ func (h *TrackHandler) CompleteChunkedUpload(c *gin.Context) { // GO-013: Utiliser validator pour messages d'erreur plus clairs validator := validators.NewValidator() if validationErrs := validator.Validate(&req); len(validationErrs) > 0 { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "Validation failed", - "errors": validationErrs, - }) + response.Error(c, http.StatusBadRequest, fmt.Sprintf("Validation failed: %v", validationErrs)) return } - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + response.BadRequest(c, err.Error()) return } // Récupérer les informations de l'upload pour obtenir le filename uploadInfo, err := h.chunkService.GetUploadInfo(req.UploadID) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + response.BadRequest(c, err.Error()) return } @@ -366,7 +360,7 @@ func (h *TrackHandler) CompleteChunkedUpload(c *gin.Context) { // Assurer que le répertoire existe if err := os.MkdirAll(filepath.Dir(finalPath), 0755); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create directory"}) + response.InternalServerError(c, "failed to create directory") return } @@ -375,7 +369,7 @@ func (h *TrackHandler) CompleteChunkedUpload(c *gin.Context) { if err != nil { errorMessage := h.mapTrackError(err) statusCode := h.getErrorStatusCode(err) - c.JSON(statusCode, gin.H{"error": errorMessage}) + response.Error(c, statusCode, errorMessage) return } @@ -385,7 +379,7 @@ func (h *TrackHandler) CompleteChunkedUpload(c *gin.Context) { statusCode := h.getErrorStatusCode(err) // Nettoyer le fichier assemblé os.Remove(finalPath) - c.JSON(statusCode, gin.H{"error": errorMessage}) + response.Error(c, statusCode, errorMessage) return } @@ -403,7 +397,7 @@ func (h *TrackHandler) CompleteChunkedUpload(c *gin.Context) { os.Remove(finalPath) errorMessage := h.mapTrackError(err) statusCode := h.getErrorStatusCode(err) - c.JSON(statusCode, gin.H{"error": errorMessage}) + response.Error(c, statusCode, errorMessage) return } @@ -422,7 +416,7 @@ func (h *TrackHandler) CompleteChunkedUpload(c *gin.Context) { } } - c.JSON(http.StatusCreated, gin.H{ + response.Created(c, gin.H{ "message": "upload completed successfully", "track": track, "md5": md5, @@ -527,14 +521,14 @@ func (h *TrackHandler) GetUploadQuota(c *gin.Context) { // Si "me" ou vide, utiliser l'utilisateur authentifié userID = c.MustGet("user_id").(uuid.UUID) if userID == uuid.Nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + response.Unauthorized(c, "unauthorized") return } } else { // Parse UUID userID, err = uuid.Parse(userIDParam) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid user id"}) + response.BadRequest(c, "invalid user id") return } } @@ -542,24 +536,24 @@ func (h *TrackHandler) GetUploadQuota(c *gin.Context) { // Vérifier que l'utilisateur peut accéder à ces informations (soit lui-même, soit admin) authenticatedUserID := c.MustGet("user_id").(uuid.UUID) if authenticatedUserID == uuid.Nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + response.Unauthorized(c, "unauthorized") return } // Un utilisateur ne peut voir que son propre quota (sauf admin, mais on simplifie pour l'instant) if authenticatedUserID != userID { - c.JSON(http.StatusForbidden, gin.H{"error": "forbidden: you can only view your own quota"}) + response.Forbidden(c, "forbidden: you can only view your own quota") return } // Récupérer le quota quota, err := h.trackService.GetUserQuota(c.Request.Context(), userID) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get quota"}) + response.InternalServerError(c, "failed to get quota") return } - c.JSON(http.StatusOK, gin.H{ + response.Success(c, gin.H{ "quota": quota, }) } @@ -578,30 +572,30 @@ func (h *TrackHandler) GetUploadQuota(c *gin.Context) { func (h *TrackHandler) ResumeUpload(c *gin.Context) { userID := c.MustGet("user_id").(uuid.UUID) if userID == uuid.Nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + response.Unauthorized(c, "unauthorized") return } uploadID := c.Param("uploadId") if uploadID == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "upload_id is required"}) + response.BadRequest(c, "upload_id is required") return } // Récupérer l'état de l'upload state, err := h.chunkService.GetUploadState(uploadID) if err != nil { - c.JSON(http.StatusNotFound, gin.H{"error": "upload not found"}) + response.NotFound(c, "upload not found") return } // Vérifier que l'upload appartient à l'utilisateur authentifié if state.UserID != userID { - c.JSON(http.StatusForbidden, gin.H{"error": "forbidden: you can only resume your own uploads"}) + response.Forbidden(c, "forbidden: you can only resume your own uploads") return } - c.JSON(http.StatusOK, gin.H{ + response.Success(c, gin.H{ "upload_id": state.UploadID, "user_id": state.UserID, "total_chunks": state.TotalChunks, @@ -679,7 +673,7 @@ func (h *TrackHandler) ListTracks(c *gin.Context) { // Appeler le service tracks, total, err := h.trackService.ListTracks(c.Request.Context(), params) if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to list tracks"}) + response.InternalServerError(c, "failed to list tracks") return } @@ -697,7 +691,7 @@ func (h *TrackHandler) ListTracks(c *gin.Context) { } } - c.JSON(http.StatusOK, gin.H{ + response.Success(c, gin.H{ "tracks": tracks, "pagination": gin.H{ "page": pageInt, @@ -722,24 +716,24 @@ func (h *TrackHandler) ListTracks(c *gin.Context) { func (h *TrackHandler) GetTrack(c *gin.Context) { trackIDStr := c.Param("id") if trackIDStr == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "track id is required"}) + response.BadRequest(c, "track id is required") return } // MIGRATION UUID: TrackID is UUID trackID, err := uuid.Parse(trackIDStr) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid track id"}) + response.BadRequest(c, "invalid track id") return } track, err := h.trackService.GetTrackByID(c.Request.Context(), trackID) if err != nil { if errors.Is(err, ErrTrackNotFound) || errors.Is(err, gorm.ErrRecordNotFound) { - c.JSON(http.StatusNotFound, gin.H{"error": "track not found"}) + response.NotFound(c, "track not found") return } - c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get track"}) + response.InternalServerError(c, "failed to get track") return } @@ -749,7 +743,7 @@ func (h *TrackHandler) GetTrack(c *gin.Context) { track.StreamManifestURL = "" } - c.JSON(http.StatusOK, gin.H{"track": track}) + response.Success(c, gin.H{"track": track}) } // UpdateTrackRequest représente la requête de mise à jour d'un track @@ -780,26 +774,26 @@ type UpdateTrackRequest struct { func (h *TrackHandler) UpdateTrack(c *gin.Context) { userID := c.MustGet("user_id").(uuid.UUID) if userID == uuid.Nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) + response.Unauthorized(c, "unauthorized") return } trackIDStr := c.Param("id") if trackIDStr == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "track id is required"}) + response.BadRequest(c, "track id is required") return } // MIGRATION UUID: TrackID is UUID trackID, err := uuid.Parse(trackIDStr) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid track id"}) + response.BadRequest(c, "invalid track id") return } var req UpdateTrackRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + response.BadRequest(c, err.Error()) return } @@ -816,23 +810,23 @@ func (h *TrackHandler) UpdateTrack(c *gin.Context) { track, err := h.trackService.UpdateTrack(c.Request.Context(), trackID, userID, params) if err != nil { if errors.Is(err, ErrTrackNotFound) || errors.Is(err, gorm.ErrRecordNotFound) { - c.JSON(http.StatusNotFound, gin.H{"error": "track not found"}) + response.NotFound(c, "track not found") return } if errors.Is(err, ErrForbidden) { - c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"}) + response.Forbidden(c, "forbidden") return } // Erreur de validation (title empty, year negative, etc.) if strings.Contains(err.Error(), "cannot be") { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + response.BadRequest(c, err.Error()) return } - c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update track"}) + response.InternalServerError(c, "failed to update track") return } - c.JSON(http.StatusOK, gin.H{"track": track}) + response.Success(c, gin.H{"track": track}) } // DeleteTrack gère la suppression d'un track @@ -864,25 +858,25 @@ func (h *TrackHandler) DeleteTrack(c *gin.Context) { // MIGRATION UUID: TrackID is UUID trackID, err := uuid.Parse(trackIDStr) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid track id"}) + response.BadRequest(c, "invalid track id") return } err = h.trackService.DeleteTrack(c.Request.Context(), trackID, userID) if err != nil { if errors.Is(err, ErrTrackNotFound) || errors.Is(err, gorm.ErrRecordNotFound) { - c.JSON(http.StatusNotFound, gin.H{"error": "track not found"}) + response.NotFound(c, "track not found") return } if errors.Is(err, ErrForbidden) { - c.JSON(http.StatusForbidden, gin.H{"error": "forbidden"}) + response.Forbidden(c, "forbidden") return } - c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete track"}) + response.InternalServerError(c, "failed to delete track") return } - c.JSON(http.StatusOK, gin.H{"message": "track deleted successfully"}) + response.Success(c, gin.H{"message": "track deleted successfully"}) } // BatchDeleteRequest représente la requête pour supprimer plusieurs tracks @@ -911,13 +905,13 @@ func (h *TrackHandler) BatchDeleteTracks(c *gin.Context) { var req BatchDeleteRequest if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + response.BadRequest(c, err.Error()) return } // Valider que la liste n'est pas vide if len(req.TrackIDs) == 0 { - c.JSON(http.StatusBadRequest, gin.H{"error": "track_ids cannot be empty"}) + response.BadRequest(c, "track_ids cannot be empty") return } @@ -933,14 +927,14 @@ func (h *TrackHandler) BatchDeleteTracks(c *gin.Context) { if err != nil { // Vérifier si c'est une erreur de taille de batch if strings.Contains(err.Error(), "batch size exceeds maximum") { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + response.BadRequest(c, err.Error()) return } - c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to delete tracks"}) + response.InternalServerError(c, "failed to delete tracks") return } - c.JSON(http.StatusOK, gin.H{ + response.Success(c, gin.H{ "deleted": result.Deleted, "failed": result.Failed, })