class ContestsController < ApplicationController include CompletionsConcern include ContestantsConcern before_action :set_contest, only: %i[ destroy show ] before_action :set_settings_contest, only: %i[ settings_general_edit settings_general_update settings_offline_edit settings_offline_update settings_categories_edit ] before_action :offline_setup, only: %i[ offline_new offline_create offline_edit offline_update offline_completed ] skip_before_action :require_authentication, only: %i[ scoreboard offline_new offline_create offline_edit offline_update offline_completed ] def index authorize :contest @contests = current_user.contests @title = I18n.t("contests.index.title", username: current_user.username) end def show authorize @contest redirect_to contest_contestants_path(@contest) end def settings_general_edit authorize @contest end def settings_offline_edit authorize @contest end def settings_categories_edit authorize @contest end def settings_general_update authorize @contest if @contest.update(settings_general_params) redirect_to "/contests/#{@contest.id}/settings/general", notice: t("contests.edit.notice") else render :settings_general_edit, status: :unprocessable_entity end end def settings_offline_update authorize @contest if @contest.update(settings_offline_params) redirect_to "/contests/#{@contest.id}/settings/offline", notice: t("contests.edit.notice") else render :settings_offline_edit, status: :unprocessable_entity end end def new authorize :contest @contest = Contest.new @title = I18n.t("contests.new.title") @nonav = true end def create authorize :contest @contest = Contest.new(new_contest_params) @contest.lang = @current_user.lang @contest.ranking_mode = "actual" @contest.user_id = current_user.id if @contest.save redirect_to "/contests/#{@contest.id}/settings/general", notice: t("contests.new.notice") else @title = I18n.t("contests.new.title") @nonav = true render :new, status: :unprocessable_entity end end def destroy authorize @contest @contest.destroy redirect_to contests_path, notice: t("contests.destroy.notice") end def scoreboard @contest = Contest.find_by(slug: params[:id]) unless @contest && @contest.public skip_authorization not_found and return end authorize @contest I18n.locale = @contest.lang @title = I18n.t("contests.scoreboard.title", name: @contest.name) @contestants = ranked_contestants(@contest) filter_contestants_per_category if params.key?(:hide_offline) && params[:hide_offline] == "true" @contestants = @contestants.select { |contestant| !contestant.offline.present? } end @puzzles = @contest.puzzles.where(hidden: false).or(@contest.puzzles.where(hidden: nil)).order(:id) if params.key?(:hide_offline) && params.key?(:category) @action_path = "/public/#{@contest.friendly_id}?hide_offline=#{params[:hide_offline]}&category=#{params[:category]}" elsif params.key?(:category) @action_path = "/public/#{@contest.friendly_id}?category=#{params[:category]}" elsif params.key?(:hide_offline) @action_path = "/public/#{@contest.friendly_id}?hide_offline=#{params[:hide_offline]}" else @action_path = "/public/#{@contest.friendly_id}" end @space = " " render :scoreboard end def offline_new authorize @contest @offline = Offline.new end def offline_create authorize @contest @offline = Offline.new(offline_start_params) @offline.contest = @contest @offline.start_time = Time.now() if @offline.save redirect_to "/public/#{@contest.friendly_id}/offline/#{@offline.generate_token_for(:token)}" else render :offline_new, status: :unprocessable_entity end end def offline_edit authorize @contest @offline = Offline.find_by_token_for(:token, params[:token]) if !@offline not_found and return end if @offline.submitted render :offline_already_submitted and return end end def offline_update authorize @contest @offline = Offline.find_by_token_for(:token, params[:token]) if !@offline not_found and return end @offline.submitted = true @offline.completed = params[:offline][:completed] @offline.end_time = Time.now() @offline.images.attach(params[:offline][:end_image]) if @offline.completed @offline.missing_pieces = params[:offline][:missing_pieces] else @offline.remaining_pieces = params[:offline][:remaining_pieces] end if @offline.save if @contest.puzzles.length > 0 dp = display_time(@offline.end_time.to_i - @offline.start_time.to_i) contestant = Contestant.create(contest: @contest, name: @offline.name, offline: @offline) Completion.create(contest: @contest, contestant: contestant, offline: @offline, puzzle: @contest.puzzles[0], completed: @offline.completed, display_time_from_start: dp, missing_pieces: @offline.missing_pieces, remaining_pieces: @offline.remaining_pieces) extend_completions!(contestant) end redirect_to "/public/#{@contest.friendly_id}/offline/#{@offline.generate_token_for(:token)}/completed" else render :offline_edit, status: :unprocessable_entity end end def offline_completed authorize @contest @offline = Offline.find_by_token_for(:token, params[:token]) if !@offline not_found and return end end private def offline_setup @contest = Contest.find_by(slug: params[:id]) I18n.locale = @contest.lang @title = I18n.t("contests.scoreboard.title", name: @contest.name) end def set_contest @contest = Contest.find(params[:id]) end def set_settings_contest @contest = Contest.find(params[:contest_id]) end def new_contest_params params.expect(contest: [ :name, :duration ]) end def settings_general_params params.expect(contest: [ :lang, :name, :duration, :public, :ranking_mode, :team, :allow_registration, :code ]) end def settings_offline_params params.expect(contest: [ :offline_form ]) end def filter_contestants_per_category if params.key?(:category) && params[:category] != "-1" if params[:category] == "-2" @contestants = @contestants.select { |contestant| contestant.categories.size == 0 } else @contestants = @contestants.select { |contestant| contestant.categories.where(id: params[:category]).any? } end end end def offline_start_params params.expect(offline: [ :name, :images ]) end def offline_end_params params.expect(offline: [ :completed, :end_image, :remaining_pieces, :missing_pieces ]) end end