class ContestantsController < ApplicationController include CompletionsConcern include ContestantsConcern before_action :set_contest, only: %i[ index edit new create update destroy import upload_csv convert_csv finalize_import export generate_qrcodes generate_qrcodes_pdf ] before_action :set_contestant, only: %i[ destroy edit update] before_action :set_completions, only: %i[edit update ] skip_before_action :require_authentication, only: %i[ get_public_completion post_public_completion public_completion_updated ] def index authorize @contest @contestants = @contest.contestants.sort_by { |contestant| contestant.name } filter_contestants_per_category end def edit authorize @contest end def new authorize @contest @contestant = Contestant.new end def create authorize @contest @contestant = Contestant.new(contestant_params) @contestant.contest_id = @contest.id if @contestant.save update_contestant_categories redirect_to contest_path(@contest), notice: t("contestants.new.notice") else render :new, status: :unprocessable_entity end end def update authorize @contest if @contestant.update(contestant_params) update_contestant_categories redirect_to contest_contestants_path(@contest), notice: t("contestants.edit.notice") else render :edit, status: :unprocessable_entity end end def destroy authorize @contest @contestant.destroy redirect_to contest_path(@contest), notice: t("contestants.destroy.notice") end def import authorize @contest @action_name = t("helpers.buttons.back") @action_path = contest_path(@contest) @csv_import = CsvImport.new end def upload_csv authorize @contest @csv_import = CsvImport.new(params.require(:csv_import).permit(:file, :separator)) if @csv_import.save redirect_to "/contests/#{@contest.id}/import/#{@csv_import.id}" else render :import, status: :unprocessable_entity end end def convert_csv authorize @contest @csv_import = CsvImport.find(params[:id]) @content = JSON.parse(@csv_import.content) @form = Forms::CsvConversionForm.new end def finalize_import authorize @contest @csv_import = CsvImport.find(params[:id]) @content = JSON.parse(@csv_import.content) all_params = params.require(:forms_csv_conversion_form) @form = Forms::CsvConversionForm.new(params.require(:forms_csv_conversion_form).permit(:email_column, :name_column)) if @form.valid? @content.each_with_index do |row, i| if all_params["row_#{i}".to_sym] == "1" if @form.email_column == -1 Contestant.create(name: row[@form.name_column], contest: @contest) else Contestant.create(name: row[@form.name_column], email: row[@form.email_column], contest: @contest) end end end redirect_to contest_path(@contest), notice: t("contestants.import.notice") else render :convert_csv, status: :unprocessable_entity end end def export authorize @contest @contestants = ranked_contestants(@contest) respond_to do |format| format.csv do response.headers["Content-Type"] = "text/csv" response.headers["Content-Disposition"] = "attachment; filename=#{contest.friendly_id}_results.csv" end end end def generate_qrcodes authorize @contest @contestants = @contest.contestants.sort_by { |contestant| contestant.name } end def generate_qrcodes_pdf authorize @contest @contestants = @contest.contestants.sort_by { |contestant| contestant.name } @nonav = true respond_to do |format| format.html { render layout: "blank" } end end def get_public_completion skip_authorization @contestant = Contestant.find_by_token_for(:token, params[:token]) if !@contestant not_found and return end @contest = @contestant.contest I18n.locale = @contest.lang @puzzles = @contest.puzzles @completion = Completion.new @completion.completed = true @public = true render "completions/_form", locals: { completion: @completion, submit_text: t("helpers.buttons.create"), method: :post, url: "/public/p/#{params[:token]}" } end def post_public_completion skip_authorization @contestant = Contestant.find_by_token_for(:token, params[:token]) if !@contestant not_found and return end @contest = @contestant.contest I18n.locale = @contest.lang @completion = Completion.new(completion_params) @completion.contest = @contest @completion.contestant = @contestant if !@completion.code.present? to_modify = true @completion.code = "incorrect-xZy" end if @completion.save extend_completions!(@completion.contestant) redirect_to "/public/p/#{params[:token]}/updated" else @puzzles = @contest.puzzles @public = true if to_modify @completion.code = nil end render "completions/_form", locals: { completion: @completion, submit_text: t("helpers.buttons.create"), method: :post, url: "/public/p/#{params[:token]}" }, status: :unprocessable_entity end end def public_completion_updated skip_authorization @contestant = Contestant.find_by_token_for(:token, params[:token]) if !@contestant not_found and return end I18n.locale = @contestant.contest.lang end private def set_contest @contest = Contest.find(params[:contest_id]) end def set_contestant @contestant = Contestant.find(params[:id]) end def set_completions @completions = @contestant.completions.order(:time_seconds) end def contestant_params params.expect(contestant: [ :email, :name ]) end def update_contestant_categories @contestant.categories.clear @contest.categories.each do |category| logger.info(params[:contestant]["category_#{category.id}".to_sym] == "1") if params[:contestant].key?("category_#{category.id}".to_sym) && params[:contestant]["category_#{category.id}".to_sym] == "1" @contestant.categories << category end end @contestant.save 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 completion_params params.expect(completion: [ :display_time_from_start, :completed, :missing_pieces, :remaining_pieces, :puzzle_id, :code ]) end end