From 2f53b2252ff2fe2151ec486a164e8ba153495b64 Mon Sep 17 00:00:00 2001 From: plural Date: Mon, 20 Jan 2025 13:31:20 -0600 Subject: [PATCH] Add id_and_faction_date JSON endpoint for tournaments. (#386) --- app/controllers/tournaments_controller.rb | 7 +++ app/models/tournament.rb | 57 +++++++++++++++++ config/routes.rb | 1 + spec/requests/tournaments_controller_spec.rb | 64 ++++++++++++++++++-- 4 files changed, 125 insertions(+), 4 deletions(-) diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index 6ed29cce..c3e907bf 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -5,6 +5,7 @@ class TournamentsController < ApplicationController show edit update destroy upload_to_abr save_json cut qr registration timer close_registration open_registration lock_player_registrations unlock_player_registrations + id_and_faction_data ] def index @@ -221,6 +222,12 @@ def unlock_player_registrations redirect_back(fallback_location: tournament_rounds_path(@tournament)) end + def id_and_faction_data + authorize @tournament, :show? + + render json: @tournament.id_and_faction_data + end + private def set_tournament diff --git a/app/models/tournament.rb b/app/models/tournament.rb index 778e30e6..a43a479d 100644 --- a/app/models/tournament.rb +++ b/app/models/tournament.rb @@ -104,6 +104,63 @@ def runner_counts end.sort_by(&:last).reverse end + def id_and_faction_data + sql = <<~SQL + WITH corp_ids AS ( + SELECT + 1 AS side, + COALESCE(corp_ids.name, 'Unknown') as id, + COALESCE(corp_ids.faction, 'unknown') AS faction + FROM + players AS p + LEFT JOIN identities AS corp_ids + ON p.corp_identity_ref_id = corp_ids.id + WHERE p.tournament_id = ? + ), + runner_ids AS ( + SELECT + 2 AS side, + COALESCE(runner_ids.name, 'Unknown') as id, + COALESCE(runner_ids.faction, 'unknown') AS faction + FROM + players AS p + LEFT JOIN identities AS runner_ids + ON p.runner_identity_ref_id = runner_ids.id + WHERE p.tournament_id = ? + ) + SELECT side, id, faction, COUNT(*) AS num_ids FROM corp_ids GROUP BY 1,2,3 + UNION ALL + SELECT side, id, faction, COUNT(*) AS num_ids FROM runner_ids GROUP BY 1,2,3 + SQL + sql = ActiveRecord::Base.sanitize_sql([sql, id, id]) + + results = { + num_players: 0, + corp: { + ids: {}, + factions: {} + }, + runner: { + ids: {}, + factions: {} + } + } + ActiveRecord::Base.connection.exec_query(sql).each do |row| + side = row['side'] == 1 ? :corp : :runner + + # We only need to use 1 side to get the total number of players + results[:num_players] += row['num_ids'] if side == :corp + + # Only 1 row per id + results[side][:ids][row['id']] = row['num_ids'] + + # Multiple rows per faction so we need to sum them up + results[side][:factions][row['faction']] ||= 0 + results[side][:factions][row['faction']] += row['num_ids'] + end + results + end + def generate_slug self.slug = rand(Integer(36**4)).to_s(36).upcase generate_slug if Tournament.exists?(slug:) diff --git a/config/routes.rb b/config/routes.rb index 01de1c7a..1605243f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -39,6 +39,7 @@ resources :stages, only: %i[create destroy] post :upload_to_abr, on: :member get :save_json, on: :member + get :id_and_faction_data, on: :member post :cut, on: :member get :qr, on: :member get :registration, on: :member diff --git a/spec/requests/tournaments_controller_spec.rb b/spec/requests/tournaments_controller_spec.rb index f601e110..8bb98c24 100644 --- a/spec/requests/tournaments_controller_spec.rb +++ b/spec/requests/tournaments_controller_spec.rb @@ -2,10 +2,25 @@ RSpec.describe TournamentsController do let(:tournament) { create(:tournament, name: 'My Tournament') } - let(:player1) { create(:player, tournament:) } - let(:player2) { create(:player, tournament:) } - let(:player3) { create(:player, tournament:) } - let(:player4) { create(:player, tournament:) } + + let(:btl) { create(:identity, name: 'Builder of Nations', faction: 'weyland-consortium') } + let(:hoshiko) { create(:identity, name: 'Hoshiko', faction: 'anarch') } + let(:sable) { create(:identity, name: 'Sable', faction: 'criminal') } + let(:az) { create(:identity, name: 'Az', faction: 'criminal') } + + let(:player1) do + create(:player, tournament:, corp_identity: btl.name, corp_identity_ref_id: btl.id, runner_identity: hoshiko.name, + runner_identity_ref_id: hoshiko.id) + end + let(:player2) do + create(:player, tournament:, runner_identity: sable.name, + runner_identity_ref_id: sable.id) + end + let(:player3) do + create(:player, tournament:, corp_identity: btl.name, corp_identity_ref_id: btl.id, runner_identity: az.name, + runner_identity_ref_id: az.id) + end + let(:player4) { create(:player, tournament:, corp_identity: btl.name, corp_identity_ref_id: btl.id) } describe '#save_json' do before do @@ -70,4 +85,45 @@ expect(tournament.swiss?).to be(true) end end + + describe '#id_and_faction_data' do + it 'returns correct id_and_faction_data JSON' do + player1.save + player2.save + player3.save + player4.save + # puts tournament.name + puts tournament.players.size + + get id_and_faction_data_tournament_path(tournament) + + expect(JSON.parse(response.body)) + .to eq( + 'num_players' => 4, + 'corp' => { + 'factions' => { + 'weyland-consortium' => 3, + 'unknown' => 1 + }, + 'ids' => { + 'Builder of Nations' => 3, + 'Unknown' => 1 + } + }, + 'runner' => { + 'factions' => { + 'unknown' => 1, + 'anarch' => 1, + 'criminal' => 2 + }, + 'ids' => { + 'Az' => 1, + 'Hoshiko' => 1, + 'Sable' => 1, + 'Unknown' => 1 + } + } + ) + end + end end