feat: Add player_configs feature and migrate user preferences
- Implemented player_configs table to store multiple player configurations per user. - Migrated existing player settings from user_preferences to player_configs. - Removed player-related columns from user_preferences. - Added referral state fields to user for tracking referral rewards. - Created migration scripts for database changes and data migration. - Added test cases for app services and usage helpers. - Introduced video job service interfaces and implementations.
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
"gorm.io/gorm"
|
||||
"stream.api/internal/database/model"
|
||||
appv1 "stream.api/internal/gen/proto/app/v1"
|
||||
"stream.api/internal/video"
|
||||
)
|
||||
|
||||
func (s *appServices) GetUploadUrl(ctx context.Context, req *appv1.GetUploadUrlRequest) (*appv1.GetUploadUrlResponse, error) {
|
||||
@@ -44,6 +45,9 @@ func (s *appServices) CreateVideo(ctx context.Context, req *appv1.CreateVideoReq
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if s.videoService == nil {
|
||||
return nil, status.Error(codes.Unavailable, "Job service is unavailable")
|
||||
}
|
||||
|
||||
title := strings.TrimSpace(req.GetTitle())
|
||||
if title == "" {
|
||||
@@ -53,41 +57,28 @@ func (s *appServices) CreateVideo(ctx context.Context, req *appv1.CreateVideoReq
|
||||
if videoURL == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "URL is required")
|
||||
}
|
||||
|
||||
statusValue := "ready"
|
||||
processingStatus := "READY"
|
||||
storageType := detectStorageType(videoURL)
|
||||
description := strings.TrimSpace(req.GetDescription())
|
||||
format := strings.TrimSpace(req.GetFormat())
|
||||
|
||||
video := &model.Video{
|
||||
ID: uuid.New().String(),
|
||||
UserID: result.UserID,
|
||||
Name: title,
|
||||
Title: title,
|
||||
Description: nullableTrimmedString(&description),
|
||||
URL: videoURL,
|
||||
Size: req.GetSize(),
|
||||
Duration: req.GetDuration(),
|
||||
Format: format,
|
||||
Status: &statusValue,
|
||||
ProcessingStatus: &processingStatus,
|
||||
StorageType: &storageType,
|
||||
}
|
||||
|
||||
if err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Create(video).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Model(&model.User{}).
|
||||
Where("id = ?", result.UserID).
|
||||
UpdateColumn("storage_used", gorm.Expr("storage_used + ?", video.Size)).Error
|
||||
}); err != nil {
|
||||
created, err := s.videoService.CreateVideo(ctx, video.CreateVideoInput{
|
||||
UserID: result.UserID,
|
||||
Title: title,
|
||||
Description: &description,
|
||||
URL: videoURL,
|
||||
Size: req.GetSize(),
|
||||
Duration: req.GetDuration(),
|
||||
Format: strings.TrimSpace(req.GetFormat()),
|
||||
})
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to create video", "error", err)
|
||||
return nil, status.Error(codes.Internal, "Failed to create video")
|
||||
switch {
|
||||
case errors.Is(err, video.ErrJobServiceUnavailable):
|
||||
return nil, status.Error(codes.Unavailable, "Job service is unavailable")
|
||||
default:
|
||||
return nil, status.Error(codes.Internal, "Failed to create video")
|
||||
}
|
||||
}
|
||||
|
||||
return &appv1.CreateVideoResponse{Video: toProtoVideo(video)}, nil
|
||||
return &appv1.CreateVideoResponse{Video: toProtoVideo(created.Video, created.Job.ID)}, nil
|
||||
}
|
||||
func (s *appServices) ListVideos(ctx context.Context, req *appv1.ListVideosRequest) (*appv1.ListVideosResponse, error) {
|
||||
result, err := s.authenticate(ctx)
|
||||
@@ -131,7 +122,12 @@ func (s *appServices) ListVideos(ctx context.Context, req *appv1.ListVideosReque
|
||||
|
||||
items := make([]*appv1.Video, 0, len(videos))
|
||||
for i := range videos {
|
||||
items = append(items, toProtoVideo(&videos[i]))
|
||||
payload, err := s.buildVideo(ctx, &videos[i])
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to build video payload", "error", err, "video_id", videos[i].ID)
|
||||
return nil, status.Error(codes.Internal, "Failed to fetch videos")
|
||||
}
|
||||
items = append(items, payload)
|
||||
}
|
||||
|
||||
return &appv1.ListVideosResponse{Videos: items, Total: total, Page: page, Limit: limit}, nil
|
||||
@@ -160,7 +156,12 @@ func (s *appServices) GetVideo(ctx context.Context, req *appv1.GetVideoRequest)
|
||||
return nil, status.Error(codes.Internal, "Failed to fetch video")
|
||||
}
|
||||
|
||||
return &appv1.GetVideoResponse{Video: toProtoVideo(&video)}, nil
|
||||
payload, err := s.buildVideo(ctx, &video)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to build video payload", "error", err, "video_id", video.ID)
|
||||
return nil, status.Error(codes.Internal, "Failed to fetch video")
|
||||
}
|
||||
return &appv1.GetVideoResponse{Video: payload}, nil
|
||||
}
|
||||
func (s *appServices) UpdateVideo(ctx context.Context, req *appv1.UpdateVideoRequest) (*appv1.UpdateVideoResponse, error) {
|
||||
result, err := s.authenticate(ctx)
|
||||
@@ -219,7 +220,12 @@ func (s *appServices) UpdateVideo(ctx context.Context, req *appv1.UpdateVideoReq
|
||||
return nil, status.Error(codes.Internal, "Failed to update video")
|
||||
}
|
||||
|
||||
return &appv1.UpdateVideoResponse{Video: toProtoVideo(&video)}, nil
|
||||
payload, err := s.buildVideo(ctx, &video)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to build video payload", "error", err, "video_id", video.ID)
|
||||
return nil, status.Error(codes.Internal, "Failed to update video")
|
||||
}
|
||||
return &appv1.UpdateVideoResponse{Video: payload}, nil
|
||||
}
|
||||
func (s *appServices) DeleteVideo(ctx context.Context, req *appv1.DeleteVideoRequest) (*appv1.MessageResponse, error) {
|
||||
result, err := s.authenticate(ctx)
|
||||
@@ -256,9 +262,6 @@ func (s *appServices) DeleteVideo(ctx context.Context, req *appv1.DeleteVideoReq
|
||||
}
|
||||
|
||||
if err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Where("video_id = ? AND user_id = ?", video.ID, result.UserID).Delete(&model.VideoAdConfig{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Where("id = ? AND user_id = ?", video.ID, result.UserID).Delete(&model.Video{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user