Billing upgrade/downgrade, inviti in app e diretta YouTube da mobile.
Upgrade Stripe con addebito immediato; downgrade programmato a fine periodo. UX billing più sobria con box info; icone piani. API inviti e OAuth YouTube per staff trasmissione; deep link join; scelta partita programmata o nuova. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
52
backend/app/controllers/api/v1/invitations_controller.rb
Normal file
52
backend/app/controllers/api/v1/invitations_controller.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
module Api
|
||||
module V1
|
||||
class InvitationsController < BaseController
|
||||
skip_before_action :authenticate_request!, only: :show
|
||||
|
||||
def show
|
||||
invitation = find_pending_invitation
|
||||
unless invitation
|
||||
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
|
||||
}
|
||||
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
|
||||
return render json: {
|
||||
error: "Questo invito è per #{invitation.email}. Accedi con quell'indirizzo email.",
|
||||
invited_email: invitation.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."
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_pending_invitation
|
||||
token = params[:token].to_s
|
||||
return nil if token.blank?
|
||||
|
||||
TeamInvitation.pending.find_by(token_digest: Digest::SHA256.hexdigest(token))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -103,7 +103,8 @@ module Api
|
||||
youtube_enabled: ent.youtube_enabled?,
|
||||
youtube_mode: ent.plan.youtube_mode,
|
||||
staff_role: current_user.staff_role_for(team),
|
||||
can_stream: current_user.can_stream_for?(team)
|
||||
can_stream: current_user.can_stream_for?(team),
|
||||
can_connect_youtube: current_user.can_stream_for?(team) && ent.premium_full? && ent.youtube_enabled?
|
||||
}
|
||||
if detail
|
||||
data[:members] = team.user_teams.includes(:user).where.not(role: "owner").map do |ut|
|
||||
|
||||
@@ -2,11 +2,18 @@ module Api
|
||||
module V1
|
||||
class YoutubeController < BaseController
|
||||
def authorize
|
||||
team = current_user.manageable_teams.find(params[:team_id])
|
||||
team = current_user.streamable_teams.find { |t| t.id.to_s == params[:team_id].to_s }
|
||||
raise ActiveRecord::RecordNotFound unless team
|
||||
|
||||
team.entitlements.assert_can_connect_youtube!
|
||||
state = Youtube::OauthState.for_team(team_id: team.id, user_id: current_user.id)
|
||||
return_app = ActiveModel::Type::Boolean.new.cast(params[:return_app])
|
||||
state = Youtube::OauthState.for_team(
|
||||
team_id: team.id,
|
||||
user_id: current_user.id,
|
||||
return_app: return_app
|
||||
)
|
||||
url = Youtube::OauthUrl.build(state: state, redirect_uri: ENV.fetch("YOUTUBE_REDIRECT_URI"))
|
||||
render json: { authorization_url: url }
|
||||
render json: { authorization_url: url, return_app: return_app }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user