Aggiunge modulo Replay, Garage dev e YouTube a livello società.
Pipeline registrazione/upload con storage S3, archivio web e app, proxy replay per il browser, OAuth YouTube sulla pagina club (Premium Full) e footer legale. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
55
backend/app/controllers/public/club_recordings_controller.rb
Normal file
55
backend/app/controllers/public/club_recordings_controller.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
module Public
|
||||
class ClubRecordingsController < WebBaseController
|
||||
before_action :require_login!
|
||||
before_action :set_club
|
||||
before_action -> { require_club_owner!(@club) }
|
||||
before_action :set_recording, only: %i[update destroy publish_youtube]
|
||||
|
||||
def index
|
||||
@stats = Recordings::ClubStats.new(@club).call
|
||||
@recordings = Recording.for_club(@club)
|
||||
.not_deleted
|
||||
.includes(stream_session: { match: :team })
|
||||
.order(recorded_at: :desc, created_at: :desc)
|
||||
@teams = @club.teams.order(:name)
|
||||
end
|
||||
|
||||
def update
|
||||
privacy = params.require(:recording).permit(:privacy_status, :title)[:privacy_status]
|
||||
attrs = {}
|
||||
attrs[:privacy_status] = privacy if privacy.in?(Recording::PRIVACY_STATUSES)
|
||||
title = params.dig(:recording, :title)
|
||||
attrs[:title] = title if title.present?
|
||||
@recording.update!(attrs)
|
||||
redirect_to public_club_recordings_path(@club), notice: "Replay aggiornato"
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
redirect_to public_club_recordings_path(@club), alert: e.record.errors.full_messages.join(", ")
|
||||
end
|
||||
|
||||
def destroy
|
||||
Recordings::Delete.new(@recording).call
|
||||
redirect_to public_club_recordings_path(@club), notice: "Replay eliminato"
|
||||
end
|
||||
|
||||
def publish_youtube
|
||||
ent = @recording.team.entitlements
|
||||
unless ent.premium_full? && ent.youtube_enabled?
|
||||
redirect_to public_club_recordings_path(@club), alert: "Republicazione YouTube con Premium Full"
|
||||
return
|
||||
end
|
||||
|
||||
Recordings::PublishToYoutubeJob.perform_async(@recording.id)
|
||||
redirect_to public_club_recordings_path(@club), notice: "Pubblicazione su YouTube avviata"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_club
|
||||
@club = current_user.owned_clubs.find(params[:club_id])
|
||||
end
|
||||
|
||||
def set_recording
|
||||
@recording = Recording.for_club(@club).not_deleted.find(params[:id])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,7 +3,7 @@ module Public
|
||||
include BrandingAttachments
|
||||
|
||||
before_action :require_login!
|
||||
before_action :set_club, only: %i[show edit update billing checkout portal]
|
||||
before_action :set_club, only: %i[show edit update billing checkout portal youtube_connect youtube_disconnect]
|
||||
before_action :require_billing_profile_for_premium_checkout!, only: :checkout
|
||||
|
||||
def new
|
||||
@@ -54,6 +54,7 @@ module Public
|
||||
@entitlements_team = @club.teams.first
|
||||
@entitlements = @entitlements_team&.entitlements
|
||||
@teams = @club.teams.order(:name)
|
||||
@replay_stats = Recordings::ClubStats.new(@club).call if @entitlements&.can_access_recordings?
|
||||
end
|
||||
|
||||
def edit
|
||||
@@ -136,6 +137,33 @@ module Public
|
||||
redirect_to public_club_billing_path(@club), alert: "Errore Stripe: #{e.message}"
|
||||
end
|
||||
|
||||
def youtube_connect
|
||||
require_club_owner!(@club)
|
||||
entitlements = @club.teams.first!.entitlements
|
||||
entitlements.assert_can_connect_youtube!
|
||||
|
||||
if ENV["YOUTUBE_CLIENT_ID"].blank?
|
||||
redirect_to public_club_path(@club), alert: "YouTube OAuth non configurato sul server"
|
||||
return
|
||||
end
|
||||
|
||||
return_app = params[:return_app] == "1"
|
||||
state = Youtube::OauthState.for_club(
|
||||
club_id: @club.id,
|
||||
user_id: current_user.id,
|
||||
return_app: return_app
|
||||
)
|
||||
redirect_to Youtube::OauthUrl.build(state: state), allow_other_host: true
|
||||
rescue Teams::EntitlementError => e
|
||||
redirect_to public_club_path(@club), alert: e.message
|
||||
end
|
||||
|
||||
def youtube_disconnect
|
||||
require_club_owner!(@club)
|
||||
@club.youtube_credential&.destroy!
|
||||
redirect_to public_club_path(@club), notice: "Canale YouTube della società scollegato"
|
||||
end
|
||||
|
||||
def portal
|
||||
require_club_owner!(@club)
|
||||
unless MatchLiveTv.stripe_enabled?
|
||||
|
||||
@@ -2,14 +2,102 @@ module Public
|
||||
class ReplayController < SiteBaseController
|
||||
layout "marketing_live"
|
||||
|
||||
def show
|
||||
@session = StreamSession.includes(match: :team).find(params[:id])
|
||||
@recording = Recording.ready.find_by(stream_session: @session)
|
||||
@match = @session.match
|
||||
before_action :set_session_and_recording, only: %i[show stream thumbnail download]
|
||||
before_action :authorize_replay_access!, only: %i[show stream thumbnail download]
|
||||
|
||||
unless @recording
|
||||
redirect_to public_live_path(@session), alert: "Replay non disponibile"
|
||||
def index
|
||||
@query = params[:q].to_s.strip
|
||||
@recordings = Recording.ready.publicly_listed
|
||||
.includes(stream_session: { match: { team: :club } })
|
||||
.search_replays(@query)
|
||||
.order(recorded_at: :desc, created_at: :desc)
|
||||
.limit(100)
|
||||
if params[:club_id].present?
|
||||
@recordings = @recordings.joins(:team).where(teams: { club_id: params[:club_id] })
|
||||
end
|
||||
if params[:team_id].present?
|
||||
@recordings = @recordings.where(team_id: params[:team_id])
|
||||
end
|
||||
@clubs = Club.joins(teams: :recordings)
|
||||
.merge(Recording.ready.publicly_listed)
|
||||
.distinct
|
||||
.order(:name)
|
||||
@filter_club = @clubs.find { |c| c.id.to_s == params[:club_id].to_s } if params[:club_id].present?
|
||||
end
|
||||
|
||||
def show
|
||||
@match = @session.match
|
||||
end
|
||||
|
||||
def stream
|
||||
Recordings::IncrementViews.new(@recording).call
|
||||
serve_video(disposition: "inline")
|
||||
end
|
||||
|
||||
def thumbnail
|
||||
serve_thumbnail
|
||||
end
|
||||
|
||||
def download
|
||||
unless download_allowed?
|
||||
redirect_to public_replay_path(@session), alert: "Download non disponibile"
|
||||
return
|
||||
end
|
||||
|
||||
serve_video(disposition: "attachment")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def serve_video(disposition:)
|
||||
Recordings::ServeFromStorage.new(
|
||||
key: @recording.storage_key,
|
||||
content_type: "video/mp4",
|
||||
disposition: disposition,
|
||||
filename: disposition == "attachment" ? download_filename : nil
|
||||
).call(self)
|
||||
rescue ArgumentError
|
||||
head :not_found
|
||||
end
|
||||
|
||||
def serve_thumbnail
|
||||
key = @recording.thumbnail_storage_key
|
||||
return head :not_found if key.blank?
|
||||
|
||||
Recordings::ServeFromStorage.new(
|
||||
key: key,
|
||||
content_type: "image/jpeg",
|
||||
disposition: "inline"
|
||||
).call(self)
|
||||
rescue ArgumentError
|
||||
head :not_found
|
||||
end
|
||||
|
||||
def download_allowed?
|
||||
ent = @recording.team.entitlements
|
||||
return false unless ent.phone_download_enabled?
|
||||
|
||||
Recordings::AccessPolicy.new(@recording, viewer: current_user).allowed? ||
|
||||
Recordings::AccessPolicy.new(@recording, viewer: current_user).manage_allowed?
|
||||
end
|
||||
|
||||
def download_filename
|
||||
slug = @recording.title_or_default.parameterize.presence || "replay"
|
||||
"#{slug}.mp4"
|
||||
end
|
||||
|
||||
def set_session_and_recording
|
||||
@session = StreamSession.includes(match: { team: :club }).find(params[:id])
|
||||
@recording = Recording.not_deleted.find_by(stream_session: @session)
|
||||
return if @recording
|
||||
|
||||
redirect_to public_live_path(@session), alert: "Replay non disponibile"
|
||||
end
|
||||
|
||||
def authorize_replay_access!
|
||||
return if Recordings::AccessPolicy.new(@recording, viewer: current_user).allowed?
|
||||
|
||||
redirect_to public_live_index_path, alert: "Replay non disponibile"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -116,40 +116,20 @@ module Public
|
||||
end
|
||||
|
||||
def youtube_connect
|
||||
require_youtube_connect_access!(@team)
|
||||
@team.entitlements.assert_can_connect_youtube!
|
||||
|
||||
if ENV["YOUTUBE_CLIENT_ID"].blank?
|
||||
redirect_to public_team_details_path(@team), alert: "YouTube OAuth non configurato sul server"
|
||||
return
|
||||
end
|
||||
|
||||
return_app = params[:return_app] == "1"
|
||||
state = Youtube::OauthState.for_team(
|
||||
team_id: @team.id,
|
||||
user_id: current_user.id,
|
||||
return_app: return_app
|
||||
redirect_to public_club_youtube_connect_path(
|
||||
@team.club_id,
|
||||
return_app: params[:return_app]
|
||||
)
|
||||
redirect_to Youtube::OauthUrl.build(state: state), allow_other_host: true
|
||||
rescue Teams::EntitlementError => e
|
||||
redirect_to public_team_details_path(@team), alert: e.message
|
||||
end
|
||||
|
||||
def youtube_disconnect
|
||||
require_club_owner_for_team!(@team)
|
||||
@team.youtube_credential&.destroy!
|
||||
redirect_to public_team_details_path(@team), notice: "Canale YouTube scollegato"
|
||||
@team.club.youtube_credential&.destroy!
|
||||
redirect_to public_club_path(@team.club), notice: "Canale YouTube della società scollegato"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_youtube_connect_access!(team)
|
||||
return if team.club&.owned_by?(current_user)
|
||||
return if current_user.can_stream_for?(team)
|
||||
|
||||
redirect_to public_team_details_path(team), alert: "Accesso non consentito"
|
||||
end
|
||||
|
||||
def load_team_details!
|
||||
@club = @team.club
|
||||
@can_manage = @club.owned_by?(current_user)
|
||||
@@ -160,7 +140,11 @@ module Public
|
||||
category: params[:category].presence_in(TeamRosterMember::CATEGORIES) || "player"
|
||||
)
|
||||
end
|
||||
@recordings = @team.recordings.ready.includes(stream_session: :match).order(created_at: :desc).limit(10)
|
||||
@recordings = @team.recordings.not_deleted
|
||||
.where(status: %w[ready processing])
|
||||
.includes(stream_session: :match)
|
||||
.order(recorded_at: :desc, created_at: :desc)
|
||||
.limit(10)
|
||||
@owner_membership = current_user.user_teams.find_by(team: @team)
|
||||
@staff_memberships = @team.user_teams.includes(:user)
|
||||
.where("user_teams.role = 'member' OR (user_teams.staff_kind IS NOT NULL)")
|
||||
|
||||
Reference in New Issue
Block a user