Corregge validazione upload copertina e generazione slate al go-live.
Rifiuta file troppo grandi o non-immagine via Marcel prima di attach, e genera la slate in sync anche quando cover_image esiste ma cover_slate non è ancora pronta. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,6 +2,7 @@ module Api
|
||||
module V1
|
||||
class BaseController < ApplicationController
|
||||
rescue_from Teams::EntitlementError, with: :render_entitlement_error
|
||||
rescue_from BrandingAttachments::CoverUploadError, with: :render_cover_upload_error
|
||||
rescue_from Youtube::BroadcastService::Error, with: :render_youtube_error
|
||||
|
||||
private
|
||||
@@ -20,6 +21,10 @@ module Api
|
||||
billing_url: error.billing_url
|
||||
}, status: :forbidden
|
||||
end
|
||||
|
||||
def render_cover_upload_error(error)
|
||||
render json: { error: error.message, error_code: "cover_upload_invalid" }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,10 +20,32 @@ module BrandingAttachments
|
||||
return if file.blank?
|
||||
|
||||
entitlements.assert_can_upload_cover!
|
||||
validate_cover_file!(file)
|
||||
record.cover_slate.purge if record.cover_slate.attached?
|
||||
record.cover_image.attach(file)
|
||||
end
|
||||
|
||||
def validate_cover_file!(file)
|
||||
allowed_types = Coverable::COVER_IMAGE_TYPES
|
||||
|
||||
# Rileva MIME dal contenuto (magic bytes) ignorando il declared_type del client.
|
||||
io = file.respond_to?(:tempfile) ? file.tempfile : file
|
||||
io.rewind if io.respond_to?(:rewind)
|
||||
detected = Marcel::MimeType.for(io, name: file.respond_to?(:original_filename) ? file.original_filename : nil)
|
||||
io.rewind if io.respond_to?(:rewind)
|
||||
|
||||
unless detected.in?(allowed_types)
|
||||
raise CoverUploadError, I18n.t("coverable.errors.invalid_type")
|
||||
end
|
||||
|
||||
byte_size = file.respond_to?(:size) ? file.size : File.size(file.path)
|
||||
if byte_size > Coverable::MAX_COVER_BYTES
|
||||
raise CoverUploadError, I18n.t("coverable.errors.too_large")
|
||||
end
|
||||
end
|
||||
|
||||
class CoverUploadError < StandardError; end
|
||||
|
||||
def enqueue_cover_slate_generation(record)
|
||||
GenerateCoverSlateJob.enqueue_for(record) if record.cover_image.attached?
|
||||
end
|
||||
|
||||
@@ -80,7 +80,7 @@ module Public
|
||||
@entitlements = @club.teams.first&.entitlements
|
||||
flash.now[:alert] = e.record.errors.full_messages.join(", ")
|
||||
render :edit, status: :unprocessable_entity
|
||||
rescue Teams::EntitlementError => e
|
||||
rescue Teams::EntitlementError, BrandingAttachments::CoverUploadError => e
|
||||
@entitlements = @club.teams.first&.entitlements
|
||||
flash.now[:alert] = e.message
|
||||
render :edit, status: :unprocessable_entity
|
||||
|
||||
@@ -59,7 +59,7 @@ module Public
|
||||
@entitlements = @team.entitlements
|
||||
flash.now[:alert] = e.record.errors.full_messages.join(", ")
|
||||
render :edit, status: :unprocessable_entity
|
||||
rescue Teams::EntitlementError => e
|
||||
rescue Teams::EntitlementError, BrandingAttachments::CoverUploadError => e
|
||||
@club = @team.club
|
||||
@entitlements = @team.entitlements
|
||||
flash.now[:alert] = e.message
|
||||
|
||||
@@ -8,8 +8,8 @@ module Coverable
|
||||
has_one_attached :cover_image
|
||||
has_one_attached :cover_slate
|
||||
|
||||
validate :cover_image_file_type, if: -> { cover_image.attached? && cover_image.blob&.new_record? }
|
||||
validate :cover_image_file_size, if: -> { cover_image.attached? && cover_image.blob&.new_record? }
|
||||
validate :cover_image_file_type, if: -> { cover_image.attached? }
|
||||
validate :cover_image_file_size, if: -> { cover_image.attached? }
|
||||
end
|
||||
|
||||
def cover_image_attached?
|
||||
|
||||
@@ -41,6 +41,17 @@ module Streams
|
||||
nil
|
||||
end
|
||||
|
||||
# Restituisce il record con cover_image nella catena anche se la slate non è ancora su disco.
|
||||
# Usato da CoverSlateEnsurer per sapere cosa generare al go-live.
|
||||
def pending_cover_record
|
||||
return nil unless @entitlements.can_use_custom_cover?
|
||||
|
||||
candidates.each do |record, _source|
|
||||
return record if record.cover_image.attached?
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def default_cover_url
|
||||
DEFAULT_COVER_URL
|
||||
end
|
||||
|
||||
@@ -11,10 +11,8 @@ module Streams
|
||||
end
|
||||
|
||||
def ensure!
|
||||
result = @resolver.resolve
|
||||
return unless result
|
||||
|
||||
record = result.record
|
||||
record = find_pending_cover_record
|
||||
return unless record
|
||||
return if slate_ready?(record)
|
||||
|
||||
GenerateCoverSlate.call(record)
|
||||
@@ -25,6 +23,12 @@ module Streams
|
||||
|
||||
private
|
||||
|
||||
# Cerca il record con cover_image nella catena di ereditarietà,
|
||||
# anche se la slate non è ancora pronta (a differenza di resolve che richiede la slate su disco).
|
||||
def find_pending_cover_record
|
||||
@resolver.pending_cover_record
|
||||
end
|
||||
|
||||
def slate_ready?(record)
|
||||
return false unless record.cover_slate.attached?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user