Merge pull request #6 from turniere/ticket/TURNIERE-87
Implement TournamentController
This commit is contained in:
commit
3053b0681e
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SimpleTournamentSerializer < ApplicationSerializer
|
||||||
|
attributes :name, :code, :description, :public
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class TournamentSerializer < SimpleTournamentSerializer
|
||||||
|
has_many :teams
|
||||||
|
has_many :stages
|
||||||
|
end
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue