package service import ( "context" "fmt" "tailly_clips/internal/domain" "tailly_clips/internal/repository" "time" ) type CommentService interface { CreateComment(ctx context.Context, clipID, userID int, content string) (*domain.ClipComment, error) GetClipComments(ctx context.Context, clipID, limit, offset int) ([]*domain.ClipComment, int, error) DeleteComment(ctx context.Context, commentID, userID int) error } type commentService struct { commentRepo repository.CommentRepository clipRepo repository.ClipRepository } func NewCommentService(commentRepo repository.CommentRepository, clipRepo repository.ClipRepository) CommentService { return &commentService{ commentRepo: commentRepo, clipRepo: clipRepo, } } func (s *commentService) CreateComment(ctx context.Context, clipID, userID int, content string) (*domain.ClipComment, error) { // Проверяем существование клипа if _, err := s.clipRepo.GetByID(ctx, clipID); err != nil { return nil, fmt.Errorf("clip not found: %w", err) } // Валидация контента if content == "" { return nil, fmt.Errorf("comment content cannot be empty") } if len(content) > 1000 { return nil, fmt.Errorf("comment content too long") } // Создаем комментарий comment := &domain.ClipComment{ ClipID: clipID, AuthorID: userID, Content: content, CreatedAt: time.Now(), UpdatedAt: time.Now(), } if err := s.commentRepo.Create(ctx, comment); err != nil { return nil, fmt.Errorf("failed to create comment: %w", err) } // Увеличиваем счетчик комментариев if err := s.clipRepo.IncrementCommentsCount(ctx, clipID); err != nil { // Откатываем создание комментария при ошибке s.commentRepo.Delete(ctx, comment.ID) return nil, fmt.Errorf("failed to increment comments count: %w", err) } return comment, nil } func (s *commentService) GetClipComments(ctx context.Context, clipID, limit, offset int) ([]*domain.ClipComment, int, error) { // Проверяем существование клипа if _, err := s.clipRepo.GetByID(ctx, clipID); err != nil { return nil, 0, fmt.Errorf("clip not found: %w", err) } comments, totalCount, err := s.commentRepo.GetByClipID(ctx, clipID, limit, offset) if err != nil { return nil, 0, fmt.Errorf("failed to get clip comments: %w", err) } return comments, totalCount, nil } func (s *commentService) DeleteComment(ctx context.Context, commentID, userID int) error { // Получаем комментарий для проверки прав comment, err := s.commentRepo.GetByID(ctx, commentID) if err != nil { return fmt.Errorf("failed to get comment: %w", err) } // Проверяем права доступа if comment.AuthorID != userID { return fmt.Errorf("user %d is not the author of comment %d", userID, commentID) } // Удаляем комментарий if err := s.commentRepo.Delete(ctx, commentID); err != nil { return fmt.Errorf("failed to delete comment: %w", err) } // Уменьшаем счетчик комментариев if err := s.clipRepo.DecrementCommentsCount(ctx, comment.ClipID); err != nil { return fmt.Errorf("failed to decrement comments count: %w", err) } return nil }