package track import ( "net/http" "github.com/google/uuid" apperrors "veza-backend-api/internal/errors" "veza-backend-api/internal/handlers" "veza-backend-api/internal/services" "github.com/gin-gonic/gin" ) // TrackHandler gère les opérations sur les tracks type TrackHandler struct { trackService *TrackService trackUploadService *services.TrackUploadService chunkService *services.TrackChunkService likeService *services.TrackLikeService streamService *services.StreamService jobEnqueuer services.JobEnqueuer // Optional: for HLS transcoding via job queue searchService *services.TrackSearchService shareService *services.TrackShareService versionService *services.TrackVersionService historyService *services.TrackHistoryService playbackAnalyticsService *services.PlaybackAnalyticsService // BE-API-019: Added for play analytics permissionService *services.PermissionService // MOD-P1-003: Added for admin check uploadValidator *services.UploadValidator // MOD-P1-001: Added for ClamAV scan before persistence licenseChecker services.TrackDownloadLicenseChecker // A04: Verify paid track download rights notificationService *services.NotificationService // Phase 2.2: Optional, for like notifications trackRecommendationService *services.TrackRecommendationService waveformService *services.WaveformService repostService *services.TrackRepostService // v0.10.3 F203 } // NewTrackHandler crée un nouveau handler de tracks func NewTrackHandler( trackService *TrackService, trackUploadService *services.TrackUploadService, chunkService *services.TrackChunkService, likeService *services.TrackLikeService, streamService *services.StreamService, ) *TrackHandler { return &TrackHandler{ trackService: trackService, trackUploadService: trackUploadService, chunkService: chunkService, likeService: likeService, streamService: streamService, } } // SetUploadValidator définit le validateur d'upload (pour injection de dépendance) // MOD-P1-001: Added for ClamAV scan before persistence func (h *TrackHandler) SetUploadValidator(uploadValidator *services.UploadValidator) { h.uploadValidator = uploadValidator } // SetPermissionService définit le service de permissions (pour injection de dépendance) // MOD-P1-003: Added for admin check in ownership verification func (h *TrackHandler) SetPermissionService(permissionService *services.PermissionService) { h.permissionService = permissionService } // SetSearchService définit le service de recherche (pour injection de dépendance) func (h *TrackHandler) SetSearchService(searchService *services.TrackSearchService) { h.searchService = searchService } // SetShareService définit le service de partage (pour injection de dépendance) func (h *TrackHandler) SetShareService(shareService *services.TrackShareService) { h.shareService = shareService } // SetVersionService définit le service de versioning (pour injection de dépendance) func (h *TrackHandler) SetVersionService(versionService *services.TrackVersionService) { h.versionService = versionService } // SetHistoryService définit le service d'historique (pour injection de dépendance) func (h *TrackHandler) SetHistoryService(historyService *services.TrackHistoryService) { h.historyService = historyService } // SetPlaybackAnalyticsService définit le service d'analytics de lecture (pour injection de dépendance) // BE-API-019: Implement track play analytics endpoint func (h *TrackHandler) SetPlaybackAnalyticsService(analyticsService *services.PlaybackAnalyticsService) { h.playbackAnalyticsService = analyticsService } // SetLicenseChecker définit le vérificateur de licence pour les téléchargements de tracks payants (A04) func (h *TrackHandler) SetLicenseChecker(checker services.TrackDownloadLicenseChecker) { h.licenseChecker = checker } // SetJobEnqueuer définit le job enqueuer pour le transcoding HLS (optionnel) func (h *TrackHandler) SetJobEnqueuer(enqueuer services.JobEnqueuer) { h.jobEnqueuer = enqueuer } // SetNotificationService définit le service de notifications (Phase 2.2) func (h *TrackHandler) SetNotificationService(notificationService *services.NotificationService) { h.notificationService = notificationService } // SetTrackRecommendationService définit le service de recommandations func (h *TrackHandler) SetTrackRecommendationService(svc *services.TrackRecommendationService) { h.trackRecommendationService = svc } // SetWaveformService définit le service de waveform (S1-05) func (h *TrackHandler) SetWaveformService(svc *services.WaveformService) { h.waveformService = svc } // SetRepostService définit le service de reposts (v0.10.3 F203) func (h *TrackHandler) SetRepostService(svc *services.TrackRepostService) { h.repostService = svc } // getUserID récupère l'ID utilisateur du contexte de manière sécurisée (fail-secure) // MOD-P1-RES-003: Remplace c.MustGet() pour éviter les panics // Retourne false si user_id est absent ou invalide (répond déjà avec 401) func (h *TrackHandler) getUserID(c *gin.Context) (uuid.UUID, bool) { userIDInterface, exists := c.Get("user_id") if !exists { // MOD-P1-RES-001: Utiliser RespondWithAppError au lieu de response.Unauthorized handlers.RespondWithAppError(c, apperrors.NewUnauthorizedError("unauthorized")) return uuid.Nil, false } userID, ok := userIDInterface.(uuid.UUID) if !ok { // MOD-P1-RES-001: Utiliser RespondWithAppError au lieu de response.Unauthorized handlers.RespondWithAppError(c, apperrors.NewUnauthorizedError("unauthorized")) return uuid.Nil, false } if userID == uuid.Nil { // MOD-P1-RES-001: Utiliser RespondWithAppError au lieu de response.Unauthorized handlers.RespondWithAppError(c, apperrors.NewUnauthorizedError("unauthorized")) return uuid.Nil, false } return userID, true } // respondWithError est un helper pour migrer vers RespondWithAppError // MOD-P1-RES-001: Helper pour standardiser les réponses d'erreur func (h *TrackHandler) respondWithError(c *gin.Context, httpStatus int, message string) { var errCode apperrors.ErrorCode switch httpStatus { case http.StatusBadRequest: errCode = apperrors.ErrCodeValidation case http.StatusUnauthorized: errCode = apperrors.ErrCodeUnauthorized case http.StatusForbidden: errCode = apperrors.ErrCodeForbidden case http.StatusNotFound: errCode = apperrors.ErrCodeNotFound case http.StatusInternalServerError: errCode = apperrors.ErrCodeInternal default: errCode = apperrors.ErrCodeInternal } handlers.RespondWithAppError(c, apperrors.New(errCode, message)) }