diff --git a/app/controllers/stages_controller.rb b/app/controllers/stages_controller.rb new file mode 100644 index 0000000..cdc5f1b --- /dev/null +++ b/app/controllers/stages_controller.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +class StagesController < ApplicationController + before_action :set_stage, only: %i[show update] + before_action :authenticate_user!, only: %i[update] + before_action -> { require_owner! @stage.owner }, only: %i[update] + + # GET /stages/1 + def show + render json: @stage, include: '**' + end + + # PUT /stages/1 + def update + if stage_params[:state] == 'finished' + unless @stage.state == 'in_progress' + render json: { error: 'Only running group stages can be finished' }, status: :unprocessable_entity + return + end + + Stage.transaction do + if @stage.update(stage_params) + handle_group_stage_end + + render json: @stage + else + render json: @stage.errors, status: :unprocessable_entity + raise ActiveRecord::Rollback + end + end + else + render json: { + error: 'The state attribute may only be changed to finished' + }, status: :unprocessable_entity + end + end + + private + + def handle_group_stage_end + unless @stage.over? + render json: { + error: 'Group Stage still has some matches that are not over yet. Finish them to generate playoffs' + }, status: :unprocessable_entity + raise ActiveRecord::Rollback + end + + return if AddPlayoffsToTournamentAndSave.call(tournament: @stage.tournament, + teams: GroupStageService.get_advancing_teams(@stage)).success? + + render json: { error: 'Generating group stage failed' }, status: :unprocessable_entity + raise ActiveRecord::Rollback + end + + def set_stage + @stage = Stage.find(params[:id]) + end + + def stage_params + params.slice(:state).permit! + end +end diff --git a/config/routes.rb b/config/routes.rb index d8f761a..61901bd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,6 +9,7 @@ Rails.application.routes.draw do resources :matches, only: %i[show update] do resources :bets, only: %i[index create] end + resources :stages, only: %i[show update] resources :teams, only: %i[show update] resources :tournaments do resources :statistics, only: %i[index] diff --git a/spec/controllers/stages_controller_spec.rb b/spec/controllers/stages_controller_spec.rb new file mode 100644 index 0000000..042db52 --- /dev/null +++ b/spec/controllers/stages_controller_spec.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe StagesController, type: :controller do + before do + @stage = create(:playoff_stage) + end + + describe 'GET #show' do + it 'returns a success response' do + get :show, params: { id: @stage.to_param } + expect(response).to be_successful + end + + it 'should return the correct stage' do + get :show, params: { id: @stage.to_param } + body = deserialize_response response + expect(Stage.find_by(id: body[:id])).to eq(@stage) + expect(body[:level]).to eq(@stage.level) + expect(body[:state]).to eq(@stage.state) + end + end + + describe 'PUT #update' do + context 'group_stage with matches that are done' do + before do + @running_group_stage = create(:group_stage, match_factory: :finished_group_match) + end + + FINISHED = { state: 'finished' }.freeze + + it 'doesn\'t have any other stages besides it before update' do + expect(@running_group_stage.tournament.stages.size).to eq(1) + end + + context 'as owner' do + before(:each) do + apply_authentication_headers_for @running_group_stage.owner + end + + before do + put :update, params: { id: @running_group_stage.to_param }.merge(FINISHED) + @running_group_stage.reload + end + + it 'succeeds' do + expect(response).to be_successful + end + + it 'stops the stage' do + expect(@running_group_stage.state).to eq(FINISHED[:state]) + end + + it 'adds new stages to the tournament' do + expect(@running_group_stage.tournament.stages.size).to be > 1 + end + + it 'adds the right teams' do + expect(@running_group_stage.tournament.stages.max_by(&:level).teams) + .to match_array(GroupStageService.get_advancing_teams(@running_group_stage)) + end + end + + context 'as another user' do + before(:each) do + apply_authentication_headers_for create(:user) + end + + it 'returns an error' do + put :update, params: { id: @stage.to_param }.merge(FINISHED) + expect(response).to have_http_status(:forbidden) + end + end + end + end +end