- F201: Commentaires avec timestamp cliquable, modération mots-clés - F202: Likes privés (compteur visible créateur uniquement) - F203: Reposts de tracks sur le profil, bouton Repost, onglet Reposts - F204: Notifications (commentaire, repost), pas de gamification Backend: migrations 127/128, comment_moderation_service, track_repost_service, GetTrackLikes/GetTrack masquent like_count pour non-créateurs Frontend: LikeButton isCreator, RepostButton, Reposts tab profil, timestamp seek
94 lines
2.7 KiB
Go
94 lines
2.7 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"veza-backend-api/internal/models"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// TrackRepostService handles track repost operations (v0.10.3 F203).
|
|
type TrackRepostService struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewTrackRepostService creates a new track repost service.
|
|
func NewTrackRepostService(db *gorm.DB) *TrackRepostService {
|
|
return &TrackRepostService{db: db}
|
|
}
|
|
|
|
// RepostTrack adds a repost of a track to the user's profile.
|
|
func (s *TrackRepostService) RepostTrack(ctx context.Context, userID, trackID uuid.UUID) error {
|
|
var track models.Track
|
|
if err := s.db.WithContext(ctx).First(&track, "id = ?", trackID).Error; err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
return fmt.Errorf("track not found")
|
|
}
|
|
return fmt.Errorf("failed to check track: %w", err)
|
|
}
|
|
|
|
repost := models.TrackRepost{
|
|
UserID: userID,
|
|
TrackID: trackID,
|
|
}
|
|
if err := s.db.WithContext(ctx).Where("user_id = ? AND track_id = ?", userID, trackID).FirstOrCreate(&repost).Error; err != nil {
|
|
return fmt.Errorf("failed to create repost: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UnrepostTrack removes a repost.
|
|
func (s *TrackRepostService) UnrepostTrack(ctx context.Context, userID, trackID uuid.UUID) error {
|
|
if err := s.db.WithContext(ctx).
|
|
Where("user_id = ? AND track_id = ?", userID, trackID).
|
|
Delete(&models.TrackRepost{}).Error; err != nil {
|
|
return fmt.Errorf("failed to delete repost: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IsReposted returns whether the user has reposted the track.
|
|
func (s *TrackRepostService) IsReposted(ctx context.Context, userID, trackID uuid.UUID) (bool, error) {
|
|
var count int64
|
|
err := s.db.WithContext(ctx).Model(&models.TrackRepost{}).
|
|
Where("user_id = ? AND track_id = ?", userID, trackID).
|
|
Count(&count).Error
|
|
if err != nil {
|
|
return false, fmt.Errorf("failed to check repost: %w", err)
|
|
}
|
|
return count > 0, nil
|
|
}
|
|
|
|
// GetUserRepostedTracks returns tracks reposted by the user, paginated.
|
|
func (s *TrackRepostService) GetUserRepostedTracks(ctx context.Context, userID uuid.UUID, limit, offset int) ([]models.Track, int64, error) {
|
|
var total int64
|
|
if err := s.db.WithContext(ctx).Model(&models.TrackRepost{}).
|
|
Where("user_id = ?", userID).
|
|
Count(&total).Error; err != nil {
|
|
return nil, 0, fmt.Errorf("failed to count reposts: %w", err)
|
|
}
|
|
|
|
var reposts []models.TrackRepost
|
|
if err := s.db.WithContext(ctx).
|
|
Where("user_id = ?", userID).
|
|
Order("created_at DESC").
|
|
Limit(limit).
|
|
Offset(offset).
|
|
Preload("Track").
|
|
Preload("Track.User").
|
|
Find(&reposts).Error; err != nil {
|
|
return nil, 0, fmt.Errorf("failed to get reposts: %w", err)
|
|
}
|
|
|
|
tracks := make([]models.Track, 0, len(reposts))
|
|
for _, r := range reposts {
|
|
if r.Track.ID != uuid.Nil {
|
|
tracks = append(tracks, r.Track)
|
|
}
|
|
}
|
|
return tracks, total, nil
|
|
}
|