package feed import ( "net/http" "strconv" "github.com/gin-gonic/gin" apperrors "veza-backend-api/internal/errors" "veza-backend-api/internal/handlers" ) // Handler handles the chronological tracks feed (v0.10.0 F210) type Handler struct { service *Service } // NewHandler creates a new feed handler func NewHandler(service *Service) *Handler { return &Handler{service: service} } // GetTracksFeed returns tracks from followed users, chronological, cursor-paginated. // v0.10.1 F355: Adds by_genres section "Nouvelles sorties dans vos genres" when user follows genres. // GET /api/v1/feed?cursor=...&limit=20&by_genres_cursor=...&by_genres_limit=10 // Requires authentication. func (h *Handler) GetTracksFeed(c *gin.Context) { userID, ok := handlers.GetUserIDUUID(c) if !ok { return } limitStr := c.DefaultQuery("limit", "20") limit, err := strconv.Atoi(limitStr) if err != nil || limit < 1 || limit > 50 { handlers.RespondWithAppError(c, apperrors.NewValidationError("limit must be between 1 and 50")) return } cursor := c.Query("cursor") byGenresCursor := c.Query("by_genres_cursor") byGenresLimit := 10 if l, err := strconv.Atoi(c.DefaultQuery("by_genres_limit", "10")); err == nil && l > 0 && l <= 50 { byGenresLimit = l } tracks, nextCursor, err := h.service.GetTracksFeed(c.Request.Context(), userID, limit, cursor) if err != nil { handlers.RespondWithAppError(c, apperrors.NewInternalErrorWrap("failed to get feed", err)) return } resp := gin.H{"items": tracks} if nextCursor != "" { resp["next_cursor"] = nextCursor } // v0.10.1 F355: Section "Nouvelles sorties dans vos genres" if ds := h.service.GetDiscoverService(); ds != nil { byGenresTracks, byGenresNext, err := ds.GetTracksFromFollowedGenres(c.Request.Context(), userID, byGenresLimit, byGenresCursor) if err == nil { section := gin.H{"items": byGenresTracks} if byGenresNext != "" { section["next_cursor"] = byGenresNext } resp["by_genres"] = section } } handlers.RespondSuccess(c, http.StatusOK, resp) }