Files
euchre_camp/app/actions/admin/tournaments/schedule.rb
T
david ac858f1e6d feat(tournaments): add partnership tracking and tournament management
Implement comprehensive partnership tracking system and tournament
management features including round-robin, single/double elimination,
and Swiss system pairings.

Changes:
- Add partnership_games and partnership_stats tables
- Implement PartnershipTracker service for recording partnership data
- Add tournament generator with multiple formats
- Create tournament management actions and views
- Add acceptance tests for partnership tracking
- Fix PartnershipTracker to use single snapshot per player per match
- Fix round-robin test to query by round_number instead of hardcoded ID

Note: All 8 acceptance tests now passing
2026-03-27 12:25:34 -07:00

127 lines
4.5 KiB
Ruby

# frozen_string_literal: true
module EuchreCamp
module Actions
module Admin
module Tournaments
class Schedule < EuchreCamp::Action
include Deps[
events_repo: 'repositories.events',
teams_repo: 'repositories.teams',
rounds_repo: 'repositories.tournament_rounds',
matchups_repo: 'repositories.bracket_matchups'
]
def handle(request, response)
tournament_id = request.params[:id]
tournament = events_repo.by_id(tournament_id)
teams = teams_repo.by_event(tournament_id)
if teams.empty?
response.flash[:error] = "No teams to schedule. Add teams first."
response.redirect_to("/admin/tournaments/#{tournament_id}")
return
end
# Generate matchups based on format
teams_data = teams.map { |t| { id: t[:id], seed: t[:id] } }
format = tournament[:format]
begin
case format
when 'round_robin'
rounds = EuchreCamp::Services::TournamentGenerator.round_robin(teams_data)
create_round_robin_schedule(tournament_id, rounds)
when 'single_elim'
bracket = EuchreCamp::Services::TournamentGenerator.single_elimination(teams_data)
create_single_elim_schedule(tournament_id, bracket, teams)
when 'swiss'
# For Swiss, create first round
rounds = EuchreCamp::Services::TournamentGenerator.swiss(teams_data, 1)
create_swiss_schedule(tournament_id, rounds, 1)
else
response.flash[:error] = "Format '#{format}' not yet implemented"
response.redirect_to("/admin/tournaments/#{tournament_id}")
return
end
# Update tournament status
events_repo.update(tournament_id, status: 'active')
response.flash[:message] = "Schedule generated successfully"
response.redirect_to("/admin/tournaments/#{tournament_id}")
rescue StandardError => e
response.flash[:error] = "Failed to generate schedule: #{e.message}"
response.redirect_to("/admin/tournaments/#{tournament_id}")
end
end
private
def create_round_robin_schedule(tournament_id, rounds)
rounds.each do |round_data|
round = rounds_repo.create(
event_id: tournament_id,
round_number: round_data[:round_number],
status: round_data[:round_number] == 1 ? 'active' : 'pending'
)
round_data[:matchups].each_with_index do |matchup, index|
matchups_repo.create(
event_id: tournament_id,
round_id: round[:id],
team_1_id: matchup[:team_1_id],
team_2_id: matchup[:team_2_id],
bracket_position: index + 1
)
end
end
end
def create_single_elim_schedule(tournament_id, bracket, teams)
# Create first round
round = rounds_repo.create(
event_id: tournament_id,
round_number: 1,
status: 'active'
)
bracket[:first_round_matchups].each do |matchup|
# Skip if team is nil (BYE)
next if matchup[:team_1_id].nil? && matchup[:team_2_id].nil?
matchups_repo.create(
event_id: tournament_id,
round_id: round[:id],
team_1_id: matchup[:team_1_id],
team_2_id: matchup[:team_2_id],
bracket_position: matchup[:bracket_position]
)
end
end
def create_swiss_schedule(tournament_id, rounds, round_number)
round = rounds_repo.create(
event_id: tournament_id,
round_number: round_number,
status: 'active'
)
rounds.each do |round_data|
round_data[:matchups].each_with_index do |matchup, index|
matchups_repo.create(
event_id: tournament_id,
round_id: round[:id],
team_1_id: matchup[:team_1_id],
team_2_id: matchup[:team_2_id],
bracket_position: index + 1
)
end
end
end
end
end
end
end
end