Files
puzzle-scoreboard/app/controllers/contestants_controller.rb
sto b43a801e3c
Some checks failed
CI / scan_ruby (push) Failing after 18s
CI / scan_js (push) Successful in 13s
CI / lint (push) Successful in 15s
CI / test (push) Failing after 42s
Generate QR codes when not present and asked for
2025-11-20 15:50:50 +01:00

225 lines
6.3 KiB
Ruby

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 ]
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
logger.info("Email")
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=export.csv"
end
end
end
def generate_qrcodes
authorize @contest
@contest.contestants.each do |contestant|
if !contestant.qrcode.present?
contestant.public_generate_qrcode
contestant.save
end
end
@contestants = @contest.contestants.sort_by { |contestant| contestant.name }
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
@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
@completion = Completion.new(completion_params)
@completion.contest = @contest
@completion.contestant = @contestant
if @completion.save
extend_completions!(@completion.contestant)
redirect_to "/public/p/#{params[:token]}/updated"
else
@puzzles = @contest.puzzles
@public = true
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
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 ])
end
end