diff --git a/app/controllers/tournaments_controller.rb b/app/controllers/tournaments_controller.rb index a40c6bf..19cb4ce 100644 --- a/app/controllers/tournaments_controller.rb +++ b/app/controllers/tournaments_controller.rb @@ -1,11 +1,12 @@ # 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] + before_action :set_tournament, only: %i[show update destroy set_timer_end, timer_end] + before_action :authenticate_user!, only: %i[create update destroy set_timer_end] + before_action -> { require_owner! @tournament.owner }, only: %i[update destroy set_timer_end] before_action :validate_create_params, only: %i[create] before_action :validate_update_params, only: %i[update] + before_action :validate_set_timer_end_params, only: %i[set_timer_end] rescue_from ActiveRecord::RecordNotFound, with: :render_not_found_error # GET /tournaments @@ -93,8 +94,27 @@ class TournamentsController < ApplicationController @tournament.destroy end + # GET /tournaments/:id/timer_end + def timer_end + render json: { timer_end: @tournament.timer_end } + end + + # PATCH /tournaments/:id/set_timer_end + def set_timer_end + if @tournament.update(timer_end_params) + render json: @tournament + else + render json: @tournament.errors, status: :unprocessable_entity + end + end + + private + def timer_end_params + { timer_end: params[:timer_end] } + end + def organize_teams_in_groups(teams) # each team gets put into a array of teams depending on the group specified in team[:group] teams.group_by { |team| team['group'] }.values.map do |group| @@ -158,3 +178,19 @@ class TournamentsController < ApplicationController }, status: :unprocessable_entity end end + +def validate_set_timer_end_params + timer_end = params[:timer_end] + return render json: { error: 'Timer end is required' }, status: :unprocessable_entity unless timer_end.present? + + begin + parsed_time = Time.zone.parse(timer_end) + if parsed_time.nil? + render json: { error: 'Invalid datetime format' }, status: :unprocessable_entity + elsif !parsed_time.future? + render json: { error: 'Timer end must be in the future' }, status: :unprocessable_entity + end + rescue ArgumentError + render json: { error: 'Invalid datetime format' }, status: :unprocessable_entity + end +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 101e869..9a6cf02 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,6 +14,10 @@ Rails.application.routes.draw do resources :tournaments do resources :statistics, only: %i[index] resources :matches, only: %i[index] + member do + get :timer_end + patch :set_timer_end + end end resources :match_scores, only: %i[show update] resources :groups, only: %i[show] diff --git a/spec/controllers/tournaments_controller_spec.rb b/spec/controllers/tournaments_controller_spec.rb index ae8f469..e0c4f82 100644 --- a/spec/controllers/tournaments_controller_spec.rb +++ b/spec/controllers/tournaments_controller_spec.rb @@ -477,4 +477,63 @@ RSpec.describe TournamentsController, type: :controller do end end end + + describe '#validate_set_timer_end_params' do + let(:tournament) { create(:tournament) } + + before do + apply_authentication_headers_for tournament.owner + @request.env['HTTP_ACCEPT'] = 'application/json' + end + + context 'when timer_end is missing' do + it 'returns unprocessable entity' do + patch :set_timer_end, params: { id: tournament.id } + expect(response).to have_http_status(:unprocessable_entity) + expect(JSON.parse(response.body)).to include('error' => 'Timer end is required') + end + end + + context 'when timer_end is invalid datetime' do + it 'returns unprocessable entity' do + patch :set_timer_end, params: { id: tournament.id, timer_end: 'invalid' } + expect(response).to have_http_status(:unprocessable_entity) + expect(JSON.parse(response.body)).to include('error' => 'Invalid datetime format') + end + end + + context 'when timer_end is in the past' do + it 'returns unprocessable entity' do + patch :set_timer_end, params: { id: tournament.id, timer_end: 1.day.ago } + expect(response).to have_http_status(:unprocessable_entity) + expect(JSON.parse(response.body)).to include('error' => 'Timer end must be in the future') + end + end + + context 'when timer_end is valid' do + it 'passes validation' do + patch :set_timer_end, params: { id: tournament.id, timer_end: 1.day.from_now } + expect(response).to have_http_status(:ok) + end + end + end + + describe 'GET #timer_end', focus:true do + let(:tournament) { create(:tournament) } + + before do + @request.env['HTTP_ACCEPT'] = 'application/json' + end + + it 'returns success response' do + get :timer_end, params: { id: tournament.to_param } + expect(response).to have_http_status(:ok) + end + + it 'returns timer_end value' do + tournament.update(timer_end: Time.zone.now + 1.day) + get :timer_end, params: { id: tournament.to_param } + expect(JSON.parse(response.body)['timer_end']).to eq(tournament.timer_end.as_json) + end + end end