From 1b9db61c22820c92b7ca1313e501de598e5e3fd2 Mon Sep 17 00:00:00 2001 From: Thor77 Date: Tue, 7 May 2019 15:19:15 +0200 Subject: [PATCH 1/4] Add owner method to Stage, Group and Match --- app/models/group.rb | 2 ++ app/models/match.rb | 4 ++++ app/models/stage.rb | 2 ++ 3 files changed, 8 insertions(+) diff --git a/app/models/group.rb b/app/models/group.rb index 1b99378..b9bac6a 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -5,6 +5,8 @@ class Group < ApplicationRecord has_many :matches, dependent: :destroy has_many :group_scores, dependent: :destroy + delegate :owner, to: :stage + def teams matches.map(&:teams).flatten.uniq end diff --git a/app/models/match.rb b/app/models/match.rb index 6c3eee8..8ab9756 100644 --- a/app/models/match.rb +++ b/app/models/match.rb @@ -15,6 +15,10 @@ class Match < ApplicationRecord match_scores.map(&:team).flatten.uniq end + def owner + stage ? stage.owner : group.owner + end + private def stage_xor_group diff --git a/app/models/stage.rb b/app/models/stage.rb index 48ad20d..e1aa980 100644 --- a/app/models/stage.rb +++ b/app/models/stage.rb @@ -5,6 +5,8 @@ class Stage < ApplicationRecord has_many :matches, dependent: :destroy has_many :groups, dependent: :destroy + delegate :owner, to: :tournament + def teams return matches.map(&:teams).flatten.uniq unless matches.size.zero? From 436adde70613bd19f5c8f1a053ac7d8d4a70630b Mon Sep 17 00:00:00 2001 From: Thor77 Date: Tue, 7 May 2019 15:33:21 +0200 Subject: [PATCH 2/4] Set global match var for reuse by other methods --- app/controllers/matches_controller.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/controllers/matches_controller.rb b/app/controllers/matches_controller.rb index d15e841..549f4d7 100644 --- a/app/controllers/matches_controller.rb +++ b/app/controllers/matches_controller.rb @@ -1,8 +1,16 @@ # frozen_string_literal: true class MatchesController < ApplicationController + before_action :set_match, only: %i[show update] + # GET /matches/1 def show - render json: Match.find(params[:id]), include: ['match_scores.points', 'match_scores.team'] + render json: @match, include: ['match_scores.points', 'match_scores.team'] + end + + private + + def set_match + @match = Match.find(params[:id]) end end From 3876f57d32af1500966807d6484d8bfbc09f19bb Mon Sep 17 00:00:00 2001 From: Thor77 Date: Tue, 7 May 2019 16:03:09 +0200 Subject: [PATCH 3/4] Add methods and specs to update a match --- app/controllers/matches_controller.rb | 28 ++++++++++ config/routes.rb | 2 +- spec/controllers/matches_controller_spec.rb | 58 ++++++++++++++++++++- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/app/controllers/matches_controller.rb b/app/controllers/matches_controller.rb index 549f4d7..10ba52f 100644 --- a/app/controllers/matches_controller.rb +++ b/app/controllers/matches_controller.rb @@ -2,15 +2,43 @@ class MatchesController < ApplicationController before_action :set_match, only: %i[show update] + before_action :validate_params, only: %i[update] + before_action -> { require_owner! @match.owner }, only: %i[update] # GET /matches/1 def show render json: @match, include: ['match_scores.points', 'match_scores.team'] end + # PATCH/PUT /matches/1 + def update + if @match.update(match_params) + render json: @match + else + render json: @match.errors, status: :unprocessable_entity + end + end + private + def validate_params + case match_params['state'] + when 'in_progress' + render json: { error: 'Match can\'t start in this state' }, status: :unprocessable_entity \ + unless @match.not_started? + when 'finished' + render json: { error: 'Match can\'t finish in this state' }, status: :unprocessable_entity \ + unless @match.in_progress? + else + render json: { error: 'Invalid target state' }, status: :unprocessable_entity + end + end + def set_match @match = Match.find(params[:id]) end + + def match_params + params.slice(:state).permit! + end end diff --git a/config/routes.rb b/config/routes.rb index bf135cb..16b79b6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,7 +6,7 @@ Rails.application.routes.draw do sessions: 'overrides/sessions' } - resources :matches, only: %i[show] + resources :matches, only: %i[show update] resources :teams, only: %i[show update] resources :tournaments resources :match_scores, only: %i[show update] diff --git a/spec/controllers/matches_controller_spec.rb b/spec/controllers/matches_controller_spec.rb index 4426afa..10b0a30 100644 --- a/spec/controllers/matches_controller_spec.rb +++ b/spec/controllers/matches_controller_spec.rb @@ -4,7 +4,7 @@ require 'rails_helper' RSpec.describe MatchesController, type: :controller do before do - @match = create(:match) + @match = create(:match, state: :not_started) @match.match_scores = create_pair(:match_score) end @@ -22,4 +22,60 @@ RSpec.describe MatchesController, type: :controller do expect(body[:match_scores].map { |ms| ms[:id] }).to eq(@match.match_scores.map(&:id)) end end + + describe 'POST #update' do + let(:valid_update) do + { + state: 'in_progress' + } + end + + let(:invalid_update) do + { + state: 'team1_won' + } + end + + context 'as owner' do + before(:each) do + apply_authentication_headers_for @match.owner + end + + context 'with valid params' do + it 'updates the match' do + put :update, params: { id: @match.to_param }.merge(valid_update) + @match.reload + expect(response).to be_successful + expect(@match.state).to eq(valid_update[:state]) + end + + it 'renders a response with the updated match' do + put :update, params: { id: @match.to_param }.merge(valid_update) + expect(response).to be_successful + body = deserialize_response response + expect(body[:state]).to eq(valid_update[:state]) + end + end + + context 'with invalid params' do + it 'renders an unprocessable entity response' do + put :update, params: { id: @match.to_param }.merge(invalid_update) + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + + context 'as another user' do + context 'with valid params' do + before(:each) do + apply_authentication_headers_for create(:user) + end + + it 'renders a forbidden error response' do + put :update, params: { id: @match.to_param }.merge(valid_update) + expect(response).to have_http_status(:forbidden) + end + end + end + end end From 27c4bcacc8bd07eb1d1310ad11c3eeb3f7dd05e5 Mon Sep 17 00:00:00 2001 From: Thor77 Date: Tue, 7 May 2019 18:29:46 +0200 Subject: [PATCH 4/4] Respond with 501 for state param 'finished' (501 = NOT IMPLEMENTED) --- app/controllers/matches_controller.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/controllers/matches_controller.rb b/app/controllers/matches_controller.rb index 10ba52f..c65b521 100644 --- a/app/controllers/matches_controller.rb +++ b/app/controllers/matches_controller.rb @@ -12,6 +12,12 @@ class MatchesController < ApplicationController # PATCH/PUT /matches/1 def update + new_state = match_params['state'] + if new_state == 'finished' + # implement logic to move the winning team into the next stage + match_params['state'] = 'team1_won' # or 'team2_won' or 'undecided' + render json: {}, status: :not_implemented + end if @match.update(match_params) render json: @match else