Aggiunge i tornei con hub, pagina pubblica e tabellone per semifinali e finali.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-05 15:05:57 +02:00
co-authored by Cursor
parent d52434fb2e
commit a1f4c24a43
124 changed files with 6979 additions and 91 deletions
@@ -9,34 +9,23 @@ module Api
return render json: { valid: false, error: "Invito non valido o scaduto" }, status: :not_found
end
render json: {
valid: true,
email: invitation.email,
team_id: invitation.team_id,
team_name: invitation.team.name,
club_name: invitation.team.club.name,
staff_kind: invitation.staff_kind,
expires_at: invitation.expires_at
}
render json: invitation_json(invitation).merge(valid: true)
end
def accept
invitation = find_pending_invitation
return render json: { error: "Invito non valido o scaduto" }, status: :not_found unless invitation
if current_user.email.downcase != invitation.email.downcase
email = invitation.email
if current_user.email.downcase != email.downcase
return render json: {
error: "Questo invito è per #{invitation.email}. Accedi con quell'indirizzo email.",
invited_email: invitation.email
error: "Questo invito è per #{email}. Accedi con quell'indirizzo email.",
invited_email: email
}, status: :unprocessable_entity
end
invitation.accept!(current_user)
render json: {
team_id: invitation.team_id,
team_name: invitation.team.name,
message: "Sei entrato in #{invitation.team.name} come responsabile trasmissione."
}
render json: invitation_json(invitation).merge(message: accept_message(invitation))
end
private
@@ -45,7 +34,42 @@ module Api
token = params[:token].to_s
return nil if token.blank?
TeamInvitation.pending.find_by(token_digest: Digest::SHA256.hexdigest(token))
digest = Digest::SHA256.hexdigest(token)
TeamInvitation.pending.find_by(token_digest: digest) ||
TournamentBroadcastInvitation.pending.find_by(token_digest: digest)
end
def invitation_json(invitation)
if invitation.is_a?(TournamentBroadcastInvitation)
tournament = invitation.tournament
{
email: invitation.email,
tournament_id: tournament.id,
tournament_name: tournament.name,
club_name: tournament.club.name,
team_id: tournament.broadcast_team_id,
team_name: tournament.name,
staff_kind: "transmission",
expires_at: invitation.expires_at
}
else
{
email: invitation.email,
team_id: invitation.team_id,
team_name: invitation.team.name,
club_name: invitation.team.club.name,
staff_kind: invitation.staff_kind,
expires_at: invitation.expires_at
}
end
end
def accept_message(invitation)
if invitation.is_a?(TournamentBroadcastInvitation)
"Sei incaricato delle dirette per #{invitation.tournament.name}."
else
"Sei entrato in #{invitation.team.name} come responsabile trasmissione."
end
end
end
end
@@ -10,13 +10,22 @@ module Api
def index
matches = @team.matches
.includes(:team, :stream_sessions)
.includes(:team, :stream_sessions, :home_participant, :away_participant)
.order(Arel.sql("scheduled_at ASC NULLS LAST"), created_at: :desc)
.select(&:coach_hub_visible?)
render json: matches.map { |m| match_json(m) }
unless current_user.club_admin?(@team.club)
if @team.tournament_broadcast?
assigned_ids = current_user.tournament_broadcast_assignments.select(:match_id)
matches = matches.where(id: assigned_ids)
end
end
render json: matches.select(&:coach_hub_visible?).map { |m| match_json(m) }
end
def create
if @team.tournament_broadcast?
return render json: { error: "Le partite del torneo si programmano dal sito web." }, status: :unprocessable_entity
end
attrs = match_params.to_h
attrs["sport_key"] = @team.sport_key
normalize_scoring_rules!(attrs)
@@ -112,9 +121,12 @@ module Api
{
id: match.id,
team_id: match.team_id,
team_name: team.name,
opponent_name: match.opponent_name,
location: match.location,
team_name: match.home_display_name,
opponent_name: match.away_display_name,
location: match.court_or_location,
court: match.court,
tournament_id: match.tournament_id,
tournament_name: match.tournament&.name,
scheduled_at: match.scheduled_at,
sport: match.sport_key,
sport_key: match.sport_key,
@@ -126,11 +138,11 @@ module Api
scoring_rules: match.scoring_rules.presence,
effective_scoring_rules: match.effective_scoring_rules,
category: match.category,
home_primary_color: team.effective_primary_color,
home_secondary_color: team.effective_secondary_color,
home_logo_url: api_absolute_url(team.effective_logo_url),
opponent_primary_color: match.effective_opponent_primary_color,
opponent_logo_url: api_absolute_url(match.opponent_logo_url),
home_primary_color: match.home_participant&.effective_primary_color || team.effective_primary_color,
home_secondary_color: match.home_participant&.effective_secondary_color || team.effective_secondary_color,
home_logo_url: api_absolute_url(match.home_participant&.effective_logo_url || team.effective_logo_url),
opponent_primary_color: match.away_participant&.effective_primary_color || match.effective_opponent_primary_color,
opponent_logo_url: api_absolute_url(match.away_participant&.effective_logo_url || match.opponent_logo_url),
**match_cover_json(match),
active_session_id: active&.id,
active_session_status: active&.status,
@@ -6,6 +6,10 @@ module Api
def create
team_ids = current_user.streamable_teams.map(&:id)
match = Match.where(team_id: team_ids).find(params[:match_id])
unless current_user.can_broadcast_match?(match)
return render json: { error: "Non sei incaricato di trasmettere questa partita" }, status: :forbidden
end
session = Sessions::Create.new(user: current_user, match: match, params: session_params).call
render json: session_json(session), status: :created
end
@@ -110,6 +110,9 @@ module Api
secondary_color: team.effective_secondary_color,
club_id: team.club_id,
club_name: team.club.name,
tournament_broadcast: team.tournament_broadcast?,
tournament_id: team.broadcast_tournament&.id,
tournament_name: team.broadcast_tournament&.name,
youtube_connected: yt.connected?,
youtube_selectable: yt.selectable?,
youtube_channel_title: yt.channel_title,