fix gw controller params and add request specs
- use gw_participation_id param (matches route param name) - use gw_crew_score root key for consistency - add crew_gw_participations request specs - add gw_crew_scores request specs - add gw_individual_scores request specs - fix batch authorization to return early 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
f2a058b6b2
commit
7f57c2c3ee
5 changed files with 536 additions and 12 deletions
|
|
@ -11,27 +11,27 @@ module Api
|
||||||
before_action :set_participation
|
before_action :set_participation
|
||||||
before_action :set_score, only: %i[update destroy]
|
before_action :set_score, only: %i[update destroy]
|
||||||
|
|
||||||
# POST /crew/gw_participations/:participation_id/crew_scores
|
# POST /crew/gw_participations/:gw_participation_id/crew_scores
|
||||||
def create
|
def create
|
||||||
score = @participation.gw_crew_scores.build(score_params)
|
score = @participation.gw_crew_scores.build(score_params)
|
||||||
|
|
||||||
if score.save
|
if score.save
|
||||||
render json: GwCrewScoreBlueprint.render(score, root: :crew_score), status: :created
|
render json: GwCrewScoreBlueprint.render(score, root: :gw_crew_score), status: :created
|
||||||
else
|
else
|
||||||
render_validation_error_response(score)
|
render_validation_error_response(score)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# PUT /crew/gw_participations/:participation_id/crew_scores/:id
|
# PUT /crew/gw_participations/:gw_participation_id/crew_scores/:id
|
||||||
def update
|
def update
|
||||||
if @score.update(score_params)
|
if @score.update(score_params)
|
||||||
render json: GwCrewScoreBlueprint.render(@score, root: :crew_score)
|
render json: GwCrewScoreBlueprint.render(@score, root: :gw_crew_score)
|
||||||
else
|
else
|
||||||
render_validation_error_response(@score)
|
render_validation_error_response(@score)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# DELETE /crew/gw_participations/:participation_id/crew_scores/:id
|
# DELETE /crew/gw_participations/:gw_participation_id/crew_scores/:id
|
||||||
def destroy
|
def destroy
|
||||||
@score.destroy!
|
@score.destroy!
|
||||||
head :no_content
|
head :no_content
|
||||||
|
|
@ -45,7 +45,7 @@ module Api
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_participation
|
def set_participation
|
||||||
@participation = @crew.crew_gw_participations.find(params[:participation_id])
|
@participation = @crew.crew_gw_participations.find(params[:gw_participation_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_score
|
def set_score
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ module Api
|
||||||
before_action :set_participation
|
before_action :set_participation
|
||||||
before_action :set_score, only: %i[update destroy]
|
before_action :set_score, only: %i[update destroy]
|
||||||
|
|
||||||
# POST /crew/gw_participations/:participation_id/individual_scores
|
# POST /crew/gw_participations/:gw_participation_id/individual_scores
|
||||||
def create
|
def create
|
||||||
# Members can only record their own scores, officers can record anyone's
|
# Members can only record their own scores, officers can record anyone's
|
||||||
membership_id = score_params[:crew_membership_id]
|
membership_id = score_params[:crew_membership_id]
|
||||||
|
|
@ -29,7 +29,7 @@ module Api
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# PUT /crew/gw_participations/:participation_id/individual_scores/:id
|
# PUT /crew/gw_participations/:gw_participation_id/individual_scores/:id
|
||||||
def update
|
def update
|
||||||
unless can_record_score_for?(@score.crew_membership_id)
|
unless can_record_score_for?(@score.crew_membership_id)
|
||||||
raise Api::V1::UnauthorizedError
|
raise Api::V1::UnauthorizedError
|
||||||
|
|
@ -42,7 +42,7 @@ module Api
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# DELETE /crew/gw_participations/:participation_id/individual_scores/:id
|
# DELETE /crew/gw_participations/:gw_participation_id/individual_scores/:id
|
||||||
def destroy
|
def destroy
|
||||||
unless can_record_score_for?(@score.crew_membership_id)
|
unless can_record_score_for?(@score.crew_membership_id)
|
||||||
raise Api::V1::UnauthorizedError
|
raise Api::V1::UnauthorizedError
|
||||||
|
|
@ -52,9 +52,9 @@ module Api
|
||||||
head :no_content
|
head :no_content
|
||||||
end
|
end
|
||||||
|
|
||||||
# POST /crew/gw_participations/:participation_id/individual_scores/batch
|
# POST /crew/gw_participations/:gw_participation_id/individual_scores/batch
|
||||||
def batch
|
def batch
|
||||||
authorize_crew_officer!
|
return render_unauthorized_response unless current_user.crew_officer?
|
||||||
|
|
||||||
scores_params = params.require(:scores)
|
scores_params = params.require(:scores)
|
||||||
results = []
|
results = []
|
||||||
|
|
@ -94,7 +94,7 @@ module Api
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_participation
|
def set_participation
|
||||||
@participation = @crew.crew_gw_participations.find(params[:participation_id])
|
@participation = @crew.crew_gw_participations.find(params[:gw_participation_id])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_score
|
def set_score
|
||||||
|
|
|
||||||
122
spec/requests/api/v1/crew_gw_participations_spec.rb
Normal file
122
spec/requests/api/v1/crew_gw_participations_spec.rb
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Api::V1::CrewGwParticipations', type: :request do
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:access_token) do
|
||||||
|
Doorkeeper::AccessToken.create!(resource_owner_id: user.id, expires_in: 30.days, scopes: 'public')
|
||||||
|
end
|
||||||
|
let(:auth_headers) { { 'Authorization' => "Bearer #{access_token.token}" } }
|
||||||
|
|
||||||
|
let(:crew) { create(:crew) }
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :captain) }
|
||||||
|
let(:gw_event) { create(:gw_event) }
|
||||||
|
|
||||||
|
describe 'POST /api/v1/gw_events/:id/participations' do
|
||||||
|
context 'as crew officer' do
|
||||||
|
it 'joins the crew to an event' do
|
||||||
|
expect {
|
||||||
|
post "/api/v1/gw_events/#{gw_event.id}/participations", headers: auth_headers
|
||||||
|
}.to change(CrewGwParticipation, :count).by(1)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:created)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns error if already participating' do
|
||||||
|
create(:crew_gw_participation, crew: crew, gw_event: gw_event)
|
||||||
|
|
||||||
|
post "/api/v1/gw_events/#{gw_event.id}/participations", headers: auth_headers
|
||||||
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as regular member' do
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :member) }
|
||||||
|
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
post "/api/v1/gw_events/#{gw_event.id}/participations", headers: auth_headers
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without a crew' do
|
||||||
|
let!(:membership) { nil }
|
||||||
|
|
||||||
|
it 'returns unprocessable_entity' do
|
||||||
|
post "/api/v1/gw_events/#{gw_event.id}/participations", headers: auth_headers
|
||||||
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['code']).to eq('not_in_crew')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET /api/v1/crew/gw_participations' do
|
||||||
|
let!(:participation1) { create(:crew_gw_participation, crew: crew) }
|
||||||
|
let!(:participation2) { create(:crew_gw_participation, crew: crew) }
|
||||||
|
let!(:other_participation) { create(:crew_gw_participation) }
|
||||||
|
|
||||||
|
it 'returns crew participations' do
|
||||||
|
get '/api/v1/crew/gw_participations', headers: auth_headers
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['crew_gw_participations'].length).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without a crew' do
|
||||||
|
let!(:membership) { nil }
|
||||||
|
let!(:participation1) { nil }
|
||||||
|
let!(:participation2) { nil }
|
||||||
|
|
||||||
|
it 'returns unprocessable_entity' do
|
||||||
|
get '/api/v1/crew/gw_participations', headers: auth_headers
|
||||||
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'GET /api/v1/crew/gw_participations/:id' do
|
||||||
|
let!(:participation) { create(:crew_gw_participation, crew: crew, gw_event: gw_event) }
|
||||||
|
|
||||||
|
it 'returns the participation' do
|
||||||
|
get "/api/v1/crew/gw_participations/#{participation.id}", headers: auth_headers
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['crew_gw_participation']['id']).to eq(participation.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns 404 for other crew participation' do
|
||||||
|
other_participation = create(:crew_gw_participation)
|
||||||
|
get "/api/v1/crew/gw_participations/#{other_participation.id}", headers: auth_headers
|
||||||
|
expect(response).to have_http_status(:not_found)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'PUT /api/v1/crew/gw_participations/:id' do
|
||||||
|
let!(:participation) { create(:crew_gw_participation, crew: crew, gw_event: gw_event) }
|
||||||
|
|
||||||
|
context 'as officer' do
|
||||||
|
it 'updates rankings' do
|
||||||
|
put "/api/v1/crew/gw_participations/#{participation.id}",
|
||||||
|
params: { crew_gw_participation: { preliminary_ranking: 1500, final_ranking: 1200 } },
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['crew_gw_participation']['preliminary_ranking']).to eq(1500)
|
||||||
|
expect(json['crew_gw_participation']['final_ranking']).to eq(1200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as regular member' do
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :member) }
|
||||||
|
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
put "/api/v1/crew/gw_participations/#{participation.id}",
|
||||||
|
params: { crew_gw_participation: { preliminary_ranking: 1500 } },
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
137
spec/requests/api/v1/gw_crew_scores_spec.rb
Normal file
137
spec/requests/api/v1/gw_crew_scores_spec.rb
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Api::V1::GwCrewScores', type: :request do
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:access_token) do
|
||||||
|
Doorkeeper::AccessToken.create!(resource_owner_id: user.id, expires_in: 30.days, scopes: 'public')
|
||||||
|
end
|
||||||
|
let(:auth_headers) { { 'Authorization' => "Bearer #{access_token.token}" } }
|
||||||
|
|
||||||
|
let(:crew) { create(:crew) }
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :captain) }
|
||||||
|
let(:gw_event) { create(:gw_event) }
|
||||||
|
let!(:participation) { create(:crew_gw_participation, crew: crew, gw_event: gw_event) }
|
||||||
|
|
||||||
|
describe 'POST /api/v1/crew/gw_participations/:gw_participation_id/crew_scores' do
|
||||||
|
let(:valid_params) do
|
||||||
|
{
|
||||||
|
crew_score: {
|
||||||
|
round: 'preliminaries',
|
||||||
|
crew_score: 5_000_000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as crew officer' do
|
||||||
|
it 'creates a crew score' do
|
||||||
|
expect {
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/crew_scores",
|
||||||
|
params: valid_params,
|
||||||
|
headers: auth_headers
|
||||||
|
}.to change(GwCrewScore, :count).by(1)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:created)
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['gw_crew_score']['round']).to eq('preliminaries')
|
||||||
|
expect(json['gw_crew_score']['crew_score']).to eq(5_000_000)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a score with opponent info' do
|
||||||
|
params = {
|
||||||
|
crew_score: {
|
||||||
|
round: 'finals_day_1',
|
||||||
|
crew_score: 10_000_000,
|
||||||
|
opponent_score: 8_000_000,
|
||||||
|
opponent_name: 'Rival Crew',
|
||||||
|
opponent_granblue_id: '12345678'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/crew_scores",
|
||||||
|
params: params,
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:created)
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['gw_crew_score']['opponent_name']).to eq('Rival Crew')
|
||||||
|
expect(json['gw_crew_score']['victory']).to be true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns error for duplicate round' do
|
||||||
|
create(:gw_crew_score, crew_gw_participation: participation, round: :preliminaries)
|
||||||
|
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/crew_scores",
|
||||||
|
params: valid_params,
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as regular member' do
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :member) }
|
||||||
|
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/crew_scores",
|
||||||
|
params: valid_params,
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'PUT /api/v1/crew/gw_participations/:gw_participation_id/crew_scores/:id' do
|
||||||
|
let!(:score) { create(:gw_crew_score, crew_gw_participation: participation, round: :preliminaries, crew_score: 1_000_000) }
|
||||||
|
|
||||||
|
context 'as crew officer' do
|
||||||
|
it 'updates the score' do
|
||||||
|
put "/api/v1/crew/gw_participations/#{participation.id}/crew_scores/#{score.id}",
|
||||||
|
params: { crew_score: { crew_score: 2_000_000 } },
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['gw_crew_score']['crew_score']).to eq(2_000_000)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as regular member' do
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :member) }
|
||||||
|
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
put "/api/v1/crew/gw_participations/#{participation.id}/crew_scores/#{score.id}",
|
||||||
|
params: { crew_score: { crew_score: 2_000_000 } },
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'DELETE /api/v1/crew/gw_participations/:gw_participation_id/crew_scores/:id' do
|
||||||
|
let!(:score) { create(:gw_crew_score, crew_gw_participation: participation) }
|
||||||
|
|
||||||
|
context 'as crew officer' do
|
||||||
|
it 'deletes the score' do
|
||||||
|
expect {
|
||||||
|
delete "/api/v1/crew/gw_participations/#{participation.id}/crew_scores/#{score.id}",
|
||||||
|
headers: auth_headers
|
||||||
|
}.to change(GwCrewScore, :count).by(-1)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:no_content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as regular member' do
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :member) }
|
||||||
|
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
delete "/api/v1/crew/gw_participations/#{participation.id}/crew_scores/#{score.id}",
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
265
spec/requests/api/v1/gw_individual_scores_spec.rb
Normal file
265
spec/requests/api/v1/gw_individual_scores_spec.rb
Normal file
|
|
@ -0,0 +1,265 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'Api::V1::GwIndividualScores', type: :request do
|
||||||
|
let(:user) { create(:user) }
|
||||||
|
let(:access_token) do
|
||||||
|
Doorkeeper::AccessToken.create!(resource_owner_id: user.id, expires_in: 30.days, scopes: 'public')
|
||||||
|
end
|
||||||
|
let(:auth_headers) { { 'Authorization' => "Bearer #{access_token.token}" } }
|
||||||
|
|
||||||
|
let(:crew) { create(:crew) }
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :captain) }
|
||||||
|
let(:gw_event) { create(:gw_event) }
|
||||||
|
let!(:participation) { create(:crew_gw_participation, crew: crew, gw_event: gw_event) }
|
||||||
|
|
||||||
|
describe 'POST /api/v1/crew/gw_participations/:gw_participation_id/individual_scores' do
|
||||||
|
let(:valid_params) do
|
||||||
|
{
|
||||||
|
individual_score: {
|
||||||
|
crew_membership_id: membership.id,
|
||||||
|
round: 'preliminaries',
|
||||||
|
score: 1_000_000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as crew officer' do
|
||||||
|
it 'creates an individual score' do
|
||||||
|
expect {
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/individual_scores",
|
||||||
|
params: valid_params,
|
||||||
|
headers: auth_headers
|
||||||
|
}.to change(GwIndividualScore, :count).by(1)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:created)
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['individual_score']['score']).to eq(1_000_000)
|
||||||
|
expect(json['individual_score']['round']).to eq('preliminaries')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'can record score for other members' do
|
||||||
|
other_user = create(:user)
|
||||||
|
other_membership = create(:crew_membership, crew: crew, user: other_user, role: :member)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
individual_score: {
|
||||||
|
crew_membership_id: other_membership.id,
|
||||||
|
round: 'preliminaries',
|
||||||
|
score: 500_000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/individual_scores",
|
||||||
|
params: params,
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:created)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns error for duplicate round per member' do
|
||||||
|
create(:gw_individual_score,
|
||||||
|
crew_gw_participation: participation,
|
||||||
|
crew_membership: membership,
|
||||||
|
round: :preliminaries)
|
||||||
|
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/individual_scores",
|
||||||
|
params: valid_params,
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as regular member' do
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :member) }
|
||||||
|
|
||||||
|
it 'can record own score' do
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/individual_scores",
|
||||||
|
params: valid_params,
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:created)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'cannot record score for other members' do
|
||||||
|
other_user = create(:user)
|
||||||
|
other_membership = create(:crew_membership, crew: crew, user: other_user, role: :member)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
individual_score: {
|
||||||
|
crew_membership_id: other_membership.id,
|
||||||
|
round: 'preliminaries',
|
||||||
|
score: 500_000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/individual_scores",
|
||||||
|
params: params,
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'PUT /api/v1/crew/gw_participations/:gw_participation_id/individual_scores/:id' do
|
||||||
|
let!(:score) do
|
||||||
|
create(:gw_individual_score,
|
||||||
|
crew_gw_participation: participation,
|
||||||
|
crew_membership: membership,
|
||||||
|
round: :preliminaries,
|
||||||
|
score: 1_000_000)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as crew officer' do
|
||||||
|
it 'updates the score' do
|
||||||
|
put "/api/v1/crew/gw_participations/#{participation.id}/individual_scores/#{score.id}",
|
||||||
|
params: { individual_score: { score: 2_000_000 } },
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['individual_score']['score']).to eq(2_000_000)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as regular member' do
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :member) }
|
||||||
|
|
||||||
|
it 'can update own score' do
|
||||||
|
put "/api/v1/crew/gw_participations/#{participation.id}/individual_scores/#{score.id}",
|
||||||
|
params: { individual_score: { score: 2_000_000 } },
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:ok)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'cannot update other member scores' do
|
||||||
|
other_user = create(:user)
|
||||||
|
other_membership = create(:crew_membership, crew: crew, user: other_user, role: :member)
|
||||||
|
other_score = create(:gw_individual_score,
|
||||||
|
crew_gw_participation: participation,
|
||||||
|
crew_membership: other_membership,
|
||||||
|
round: :finals_day_1)
|
||||||
|
|
||||||
|
put "/api/v1/crew/gw_participations/#{participation.id}/individual_scores/#{other_score.id}",
|
||||||
|
params: { individual_score: { score: 2_000_000 } },
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'DELETE /api/v1/crew/gw_participations/:gw_participation_id/individual_scores/:id' do
|
||||||
|
let!(:score) do
|
||||||
|
create(:gw_individual_score,
|
||||||
|
crew_gw_participation: participation,
|
||||||
|
crew_membership: membership)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as crew officer' do
|
||||||
|
it 'deletes the score' do
|
||||||
|
expect {
|
||||||
|
delete "/api/v1/crew/gw_participations/#{participation.id}/individual_scores/#{score.id}",
|
||||||
|
headers: auth_headers
|
||||||
|
}.to change(GwIndividualScore, :count).by(-1)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:no_content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as regular member' do
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :member) }
|
||||||
|
|
||||||
|
it 'can delete own score' do
|
||||||
|
expect {
|
||||||
|
delete "/api/v1/crew/gw_participations/#{participation.id}/individual_scores/#{score.id}",
|
||||||
|
headers: auth_headers
|
||||||
|
}.to change(GwIndividualScore, :count).by(-1)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:no_content)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'cannot delete other member scores' do
|
||||||
|
other_user = create(:user)
|
||||||
|
other_membership = create(:crew_membership, crew: crew, user: other_user, role: :member)
|
||||||
|
other_score = create(:gw_individual_score,
|
||||||
|
crew_gw_participation: participation,
|
||||||
|
crew_membership: other_membership)
|
||||||
|
|
||||||
|
delete "/api/v1/crew/gw_participations/#{participation.id}/individual_scores/#{other_score.id}",
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'POST /api/v1/crew/gw_participations/:gw_participation_id/individual_scores/batch' do
|
||||||
|
let(:other_user) { create(:user) }
|
||||||
|
let!(:other_membership) { create(:crew_membership, crew: crew, user: other_user, role: :member) }
|
||||||
|
|
||||||
|
context 'as crew officer' do
|
||||||
|
it 'creates multiple scores' do
|
||||||
|
params = {
|
||||||
|
scores: [
|
||||||
|
{ crew_membership_id: membership.id, round: 'preliminaries', score: 1_000_000 },
|
||||||
|
{ crew_membership_id: other_membership.id, round: 'preliminaries', score: 500_000 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
expect {
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/individual_scores/batch",
|
||||||
|
params: params,
|
||||||
|
headers: auth_headers
|
||||||
|
}.to change(GwIndividualScore, :count).by(2)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:created)
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json['individual_scores'].length).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates existing scores in batch' do
|
||||||
|
existing = create(:gw_individual_score,
|
||||||
|
crew_gw_participation: participation,
|
||||||
|
crew_membership: membership,
|
||||||
|
round: :preliminaries,
|
||||||
|
score: 100_000)
|
||||||
|
|
||||||
|
params = {
|
||||||
|
scores: [
|
||||||
|
{ crew_membership_id: membership.id, round: 'preliminaries', score: 2_000_000 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
expect {
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/individual_scores/batch",
|
||||||
|
params: params,
|
||||||
|
headers: auth_headers
|
||||||
|
}.not_to change(GwIndividualScore, :count)
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:created)
|
||||||
|
expect(existing.reload.score).to eq(2_000_000)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'as regular member' do
|
||||||
|
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :member) }
|
||||||
|
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
params = {
|
||||||
|
scores: [
|
||||||
|
{ crew_membership_id: membership.id, round: 'preliminaries', score: 1_000_000 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/api/v1/crew/gw_participations/#{participation.id}/individual_scores/batch",
|
||||||
|
params: params,
|
||||||
|
headers: auth_headers
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue