Merge pull request #6 from turniere/ticket/TURNIERE-87

Implement TournamentController
This commit is contained in:
Jonas Seydel 2018-11-25 23:00:23 +01:00 committed by GitHub
commit 3053b0681e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 318 additions and 19 deletions

View File

@ -24,4 +24,8 @@ class ApplicationController < ActionController::API
] ]
}, status: :forbidden }, status: :forbidden
end end
def deserialize_params(opts)
ActiveModelSerializers::Deserialization.jsonapi_parse(params, opts)
end
end end

View File

@ -5,10 +5,4 @@ class MatchesController < ApplicationController
def show def show
render json: Match.find(params[:id]), include: ['scores.score', 'scores.team'], status: status render json: Match.find(params[:id]), include: ['scores.score', 'scores.team'], status: status
end end
private
def match_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params, only: [:state])
end
end end

View File

@ -26,6 +26,6 @@ class TeamsController < ApplicationController
end end
def team_params def team_params
ActiveModelSerializers::Deserialization.jsonapi_parse(params, only: [:name]) deserialize_params only: %i[name]
end end
end end

View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
class TournamentsController < ApplicationController
before_action :set_tournament, only: %i[show update destroy]
before_action :authenticate_user!, only: %i[create update destroy]
before_action -> { require_owner! @tournament.owner }, only: %i[update destroy]
# GET /tournaments
def index
tournaments = Tournament.where(public: true).or(Tournament.where(owner: current_user)).order(:created_at)
render json: tournaments, each_serializer: SimpleTournamentSerializer
end
# GET /tournaments/1
def show
render json: @tournament
end
# POST /tournaments
def create
tournament = current_user.tournaments.new tournament_params
if tournament.save
render json: tournament, status: :created, location: tournament
else
render json: tournament.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /tournaments/1
def update
if @tournament.update(tournament_params)
render json: @tournament
else
render json: @tournament.errors, status: :unprocessable_entity
end
end
# DELETE /tournaments/1
def destroy
@tournament.destroy
end
private
def set_tournament
@tournament = Tournament.find(params[:id])
end
def tournament_params
deserialize_params only: %i[name description public teams]
end
end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class Team < ApplicationRecord class Team < ApplicationRecord
belongs_to :tournament belongs_to :tournament, optional: true
has_many :group_scores, dependent: :destroy has_many :group_scores, dependent: :destroy
has_many :scores, dependent: :destroy has_many :scores, dependent: :destroy

View File

@ -0,0 +1,5 @@
# frozen_string_literal: true
class SimpleTournamentSerializer < ApplicationSerializer
attributes :name, :code, :description, :public
end

View File

@ -0,0 +1,6 @@
# frozen_string_literal: true
class TournamentSerializer < SimpleTournamentSerializer
has_many :teams
has_many :stages
end

View File

@ -5,4 +5,5 @@ Rails.application.routes.draw do
resources :matches, only: %i[show] resources :matches, only: %i[show]
resources :teams, only: %i[show update] resources :teams, only: %i[show update]
resources :tournaments
end end

View File

@ -3,6 +3,6 @@
module AuthHelpers module AuthHelpers
def apply_authentication_headers_for(user) def apply_authentication_headers_for(user)
user_headers = user.create_new_auth_token user_headers = user.create_new_auth_token
@request.headers.merge!(user_headers) request.headers.merge!(user_headers)
end end
end end

View File

@ -3,16 +3,6 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe MatchesController, type: :controller do RSpec.describe MatchesController, type: :controller do
let(:valid_attributes) do
skip('Add a hash of attributes valid for your model')
end
let(:invalid_attributes) do
skip('Add a hash of attributes invalid for your model')
end
let(:valid_session) { {} }
before do before do
@match = create(:match) @match = create(:match)
@match.scores = create_pair(:score) @match.scores = create_pair(:score)

View File

@ -0,0 +1,205 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe TournamentsController, type: :controller do
def tournament_ids(response)
deserialize_list(response).map { |t| t[:id].to_i }
end
before do
@tournament = create(:tournament)
@user = @tournament.owner
@another_user = create(:user)
@private_tournament = create(:tournament, user: @another_user, public: false)
@teams = create_list(:detached_team, 4)
end
describe 'GET #index' do
it 'returns a success response' do
get :index
expect(response).to be_successful
end
it 'returns all public tournaments' do
get :index
tournaments = deserialize_list response
public_tournaments = tournaments.select { |t| t[:public] }
expect(public_tournaments.size).to eq((Tournament.where public: true).size)
end
it 'returns no private tournaments for unauthenticated users' do
get :index
tournaments = deserialize_list response
private_tournaments = tournaments.reject { |t| t[:public] }
expect(private_tournaments.size).to eq(0)
end
it 'returns private tournaments owned by the authenticated user' do
apply_authentication_headers_for @another_user
get :index
expect(tournament_ids(response)).to include(@private_tournament.id)
end
it 'returns no private tournaments owned by another user' do
apply_authentication_headers_for @user
get :index
expect(tournament_ids(response)).not_to include(@private_tournament.id)
end
end
describe 'GET #show' do
it 'returns a success response' do
get :show, params: { id: @tournament.to_param }
expect(response).to be_successful
end
it 'returns the requested tournament' do
get :show, params: { id: @tournament.to_param }
expect(deserialize_response(response)[:id].to_i).to eq(@tournament.id)
end
end
describe 'POST #create' do
let(:create_data) do
{
data: {
type: 'tournaments',
attributes: {
name: Faker::Dog.name,
description: Faker::Lorem.sentence,
public: false
},
relationships: {
teams: {
data: @teams.map { |team| { type: 'teams', id: team.id } }
}
}
}
}
end
before(:each) do
apply_authentication_headers_for @user
end
context 'with valid params' do
it 'creates a new Tournament' do
expect do
post :create, params: create_data
end.to change(Tournament, :count).by(1)
end
it 'associates the new tournament with the authenticated user' do
expect do
post :create, params: create_data
end.to change(@user.tournaments, :size).by(1)
end
it 'associates the given teams with the created tournament' do
new_teams = create_list(:detached_team, 4)
new_teams_create_data = create_data
new_teams_create_data[:data][:relationships][:teams][:data] = \
new_teams.map { |team| { type: 'teams', id: team.id } }
post :create, params: new_teams_create_data
expect(Tournament.last.teams).to match_array(new_teams)
end
it 'renders a JSON response with the new tournament' do
post :create, params: create_data
expect(response).to have_http_status(:created)
expect(response.content_type).to eq('application/json')
expect(response.location).to eq(tournament_url(Tournament.last))
end
end
end
describe 'PUT #update' do
let(:valid_update) do
{
data: {
type: 'tournaments',
id: @tournament.id,
attributes: {
name: Faker::Dog.name
}
}
}
end
context 'with valid params' do
context 'without authentication headers' do
it 'renders a unauthorized error response' do
put :update, params: { id: @tournament.to_param }.merge(valid_update)
expect(response).to have_http_status(:unauthorized)
end
end
context 'as owner' do
before(:each) do
apply_authentication_headers_for @tournament.owner
end
it 'updates the requested tournament' do
put :update, params: { id: @tournament.to_param }.merge(valid_update)
@tournament.reload
expect(@tournament.name).to eq(valid_update[:data][:attributes][:name])
end
it 'renders a JSON response with the tournament' do
put :update, params: { id: @tournament.to_param }.merge(valid_update)
expect(response).to have_http_status(:ok)
expect(response.content_type).to eq('application/json')
end
end
context 'as another user' do
before do
apply_authentication_headers_for create(:user)
end
it 'renders a forbidden error response' do
put :update, params: { id: @tournament.to_param }.merge(valid_update)
expect(response).to have_http_status(:forbidden)
end
end
end
end
describe 'DELETE #destroy' do
context 'without authentication headers' do
it 'renders a unauthorized error response' do
delete :destroy, params: { id: @tournament.to_param }
expect(response).to have_http_status(:unauthorized)
end
end
context 'as owner' do
before(:each) do
apply_authentication_headers_for @tournament.owner
end
it 'destroys the requested tournament' do
expect do
delete :destroy, params: { id: @tournament.to_param }
end.to change(Tournament, :count).by(-1)
end
it 'destroys associated teams' do
expect do
delete :destroy, params: { id: @tournament.to_param }
end.to change(Team, :count).by(-@tournament.teams.size)
end
end
context 'as another user' do
before do
apply_authentication_headers_for create(:user)
end
it 'renders a forbidden error response' do
delete :destroy, params: { id: @tournament.to_param }
expect(response).to have_http_status(:forbidden)
end
end
end
end

View File

@ -4,4 +4,10 @@ module DeserializeHelpers
def deserialize_response(response) def deserialize_response(response)
ActiveModelSerializers::Deserialization.jsonapi_parse(JSON.parse(response.body)) ActiveModelSerializers::Deserialization.jsonapi_parse(JSON.parse(response.body))
end end
def deserialize_list(response)
JSON.parse(response.body, symbolize_names: true)[:data].map do |raw_obj|
raw_obj[:attributes].merge raw_obj.except(:attributes)
end
end
end end

View File

@ -5,4 +5,8 @@ FactoryBot.define do
name { Faker::Dog.name } name { Faker::Dog.name }
tournament tournament
end end
factory :detached_team, class: Team do
name { Faker::Dog.name }
end
end end

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe TournamentsController, type: :routing do
describe 'routing' do
it 'routes to #index' do
expect(get: '/tournaments').to route_to('tournaments#index')
end
it 'routes to #show' do
expect(get: '/tournaments/1').to route_to('tournaments#show', id: '1')
end
it 'routes to #create' do
expect(post: '/tournaments').to route_to('tournaments#create')
end
it 'routes to #update via PUT' do
expect(put: '/tournaments/1').to route_to('tournaments#update', id: '1')
end
it 'routes to #update via PATCH' do
expect(patch: '/tournaments/1').to route_to('tournaments#update', id: '1')
end
it 'routes to #destroy' do
expect(delete: '/tournaments/1').to route_to('tournaments#destroy', id: '1')
end
end
end