veza/veza-backend-api/internal/services/track_like_service.go
2025-12-03 20:29:37 +01:00

172 lines
5.7 KiB
Go

package services
import (
"context"
"fmt"
"github.com/google/uuid"
"go.uber.org/zap"
"gorm.io/gorm"
"veza-backend-api/internal/models"
)
// TrackLikeService gère les opérations sur les likes de tracks
type TrackLikeService struct {
db *gorm.DB
logger *zap.Logger
}
// NewTrackLikeService crée un nouveau service de likes de tracks
func NewTrackLikeService(db *gorm.DB, logger *zap.Logger) *TrackLikeService {
if logger == nil {
logger = zap.NewNop()
}
return &TrackLikeService{
db: db,
logger: logger,
}
}
// LikeTrack ajoute un like d'un utilisateur sur un track
// MIGRATION UUID: userID migré vers uuid.UUID, trackID reste int64 - Corrected: trackID est maintenant uuid.UUID
func (s *TrackLikeService) LikeTrack(ctx context.Context, userID uuid.UUID, trackID uuid.UUID) error { // Changed trackID to uuid.UUID
// Vérifier si le track existe
var track models.Track
if err := s.db.WithContext(ctx).First(&track, "id = ?", trackID).Error; err != nil { // Updated query
if err == gorm.ErrRecordNotFound {
return fmt.Errorf("track not found")
}
return fmt.Errorf("failed to check track: %w", err)
}
// Vérifier si l'utilisateur a déjà liké ce track
var existing models.TrackLike
if err := s.db.WithContext(ctx).Where("user_id = ? AND track_id = ?", userID, trackID).First(&existing).Error; err == nil {
// Déjà liké, retourner nil (idempotent)
return nil
} else if err != gorm.ErrRecordNotFound {
return fmt.Errorf("failed to check existing like: %w", err)
}
// Créer le like
like := models.TrackLike{
UserID: userID,
TrackID: trackID,
}
if err := s.db.WithContext(ctx).Create(&like).Error; err != nil {
return fmt.Errorf("failed to create like: %w", err)
}
// Mettre à jour le compteur de likes du track
if err := s.db.WithContext(ctx).Model(&track).UpdateColumn("like_count", gorm.Expr("like_count + ?", 1)).Error; err != nil {
s.logger.Warn("Failed to update track like_count",
zap.Any("track_id", trackID), // Changed to zap.Any for uuid.UUID
zap.Error(err),
)
// Ne pas retourner l'erreur, le like a été créé avec succès
}
s.logger.Info("Track liked",
zap.String("user_id", userID.String()),
zap.Any("track_id", trackID), // Changed to zap.Any for uuid.UUID
)
return nil
}
// UnlikeTrack supprime un like d'un utilisateur sur un track
// MIGRATION UUID: userID migré vers uuid.UUID, trackID reste int64 - Corrected: trackID est maintenant uuid.UUID
func (s *TrackLikeService) UnlikeTrack(ctx context.Context, userID uuid.UUID, trackID uuid.UUID) error { // Changed trackID to uuid.UUID
// Vérifier si le like existe
var like models.TrackLike
if err := s.db.WithContext(ctx).Where("user_id = ? AND track_id = ?", userID, trackID).First(&like).Error; err != nil {
if err == gorm.ErrRecordNotFound {
// Pas de like à supprimer, retourner nil (idempotent)
return nil
}
return fmt.Errorf("failed to check like: %w", err)
}
// Supprimer le like
if err := s.db.WithContext(ctx).Delete(&like).Error; err != nil {
return fmt.Errorf("failed to delete like: %w", err)
}
// Mettre à jour le compteur de likes du track
var track models.Track
if err := s.db.WithContext(ctx).First(&track, "id = ?", trackID).Error; err == nil { // Updated query
if err := s.db.WithContext(ctx).Model(&track).UpdateColumn("like_count", gorm.Expr("GREATEST(like_count - 1, 0)")).Error; err != nil {
s.logger.Warn("Failed to update track like_count",
zap.Any("track_id", trackID), // Changed to zap.Any for uuid.UUID
zap.Error(err),
)
// Ne pas retourner l'erreur, le like a été supprimé avec succès
}
}
s.logger.Info("Track unliked",
zap.String("user_id", userID.String()),
zap.Any("track_id", trackID), // Changed to zap.Any for uuid.UUID
)
return nil
}
// IsLiked vérifie si un utilisateur a liké un track
func (s *TrackLikeService) IsLiked(ctx context.Context, userID uuid.UUID, trackID uuid.UUID) (bool, error) { // Changed trackID to uuid.UUID
var count int64
err := s.db.WithContext(ctx).Model(&models.TrackLike{}).
Where("user_id = ? AND track_id = ?", userID, trackID).
Count(&count).Error
if err != nil {
return false, fmt.Errorf("failed to check like: %w", err)
}
return count > 0, nil
}
// GetTrackLikesCount retourne le nombre de likes d'un track
func (s *TrackLikeService) GetTrackLikesCount(ctx context.Context, trackID uuid.UUID) (int64, error) { // Changed trackID to uuid.UUID
var count int64
err := s.db.WithContext(ctx).Model(&models.TrackLike{}).
Where("track_id = ?", trackID).
Count(&count).Error
if err != nil {
return 0, fmt.Errorf("failed to get likes count: %w", err)
}
return count, nil
}
// GetUserLikedTracks retourne la liste des tracks likés par un utilisateur
func (s *TrackLikeService) GetUserLikedTracks(ctx context.Context, userID uuid.UUID, limit, offset int) ([]models.Track, error) {
var tracks []models.Track
query := s.db.WithContext(ctx).
Joins("INNER JOIN track_likes ON tracks.id = track_likes.track_id").
Where("track_likes.user_id = ?", userID).
Order("track_likes.created_at DESC")
if limit > 0 {
query = query.Limit(limit)
}
if offset > 0 {
query = query.Offset(offset)
}
if err := query.Find(&tracks).Error; err != nil {
return nil, fmt.Errorf("failed to get user liked tracks: %w", err)
}
return tracks, nil
}
// GetUserLikedTracksCount retourne le nombre total de tracks likés par un utilisateur
func (s *TrackLikeService) GetUserLikedTracksCount(ctx context.Context, userID uuid.UUID) (int64, error) {
var count int64
err := s.db.WithContext(ctx).Model(&models.TrackLike{}).
Where("user_id = ?", userID).
Count(&count).Error
if err != nil {
return 0, fmt.Errorf("failed to get user liked tracks count: %w", err)
}
return count, nil
}