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

131 lines
No EOL
3.8 KiB
Go

package services
import (
"context"
"errors"
"fmt"
"github.com/google/uuid"
"go.uber.org/zap"
"veza-backend-api/internal/models"
)
// PlaylistDuplicateService gère la duplication de playlists
// T0495: Create Playlist Duplicate Feature
type PlaylistDuplicateService struct {
playlistService *PlaylistService
logger *zap.Logger
}
// NewPlaylistDuplicateService crée un nouveau service de duplication de playlists
func NewPlaylistDuplicateService(playlistService *PlaylistService, logger *zap.Logger) *PlaylistDuplicateService {
if logger == nil {
logger = zap.NewNop()
}
return &PlaylistDuplicateService{
playlistService: playlistService,
logger: logger,
}
}
// DuplicatePlaylistRequest représente la requête de duplication
type DuplicatePlaylistRequest struct {
NewTitle string `json:"new_title"`
NewDescription string `json:"new_description,omitempty"`
IsPublic *bool `json:"is_public,omitempty"`
}
// DuplicatePlaylist duplique une playlist avec tous ses tracks
// T0495: Create Playlist Duplicate Feature
// MIGRATION UUID: Completée. playlistID et userID sont des UUIDs.
func (s *PlaylistDuplicateService) DuplicatePlaylist(
ctx context.Context,
playlistID uuid.UUID,
userID uuid.UUID,
request DuplicatePlaylistRequest,
) (*models.Playlist, error) {
// Récupérer la playlist originale
userIDPtr := &userID
originalPlaylist, err := s.playlistService.GetPlaylist(ctx, playlistID, userIDPtr)
if err != nil {
if err.Error() == "playlist not found" {
return nil, errors.New("playlist not found")
}
return nil, fmt.Errorf("failed to get playlist: %w", err)
}
// Vérifier que l'utilisateur a accès à la playlist (propriétaire, collaborateur ou publique)
if originalPlaylist.UserID != userID && !originalPlaylist.IsPublic {
// Vérifier si l'utilisateur est collaborateur
hasAccess, err := s.playlistService.CheckPermission(ctx, playlistID, userID, models.PlaylistPermissionRead)
if err != nil || !hasAccess {
return nil, errors.New("forbidden: you don't have access to this playlist")
}
}
// Déterminer le titre de la nouvelle playlist
newTitle := request.NewTitle
if newTitle == "" {
newTitle = originalPlaylist.Title + " (Copy)"
}
// Déterminer la description
newDescription := request.NewDescription
if newDescription == "" {
newDescription = originalPlaylist.Description
}
// Déterminer si la playlist est publique
isPublic := originalPlaylist.IsPublic
if request.IsPublic != nil {
isPublic = *request.IsPublic
}
// Créer la nouvelle playlist
newPlaylist, err := s.playlistService.CreatePlaylist(
ctx,
userID,
newTitle,
newDescription,
isPublic,
)
if err != nil {
return nil, fmt.Errorf("failed to create duplicate playlist: %w", err)
}
// Dupliquer les tracks
if originalPlaylist.Tracks != nil && len(originalPlaylist.Tracks) > 0 {
for _, playlistTrack := range originalPlaylist.Tracks {
// Track est un struct (non-pointeur), toujours valide
{
// Ajouter le track à la nouvelle playlist avec la même position
err := s.playlistService.AddTrackToPlaylist(
ctx,
newPlaylist.ID,
playlistTrack.Track.ID,
userID,
playlistTrack.Position,
)
if err != nil {
// Log l'erreur mais continue avec les autres tracks
s.logger.Warn("Failed to add track to duplicated playlist",
zap.String("playlist_id", newPlaylist.ID.String()),
zap.String("track_id", playlistTrack.Track.ID.String()),
zap.Error(err),
)
// On continue avec les autres tracks plutôt que d'échouer complètement
continue
}
}
}
}
s.logger.Info("Playlist duplicated",
zap.String("original_playlist_id", playlistID.String()),
zap.String("new_playlist_id", newPlaylist.ID.String()),
zap.String("user_id", userID.String()),
zap.Int("tracks_count", len(originalPlaylist.Tracks)),
)
return newPlaylist, nil
}