From 4a6ae93d201bcfeb6ac3580489bbac50227afc83 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Thu, 18 Dec 2025 11:02:59 -0800 Subject: [PATCH] add gw scores history endpoints for members and phantoms --- .../api/v1/crew_memberships_controller.rb | 40 +++++++++++++++++- .../api/v1/phantom_players_controller.rb | 41 ++++++++++++++++++- app/models/crew_membership.rb | 1 + config/routes.rb | 4 ++ 4 files changed, 83 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/v1/crew_memberships_controller.rb b/app/controllers/api/v1/crew_memberships_controller.rb index dc18ec5..29788d9 100644 --- a/app/controllers/api/v1/crew_memberships_controller.rb +++ b/app/controllers/api/v1/crew_memberships_controller.rb @@ -6,11 +6,14 @@ module Api include CrewAuthorizationConcern before_action :restrict_access - before_action :set_crew + before_action :set_crew, except: %i[gw_scores] + before_action :set_crew_from_user, only: %i[gw_scores] before_action :set_membership, only: %i[update destroy promote demote] + before_action :set_membership_for_scores, only: %i[gw_scores] before_action :authorize_crew_officer!, only: %i[destroy] before_action :authorize_crew_captain!, only: %i[promote demote] before_action :authorize_membership_update!, only: %i[update] + before_action :authorize_crew_member!, only: %i[gw_scores] # PUT /crews/:crew_id/memberships/:id def update @@ -55,16 +58,51 @@ module Api render json: CrewMembershipBlueprint.render(@membership, view: :with_user, root: :membership) end + # GET /crew/memberships/:id/gw_scores + def gw_scores + # Group scores by participation/event and calculate totals + scores_by_event = @membership.gw_individual_scores + .includes(crew_gw_participation: :gw_event) + .group_by(&:crew_gw_participation) + + event_scores = scores_by_event.map do |participation, scores| + { + gw_event: GwEventBlueprint.render_as_hash(participation.gw_event), + total_score: scores.sum(&:score) + } + end + + # Sort by event number descending (most recent first) + event_scores.sort_by! { |es| -es[:gw_event][:event_number] } + + grand_total = event_scores.sum { |es| es[:total_score] } + + render json: { + member: CrewMembershipBlueprint.render_as_hash(@membership, view: :with_user), + event_scores: event_scores, + grand_total: grand_total + } + end + private def set_crew @crew = Crew.find(params[:crew_id]) end + def set_crew_from_user + @crew = current_user.crew + raise CrewErrors::NotInCrewError unless @crew + end + def set_membership @membership = @crew.crew_memberships.find(params[:id]) end + def set_membership_for_scores + @membership = @crew.crew_memberships.find(params[:id]) + end + def membership_params params.require(:membership).permit(:role, :joined_at, :retired, :retired_at) end diff --git a/app/controllers/api/v1/phantom_players_controller.rb b/app/controllers/api/v1/phantom_players_controller.rb index 1be9a5c..c440ce9 100644 --- a/app/controllers/api/v1/phantom_players_controller.rb +++ b/app/controllers/api/v1/phantom_players_controller.rb @@ -6,10 +6,12 @@ module Api include CrewAuthorizationConcern before_action :restrict_access - before_action :set_crew - before_action :authorize_crew_member!, only: %i[index confirm_claim decline_claim] + before_action :set_crew, except: %i[gw_scores] + before_action :set_crew_from_user, only: %i[gw_scores] + before_action :authorize_crew_member!, only: %i[index confirm_claim decline_claim gw_scores] before_action :authorize_crew_officer!, only: %i[create bulk_create update destroy assign] before_action :set_phantom, only: %i[show update destroy assign confirm_claim decline_claim] + before_action :set_phantom_for_scores, only: %i[gw_scores] # GET /crews/:crew_id/phantom_players def index @@ -86,16 +88,51 @@ module Api render json: PhantomPlayerBlueprint.render(@phantom, view: :with_claimed_by, root: :phantom_player) end + # GET /crew/phantom_players/:id/gw_scores + def gw_scores + # Group scores by participation/event and calculate totals + scores_by_event = @phantom.gw_individual_scores + .includes(crew_gw_participation: :gw_event) + .group_by(&:crew_gw_participation) + + event_scores = scores_by_event.map do |participation, scores| + { + gw_event: GwEventBlueprint.render_as_hash(participation.gw_event), + total_score: scores.sum(&:score) + } + end + + # Sort by event number descending (most recent first) + event_scores.sort_by! { |es| -es[:gw_event][:event_number] } + + grand_total = event_scores.sum { |es| es[:total_score] } + + render json: { + phantom: PhantomPlayerBlueprint.render_as_hash(@phantom), + event_scores: event_scores, + grand_total: grand_total + } + end + private def set_crew @crew = Crew.find(params[:crew_id]) end + def set_crew_from_user + @crew = current_user.crew + raise CrewErrors::NotInCrewError unless @crew + end + def set_phantom @phantom = @crew.phantom_players.find(params[:id]) end + def set_phantom_for_scores + @phantom = @crew.phantom_players.find(params[:id]) + end + def phantom_params params.require(:phantom_player).permit(:name, :granblue_id, :notes, :joined_at, :retired, :retired_at) end diff --git a/app/models/crew_membership.rb b/app/models/crew_membership.rb index ef06eef..8233262 100644 --- a/app/models/crew_membership.rb +++ b/app/models/crew_membership.rb @@ -3,6 +3,7 @@ class CrewMembership < ApplicationRecord belongs_to :crew belongs_to :user + has_many :gw_individual_scores, dependent: :nullify enum :role, { member: 0, vice_captain: 1, captain: 2 } diff --git a/config/routes.rb b/config/routes.rb index 53544fa..3781fcc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -238,6 +238,10 @@ Rails.application.routes.draw do # Create individual scores by event (auto-creates participation if needed) post 'gw_events/:gw_event_id/individual_scores', to: 'gw_individual_scores#create_by_event' post 'gw_events/:gw_event_id/individual_scores/batch', to: 'gw_individual_scores#batch_by_event' + + # Member/phantom GW score history + get 'memberships/:id/gw_scores', to: 'crew_memberships#gw_scores' + get 'phantom_players/:id/gw_scores', to: 'phantom_players#gw_scores' end # Reading collections - works for any user with privacy check