Limita una diretta attiva per account e valorizza la copertina Premium Full.

Blocca la seconda diretta sullo stesso utente, registra gli abusi in admin e presenta la copertina come grafica caricata dalla società, con demo Team MLTV.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-01 12:52:26 +02:00
co-authored by Cursor
parent 356aa28fad
commit d52434fb2e
62 changed files with 1509 additions and 109 deletions
@@ -0,0 +1,99 @@
# frozen_string_literal: true
require "rails_helper"
RSpec.describe Sessions::Start, "one live per user" do
let(:user) { User.create!(email: "tx@test.it", name: "Tx", password: "Password123", role: "coach") }
let(:club) { Club.create!(name: "Club A", sport: "volleyball") }
let(:team) { club.teams.create!(name: "Team A", sport: "volleyball") }
let(:match_a) { team.matches.create!(opponent_name: "Opp A", sport: "volleyball") }
let(:match_b) { team.matches.create!(opponent_name: "Opp B", sport: "volleyball") }
before do
club.club_memberships.create!(user: user, role: "owner")
plan = Plan.find_or_initialize_by(slug: "premium_full")
plan.name ||= "Premium Full"
plan.features = (plan.features || {}).merge(
"platforms" => %w[matchlivetv youtube],
"concurrent_streams_limit" => 10
)
plan.save!
club.create_subscription!(plan: plan, status: "active") if club.subscription.blank?
allow(SessionChannel).to receive(:broadcast_message)
end
def session_for(match, status:, device_model: "Pixel 8")
StreamSession.create!(
match: match,
user: user,
platform: "matchlivetv",
status: status,
device_manufacturer: "Google",
device_model: device_model,
client_os: "android"
)
end
it "avvia la prima diretta" do
session = session_for(match_a, status: "idle")
described_class.new(session).call
expect(session.reload.status).to eq("connecting")
expect(StreamConcurrencyViolation.count).to eq(0)
end
it "blocca la seconda diretta dello stesso account e registra l'abuso" do
live = session_for(match_a, status: "live", device_model: "Pixel 8")
live.update!(started_at: 10.minutes.ago)
second = session_for(match_b, status: "idle", device_model: "iPhone 15")
second.update!(client_os: "ios", device_manufacturer: "Apple")
expect {
described_class.new(second).call
}.to raise_error(Teams::EntitlementError) { |e|
expect(e.code).to eq("user_concurrent_stream")
}
expect(second.reload.status).to eq("idle")
violation = StreamConcurrencyViolation.last
expect(violation).to be_present
expect(violation.user_email).to eq(user.email)
expect(violation.occupying_session_id).to eq(live.id)
expect(violation.attempted_session_id).to eq(second.id)
expect(violation.devices_differ).to be(true)
expect(violation.attempt_action).to eq("start")
end
it "non blocca un secondo account sulla stessa società" do
other = User.create!(email: "tx2@test.it", name: "Tx2", password: "Password123", role: "coach")
club.club_memberships.create!(user: other, role: "owner")
session_for(match_a, status: "live")
other_session = StreamSession.create!(
match: match_b,
user: other,
platform: "matchlivetv",
status: "idle"
)
described_class.new(other_session).call
expect(other_session.reload.status).to eq("connecting")
end
it "considera occupante anche una sessione in pausa" do
session_for(match_a, status: "paused")
second = session_for(match_b, status: "idle")
expect {
described_class.new(second).call
}.to raise_error(Teams::EntitlementError) { |e|
expect(e.code).to eq("user_concurrent_stream")
}
end
it "non considera occupante una sessione idle" do
session_for(match_a, status: "idle")
second = session_for(match_b, status: "idle")
described_class.new(second).call
expect(second.reload.status).to eq("connecting")
end
end