gw event improvements: status field, members_during_event endpoint
This commit is contained in:
parent
7d27d3c8b1
commit
26718b5a3e
9 changed files with 116 additions and 14 deletions
|
|
@ -3,7 +3,11 @@
|
|||
module Api
|
||||
module V1
|
||||
class GwEventBlueprint < ApiBlueprint
|
||||
fields :name, :element, :start_date, :end_date, :event_number
|
||||
fields :start_date, :end_date, :event_number
|
||||
|
||||
field :element do |event|
|
||||
GwEvent.elements[event.element]
|
||||
end
|
||||
|
||||
field :status do |event|
|
||||
if event.active?
|
||||
|
|
|
|||
|
|
@ -22,6 +22,39 @@ module Api
|
|||
render json: CrewGwParticipationBlueprint.render(@participation, view: :with_individual_scores, root: :crew_gw_participation)
|
||||
end
|
||||
|
||||
# GET /crew/gw_participations/by_event/:event_id
|
||||
def by_event
|
||||
# Support lookup by event_id (UUID) or event_number (integer)
|
||||
event = if params[:event_id].match?(/\A\d+\z/)
|
||||
GwEvent.find_by(event_number: params[:event_id])
|
||||
else
|
||||
GwEvent.find_by(id: params[:event_id])
|
||||
end
|
||||
|
||||
return render json: { gw_event: nil, crew_gw_participation: nil, members_during_event: [] } unless event
|
||||
|
||||
participation = @crew.crew_gw_participations
|
||||
.includes(:gw_event, gw_individual_scores: [:crew_membership, :phantom_player])
|
||||
.find_by(gw_event: event)
|
||||
|
||||
# Get all members who were active during the event (includes retired members who left after event started)
|
||||
# Also include all currently active members for score entry purposes
|
||||
# Uses joined_at (editable) for historical accuracy
|
||||
members_during_event = @crew.crew_memberships
|
||||
.includes(:user)
|
||||
.active_during(event.start_date, event.end_date)
|
||||
|
||||
# Get all phantom players who were active during the event or currently active
|
||||
phantom_players = @crew.phantom_players.active_during(event.start_date, event.end_date)
|
||||
|
||||
render json: {
|
||||
gw_event: GwEventBlueprint.render_as_hash(event),
|
||||
crew_gw_participation: participation ? CrewGwParticipationBlueprint.render_as_hash(participation, view: :with_individual_scores) : nil,
|
||||
members_during_event: CrewMembershipBlueprint.render_as_hash(members_during_event, view: :with_user),
|
||||
phantom_players: PhantomPlayerBlueprint.render_as_hash(phantom_players)
|
||||
}
|
||||
end
|
||||
|
||||
# POST /gw_events/:id/participations
|
||||
def create
|
||||
event = GwEvent.find(params[:id])
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ module Api
|
|||
end
|
||||
|
||||
def event_params
|
||||
params.require(:gw_event).permit(:name, :element, :start_date, :end_date, :event_number)
|
||||
params.require(:gw_event).permit(:element, :start_date, :end_date, :event_number)
|
||||
end
|
||||
|
||||
def require_admin!
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ class GwEvent < ApplicationRecord
|
|||
|
||||
enum :element, ELEMENTS
|
||||
|
||||
validates :name, presence: true
|
||||
validates :element, presence: true
|
||||
validates :start_date, presence: true
|
||||
validates :end_date, presence: true
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ChangeGwEventsNameNullable < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
remove_column :gw_events, :name, :string
|
||||
end
|
||||
end
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_12_04_075226) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_12_04_102935) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "btree_gin"
|
||||
enable_extension "pg_catalog.plpgsql"
|
||||
|
|
@ -269,6 +269,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_12_04_075226) do
|
|||
t.datetime "retired_at"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.datetime "joined_at"
|
||||
t.index ["crew_id", "role"], name: "index_crew_memberships_on_crew_id_and_role"
|
||||
t.index ["crew_id", "user_id"], name: "index_crew_memberships_on_crew_id_and_user_id", unique: true
|
||||
t.index ["crew_id"], name: "index_crew_memberships_on_crew_id"
|
||||
|
|
@ -462,7 +463,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_12_04_075226) do
|
|||
end
|
||||
|
||||
create_table "gw_events", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.integer "element", null: false
|
||||
t.date "start_date", null: false
|
||||
t.date "end_date", null: false
|
||||
|
|
@ -664,6 +664,9 @@ ActiveRecord::Schema[8.0].define(version: 2025_12_04_075226) do
|
|||
t.boolean "claim_confirmed", default: false, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.boolean "retired", default: false, null: false
|
||||
t.datetime "retired_at"
|
||||
t.datetime "joined_at"
|
||||
t.index ["claimed_by_id"], name: "index_phantom_players_on_claimed_by_id"
|
||||
t.index ["claimed_from_membership_id"], name: "index_phantom_players_on_claimed_from_membership_id"
|
||||
t.index ["crew_id", "granblue_id"], name: "index_phantom_players_on_crew_id_and_granblue_id", unique: true, where: "(granblue_id IS NOT NULL)"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
FactoryBot.define do
|
||||
factory :gw_event do
|
||||
sequence(:name) { |n| "Unite and Fight ##{n}" }
|
||||
element { %i[Fire Water Earth Wind Light Dark].sample }
|
||||
start_date { 1.week.from_now.to_date }
|
||||
end_date { 2.weeks.from_now.to_date }
|
||||
|
|
|
|||
|
|
@ -91,6 +91,65 @@ RSpec.describe 'Api::V1::CrewGwParticipations', type: :request do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v1/crew/gw_participations/by_event/:event_id' do
|
||||
context 'when participating in the event' do
|
||||
let!(:participation) { create(:crew_gw_participation, crew: crew, gw_event: gw_event) }
|
||||
|
||||
it 'returns the event and participation by event ID' do
|
||||
get "/api/v1/crew/gw_participations/by_event/#{gw_event.id}", headers: auth_headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['gw_event']['id']).to eq(gw_event.id)
|
||||
expect(json['crew_gw_participation']['id']).to eq(participation.id)
|
||||
expect(json['members_during_event']).to be_an(Array)
|
||||
end
|
||||
|
||||
it 'returns the event and participation by event number' do
|
||||
get "/api/v1/crew/gw_participations/by_event/#{gw_event.event_number}", headers: auth_headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['gw_event']['id']).to eq(gw_event.id)
|
||||
expect(json['crew_gw_participation']['id']).to eq(participation.id)
|
||||
end
|
||||
|
||||
it 'includes members who were active during the event' do
|
||||
get "/api/v1/crew/gw_participations/by_event/#{gw_event.id}", headers: auth_headers
|
||||
json = JSON.parse(response.body)
|
||||
member_ids = json['members_during_event'].map { |m| m['id'] }
|
||||
expect(member_ids).to include(membership.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when not participating in the event' do
|
||||
it 'returns event but null participation' do
|
||||
get "/api/v1/crew/gw_participations/by_event/#{gw_event.id}", headers: auth_headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['gw_event']['id']).to eq(gw_event.id)
|
||||
expect(json['crew_gw_participation']).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when event does not exist' do
|
||||
it 'returns null for both' do
|
||||
get '/api/v1/crew/gw_participations/by_event/99999', headers: auth_headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json['gw_event']).to be_nil
|
||||
expect(json['crew_gw_participation']).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'without a crew' do
|
||||
let!(:membership) { nil }
|
||||
|
||||
it 'returns unprocessable_entity' do
|
||||
get "/api/v1/crew/gw_participations/by_event/#{gw_event.id}", headers: auth_headers
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /api/v1/crew/gw_participations/:id' do
|
||||
let!(:participation) { create(:crew_gw_participation, crew: crew, gw_event: gw_event) }
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ RSpec.describe 'Api::V1::GwEvents', type: :request do
|
|||
get "/api/v1/gw_events/#{event.id}"
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json_response['gw_event']['id']).to eq(event.id)
|
||||
expect(json_response['gw_event']['name']).to eq(event.name)
|
||||
expect(json_response['gw_event']['element']).to eq(event.element)
|
||||
expect(json_response['gw_event']['element']).to eq(GwEvent.elements[event.element])
|
||||
end
|
||||
|
||||
it 'returns 404 for non-existent event' do
|
||||
|
|
@ -45,7 +44,6 @@ RSpec.describe 'Api::V1::GwEvents', type: :request do
|
|||
let(:valid_params) do
|
||||
{
|
||||
gw_event: {
|
||||
name: 'Unite and Fight #50',
|
||||
element: 'Fire',
|
||||
start_date: 1.week.from_now.to_date,
|
||||
end_date: 2.weeks.from_now.to_date,
|
||||
|
|
@ -61,12 +59,12 @@ RSpec.describe 'Api::V1::GwEvents', type: :request do
|
|||
}.to change(GwEvent, :count).by(1)
|
||||
|
||||
expect(response).to have_http_status(:created)
|
||||
expect(json_response['gw_event']['name']).to eq('Unite and Fight #50')
|
||||
expect(json_response['gw_event']['element']).to eq('Fire')
|
||||
expect(json_response['gw_event']['element']).to eq(GwEvent.elements['Fire'])
|
||||
expect(json_response['gw_event']['event_number']).to eq(50)
|
||||
end
|
||||
|
||||
it 'returns errors for invalid params' do
|
||||
post '/api/v1/gw_events', params: { gw_event: { name: '' } }, headers: admin_headers
|
||||
post '/api/v1/gw_events', params: { gw_event: { element: '' } }, headers: admin_headers
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
end
|
||||
end
|
||||
|
|
@ -88,13 +86,13 @@ RSpec.describe 'Api::V1::GwEvents', type: :request do
|
|||
|
||||
describe 'PUT /api/v1/gw_events/:id' do
|
||||
let!(:event) { create(:gw_event) }
|
||||
let(:update_params) { { gw_event: { name: 'Updated Event Name' } } }
|
||||
let(:update_params) { { gw_event: { event_number: 99 } } }
|
||||
|
||||
context 'as admin' do
|
||||
it 'updates the event' do
|
||||
put "/api/v1/gw_events/#{event.id}", params: update_params, headers: admin_headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(json_response['gw_event']['name']).to eq('Updated Event Name')
|
||||
expect(json_response['gw_event']['event_number']).to eq(99)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue