Completa modulo Replay: S3, retention, sync YouTube e gestione società.

Streaming chunked da Garage, purge con delete YouTube, privacy sincronizzata,
archivio club migliorato, retention 30/90 separata da stato abbonamento.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-08 09:33:59 +02:00
parent ae36d17adb
commit 74eee24293
17 changed files with 385 additions and 34 deletions

View File

@@ -0,0 +1,38 @@
require "rails_helper"
RSpec.describe Recordings::Delete do
let!(:club) { Club.create!(name: "Club", sport: "volleyball", primary_color: "#e53935", secondary_color: "#ffffff") }
let!(:team) { club.teams.create!(name: "Team", sport: "volleyball") }
let!(:user) { User.create!(email: "coach@test.com", name: "Coach", password: "password123", role: "coach") }
let!(:match) { team.matches.create!(opponent_name: "Rival", scheduled_at: 1.day.from_now) }
let!(:session) do
StreamSession.create!(match: match, user: user, platform: "youtube", status: "ended")
end
let!(:recording) do
Recording.create!(
stream_session: session,
team: team,
status: "ready",
privacy_status: "public",
expires_at: 10.days.from_now,
storage_key: "teams/#{team.id}/sessions/#{session.id}/replay.mp4",
youtube_video_id: "abc123xyz"
)
end
it "elimina storage e revoca youtube_video_id" do
storage = instance_double(Recordings::Storage, delete: true)
allow(Recordings::Storage).to receive(:new).and_return(storage)
yt = instance_double(Youtube::VideoLifecycleService, delete!: true)
allow(Youtube::VideoLifecycleService).to receive(:new).with(recording).and_return(yt)
described_class.new(recording).call
expect(yt).to have_received(:delete!)
expect(storage).to have_received(:delete).at_least(:once)
recording.reload
expect(recording.deleted_at).to be_present
expect(recording.youtube_video_id).to be_nil
expect(recording.storage_key).to be_nil
end
end

View File

@@ -32,4 +32,16 @@ RSpec.describe Recordings::FinalizeSession do
Billing::AssignPlan.call(club: club, plan_slug: "free")
expect(described_class.new(session).call).to be_nil
end
it "imposta retention 90 giorni con premium full" do
Billing::AssignPlan.call(club: club, plan_slug: "premium_full")
rec = described_class.new(session).call
expect(rec.expires_at).to be > 89.days.from_now
end
it "non crea recording se abbonamento scaduto" do
Billing::AssignPlan.call(club: club, plan_slug: "premium_light")
club.subscription.update!(status: "canceled")
expect(described_class.new(session).call).to be_nil
end
end

View File

@@ -0,0 +1,41 @@
require "rails_helper"
RSpec.describe Teams::Entitlements, "recordings" do
let!(:club) { Club.create!(name: "Club", sport: "volleyball", primary_color: "#e53935", secondary_color: "#ffffff") }
let!(:team) { club.teams.create!(name: "Team", sport: "volleyball") }
let!(:user) { User.create!(email: "coach@test.com", name: "Coach", password: "password123", role: "coach") }
let!(:match) { team.matches.create!(opponent_name: "Rival", scheduled_at: 1.day.from_now) }
let!(:session) do
StreamSession.create!(match: match, user: user, platform: "matchlivetv", status: "ended")
end
before { load Rails.root.join("db/seeds/plans.rb") }
it "premium attivo può creare registrazioni" do
Billing::AssignPlan.call(club: club, plan_slug: "premium_light")
ent = described_class.new(team)
expect(ent.can_create_recordings?).to be true
expect(ent.can_access_recordings?).to be true
end
it "abbonamento scaduto non crea ma accede all'archivio esistente" do
Billing::AssignPlan.call(club: club, plan_slug: "premium_light")
club.subscription.update!(status: "canceled")
Recording.create!(
stream_session: session,
team: team,
status: "ready",
privacy_status: "unlisted",
expires_at: 5.days.from_now,
storage_key: "k"
)
ent = described_class.new(team.reload)
expect(ent.can_create_recordings?).to be false
expect(ent.can_access_recordings?).to be true
end
it "premium full ha retention 90 giorni" do
Billing::AssignPlan.call(club: club, plan_slug: "premium_full")
expect(described_class.new(team).recording_retention_days).to eq(90)
end
end