veza/veza-backend-api/internal/services/track_history_service.go
2026-03-05 23:03:43 +01:00

203 lines
5.9 KiB
Go

package services
import (
"context"
"encoding/json"
"errors"
"fmt"
"veza-backend-api/internal/models"
"github.com/google/uuid"
"go.uber.org/zap"
"gorm.io/gorm"
)
// TrackHistoryService gère l'historique des modifications de tracks
type TrackHistoryService struct {
db *gorm.DB
logger *zap.Logger
}
// NewTrackHistoryService crée un nouveau service d'historique de tracks
func NewTrackHistoryService(db *gorm.DB, logger *zap.Logger) *TrackHistoryService {
if logger == nil {
logger = zap.NewNop()
}
return &TrackHistoryService{
db: db,
logger: logger,
}
}
// RecordHistoryParams représente les paramètres pour enregistrer un historique
// MIGRATION UUID: UserID et TrackID en UUID
type RecordHistoryParams struct {
TrackID uuid.UUID
UserID uuid.UUID
Action models.TrackHistoryAction
OldValue interface{} // Peut être n'importe quel type, sera sérialisé en JSON
NewValue interface{} // Peut être n'importe quel type, sera sérialisé en JSON
}
// RecordHistory enregistre une entrée dans l'historique d'un track
func (s *TrackHistoryService) RecordHistory(ctx context.Context, params RecordHistoryParams) (*models.TrackHistory, error) {
// Vérifier que le track existe
var track models.Track
if err := s.db.WithContext(ctx).First(&track, "id = ?", params.TrackID).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, ErrTrackNotFound
}
return nil, fmt.Errorf("failed to get track: %w", err)
}
// Sérialiser old_value et new_value en JSON si nécessaire
var oldValueStr string
var newValueStr string
if params.OldValue != nil {
oldValueBytes, err := json.Marshal(params.OldValue)
if err != nil {
return nil, fmt.Errorf("failed to marshal old_value: %w", err)
}
oldValueStr = string(oldValueBytes)
}
if params.NewValue != nil {
newValueBytes, err := json.Marshal(params.NewValue)
if err != nil {
return nil, fmt.Errorf("failed to marshal new_value: %w", err)
}
newValueStr = string(newValueBytes)
}
// Créer l'entrée d'historique (TrackHistory utilise UUID)
history := &models.TrackHistory{
TrackID: params.TrackID,
UserID: params.UserID,
Action: params.Action,
OldValue: oldValueStr,
NewValue: newValueStr,
}
if err := s.db.WithContext(ctx).Create(history).Error; err != nil {
return nil, fmt.Errorf("failed to create track history: %w", err)
}
s.logger.Info("Track history recorded",
zap.String("track_id", params.TrackID.String()),
zap.String("user_id", params.UserID.String()),
zap.String("action", string(params.Action)),
zap.String("history_id", history.ID.String()),
)
return history, nil
}
// GetHistory récupère l'historique d'un track
func (s *TrackHistoryService) GetHistory(ctx context.Context, trackID uuid.UUID, limit, offset int) ([]models.TrackHistory, int64, error) {
// Vérifier que le track existe
var track models.Track
if err := s.db.WithContext(ctx).First(&track, "id = ?", trackID).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, 0, ErrTrackNotFound
}
return nil, 0, fmt.Errorf("failed to get track: %w", err)
}
// Compter le total d'entrées
var total int64
if err := s.db.WithContext(ctx).Model(&models.TrackHistory{}).
Where("track_id = ?", trackID).
Count(&total).Error; err != nil {
return nil, 0, fmt.Errorf("failed to count track history: %w", err)
}
// Récupérer les entrées avec pagination
var histories []models.TrackHistory
query := s.db.WithContext(ctx).
Where("track_id = ?", trackID).
Order("created_at DESC")
if limit > 0 {
query = query.Limit(limit)
}
if offset > 0 {
query = query.Offset(offset)
}
if err := query.Find(&histories).Error; err != nil {
return nil, 0, fmt.Errorf("failed to get track history: %w", err)
}
return histories, total, nil
}
// GetHistoryByUser récupère l'historique des tracks modifiés par un utilisateur
func (s *TrackHistoryService) GetHistoryByUser(ctx context.Context, userID uuid.UUID, limit, offset int) ([]models.TrackHistory, int64, error) {
// Compter le total d'entrées
var total int64
if err := s.db.WithContext(ctx).Model(&models.TrackHistory{}).
Where("user_id = ?", userID).
Count(&total).Error; err != nil {
return nil, 0, fmt.Errorf("failed to count user track history: %w", err)
}
// Récupérer les entrées avec pagination
var histories []models.TrackHistory
query := s.db.WithContext(ctx).
Where("user_id = ?", userID).
Order("created_at DESC")
if limit > 0 {
query = query.Limit(limit)
}
if offset > 0 {
query = query.Offset(offset)
}
if err := query.Find(&histories).Error; err != nil {
return nil, 0, fmt.Errorf("failed to get user track history: %w", err)
}
return histories, total, nil
}
// GetHistoryByAction récupère l'historique filtré par action
func (s *TrackHistoryService) GetHistoryByAction(ctx context.Context, trackID uuid.UUID, action models.TrackHistoryAction, limit, offset int) ([]models.TrackHistory, int64, error) {
// Vérifier que le track existe
var track models.Track
if err := s.db.WithContext(ctx).First(&track, "id = ?", trackID).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, 0, ErrTrackNotFound
}
return nil, 0, fmt.Errorf("failed to get track: %w", err)
}
// Compter le total d'entrées
var total int64
if err := s.db.WithContext(ctx).Model(&models.TrackHistory{}).
Where("track_id = ? AND action = ?", trackID, action).
Count(&total).Error; err != nil {
return nil, 0, fmt.Errorf("failed to count track history by action: %w", err)
}
// Récupérer les entrées avec pagination
var histories []models.TrackHistory
query := s.db.WithContext(ctx).
Where("track_id = ? AND action = ?", trackID, action).
Order("created_at DESC")
if limit > 0 {
query = query.Limit(limit)
}
if offset > 0 {
query = query.Offset(offset)
}
if err := query.Find(&histories).Error; err != nil {
return nil, 0, fmt.Errorf("failed to get track history by action: %w", err)
}
return histories, total, nil
}