Add judges codes
This commit is contained in:
@@ -24,7 +24,7 @@ class CompletionsController < ApplicationController
|
||||
authorize @contest
|
||||
|
||||
@completion = Completion.new(completion_params)
|
||||
@completion.contest = @contet
|
||||
@completion.contest = @contest
|
||||
if @completion.save
|
||||
extend_completions!(@completion.contestant)
|
||||
if @contestant && !params[:completion].key?(:message_id)
|
||||
|
||||
@@ -123,12 +123,6 @@ class ContestantsController < ApplicationController
|
||||
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
|
||||
|
||||
@@ -140,6 +134,7 @@ class ContestantsController < ApplicationController
|
||||
not_found and return
|
||||
end
|
||||
@contest = @contestant.contest
|
||||
I18n.locale = @contest.lang
|
||||
@puzzles = @contest.puzzles
|
||||
@completion = Completion.new
|
||||
@completion.completed = true
|
||||
@@ -156,16 +151,24 @@ class ContestantsController < ApplicationController
|
||||
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
|
||||
@@ -177,6 +180,7 @@ class ContestantsController < ApplicationController
|
||||
if !@contestant
|
||||
not_found and return
|
||||
end
|
||||
I18n.locale = @contestant.contest.lang
|
||||
end
|
||||
|
||||
private
|
||||
@@ -219,6 +223,6 @@ class ContestantsController < ApplicationController
|
||||
end
|
||||
|
||||
def completion_params
|
||||
params.expect(completion: [ :display_time_from_start, :completed, :missing_pieces, :remaining_pieces, :puzzle_id ])
|
||||
params.expect(completion: [ :display_time_from_start, :completed, :missing_pieces, :remaining_pieces, :puzzle_id, :code ])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -210,7 +210,7 @@ class ContestsController < ApplicationController
|
||||
end
|
||||
|
||||
def settings_general_params
|
||||
params.expect(contest: [ :lang, :name, :duration, :public, :ranking_mode, :team, :allow_registration ])
|
||||
params.expect(contest: [ :lang, :name, :duration, :public, :ranking_mode, :team, :allow_registration, :code ])
|
||||
end
|
||||
|
||||
def settings_offline_params
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Table name: completions
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# code :string
|
||||
# completed :boolean
|
||||
# display_relative_time :string
|
||||
# display_time_from_start :string
|
||||
@@ -50,10 +51,11 @@ class Completion < ApplicationRecord
|
||||
validates :puzzle_id, uniqueness: { scope: :contestant }, if: -> { contest.puzzles.size > 1 }
|
||||
validates :remaining_pieces, numericality: { only_integer: true }, if: -> { remaining_pieces.present? }
|
||||
validate :remaining_pieces_is_correct, if: -> { remaining_pieces.present? }
|
||||
validate :contest_code_is_correct, if: -> { code.present? }
|
||||
|
||||
def remaining_pieces_is_correct
|
||||
if self.remaining_pieces > self.puzzle.pieces
|
||||
errors.add(:remaining_pieces, "Cannot be greater than the number of pieces for this puzzle")
|
||||
errors.add(:remaining_pieces, I18n.t("activerecord.errors.models.completion.attributes.remaining_pieces.too_large"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -92,4 +94,10 @@ class Completion < ApplicationRecord
|
||||
self.projected_time = assembled_time + Integer(self.remaining_pieces.to_f / pieces_per_second)
|
||||
end
|
||||
end
|
||||
|
||||
def contest_code_is_correct
|
||||
if self.code != self.contest.code
|
||||
errors.add(:code, I18n.t("activerecord.errors.models.completion.attributes.code.mismatch"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# allow_registration :boolean default(FALSE)
|
||||
# code :string
|
||||
# duration :string
|
||||
# duration_seconds :integer
|
||||
# lang :string default("en")
|
||||
|
||||
@@ -43,10 +43,6 @@ class Contestant < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def public_generate_qrcode
|
||||
self.generate_qrcode
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def initialize_time_seconds_if_empty
|
||||
|
||||
@@ -1,88 +1,101 @@
|
||||
= form_with model: completion, url: url, method: method do |form|
|
||||
- if @message
|
||||
= form.hidden_field :message_id, value: @message.id
|
||||
.row.mb-3
|
||||
- if @public && @puzzles.length == @contestant.completions.length
|
||||
h4
|
||||
= t("completions.form.validate_name", name: @contestant.name)
|
||||
.mt-3.alert.alert-warning
|
||||
= t("completions.form.all_finished", name: @contestant.name)
|
||||
- else
|
||||
= form_with model: completion, url: url, method: method do |form|
|
||||
- if @message
|
||||
= form.hidden_field :message_id, value: @message.id
|
||||
.row.mb-3
|
||||
.col
|
||||
h4 = t("messages.singular").capitalize
|
||||
.alert.alert-secondary
|
||||
b
|
||||
= @message.author
|
||||
br
|
||||
= @message.text
|
||||
.row.mb-2
|
||||
.col
|
||||
h4 = t("messages.singular").capitalize
|
||||
.alert.alert-secondary
|
||||
b
|
||||
= @message.author
|
||||
br
|
||||
= @message.text
|
||||
.row.mb-2
|
||||
.col
|
||||
h4
|
||||
- if @public
|
||||
= t("completions.form.validate_name", name: @contestant.name)
|
||||
- else
|
||||
= t("completions.singular").capitalize
|
||||
- if @contestants.present?
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.select :contestant_id, @contestants.map { |contestant| [contestant.form_name, contestant.id] }, {}, class: "form-select"
|
||||
= form.label :contestant_id
|
||||
- if @closest_contestant
|
||||
javascript:
|
||||
el = document.querySelector('select[name="completion[contestant_id]"]');
|
||||
el.value = "#{@closest_contestant.id}"
|
||||
- if @puzzles.size > 1
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.select :puzzle_id, @puzzles.map { |puzzle| ["#{puzzle.name} - #{puzzle.brand}", puzzle.id] }, {}, class: "form-select"
|
||||
= form.label :puzzle_id
|
||||
- elsif @puzzles.size == 1
|
||||
= form.hidden_field :puzzle_id, value: @puzzles.first.id
|
||||
- else
|
||||
= form.hidden_field :puzzle_id
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-check.form-switch
|
||||
= form.check_box :completed, class: "form-check-input"
|
||||
= form.label :completed
|
||||
h4
|
||||
- if @public
|
||||
= t("completions.form.validate_name", name: @contestant.name)
|
||||
- else
|
||||
= t("completions.singular").capitalize
|
||||
- if @contestants.present?
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.select :contestant_id, @contestants.map { |contestant| [contestant.form_name, contestant.id] }, {}, class: "form-select"
|
||||
= form.label :contestant_id
|
||||
- if @closest_contestant
|
||||
javascript:
|
||||
completedEl = document.getElementById('completion_completed');
|
||||
completedEl.addEventListener('change', (e) => {
|
||||
const timeEl = document.getElementById('time');
|
||||
const missingPiecesEl = document.getElementById('missing_pieces');
|
||||
const remainingPiecesEl = document.getElementById('remaining_pieces');
|
||||
if (e.target.checked) {
|
||||
timeEl.value = '#{@completion.display_time_from_start}';
|
||||
missingPiecesEl.style.display = 'block';
|
||||
remainingPiecesEl.style.display = 'none';
|
||||
} else {
|
||||
timeEl.value = '#{display_time(@contest.duration_seconds)}';
|
||||
missingPiecesEl.style.display = 'none';
|
||||
remainingPiecesEl.style.display = 'block';
|
||||
}
|
||||
})
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :display_time_from_start, autocomplete: "off", class: "form-control", id: "time"
|
||||
= form.label :display_time_from_start, class: "required"
|
||||
.row.mb-3 id="missing_pieces"
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :missing_pieces, autocomplete: "off", class: "form-control"
|
||||
= form.label :missing_pieces
|
||||
.row.mb-3 id="remaining_pieces" style="display: none;"
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :remaining_pieces, autocomplete: "off", class: "form-control"
|
||||
= form.label :remaining_pieces
|
||||
javascript:
|
||||
completedEl = document.getElementById('completion_completed');
|
||||
missingPiecesEl = document.getElementById('missing_pieces');
|
||||
remainingPiecesEl = document.getElementById('remaining_pieces');
|
||||
if (completedEl.checked) {
|
||||
missingPiecesEl.style.display = 'block';
|
||||
remainingPiecesEl.style.display = 'none';
|
||||
} else {
|
||||
missingPiecesEl.style.display = 'none';
|
||||
remainingPiecesEl.style.display = 'block';
|
||||
}
|
||||
.row
|
||||
.col
|
||||
= form.submit submit_text, class: "btn btn-primary"
|
||||
el = document.querySelector('select[name="completion[contestant_id]"]');
|
||||
el.value = "#{@closest_contestant.id}"
|
||||
- if @puzzles.size > 1
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.select :puzzle_id, @puzzles.map { |puzzle| ["#{puzzle.name} - #{puzzle.brand}", puzzle.id] }, {}, class: "form-select"
|
||||
= form.label :puzzle_id
|
||||
- elsif @puzzles.size == 1
|
||||
= form.hidden_field :puzzle_id, value: @puzzles.first.id
|
||||
- else
|
||||
= form.hidden_field :puzzle_id
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-check.form-switch
|
||||
= form.check_box :completed, class: "form-check-input"
|
||||
= form.label :completed
|
||||
javascript:
|
||||
completedEl = document.getElementById('completion_completed');
|
||||
completedEl.addEventListener('change', (e) => {
|
||||
const timeEl = document.getElementById('time');
|
||||
const missingPiecesEl = document.getElementById('missing_pieces');
|
||||
const remainingPiecesEl = document.getElementById('remaining_pieces');
|
||||
if (e.target.checked) {
|
||||
timeEl.value = '#{@completion.display_time_from_start}';
|
||||
missingPiecesEl.style.display = 'block';
|
||||
remainingPiecesEl.style.display = 'none';
|
||||
} else {
|
||||
timeEl.value = '#{display_time(@contest.duration_seconds)}';
|
||||
missingPiecesEl.style.display = 'none';
|
||||
remainingPiecesEl.style.display = 'block';
|
||||
}
|
||||
})
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :display_time_from_start, autocomplete: "off", class: "form-control", id: "time"
|
||||
= form.label :display_time_from_start, class: "required"
|
||||
.row.mb-3 id="missing_pieces"
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :missing_pieces, autocomplete: "off", class: "form-control"
|
||||
= form.label :missing_pieces
|
||||
.row.mb-3 id="remaining_pieces" style="display: none;"
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :remaining_pieces, autocomplete: "off", class: "form-control"
|
||||
= form.label :remaining_pieces
|
||||
javascript:
|
||||
completedEl = document.getElementById('completion_completed');
|
||||
missingPiecesEl = document.getElementById('missing_pieces');
|
||||
remainingPiecesEl = document.getElementById('remaining_pieces');
|
||||
if (completedEl.checked) {
|
||||
missingPiecesEl.style.display = 'block';
|
||||
remainingPiecesEl.style.display = 'none';
|
||||
} else {
|
||||
missingPiecesEl.style.display = 'none';
|
||||
remainingPiecesEl.style.display = 'block';
|
||||
}
|
||||
- if @public
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :code, autocomplete: "off", class: "form-control"
|
||||
= form.label :code
|
||||
= t("completions.form.code")
|
||||
.row
|
||||
.col
|
||||
= form.submit submit_text, class: "btn btn-primary"
|
||||
@@ -1,12 +1,22 @@
|
||||
.row.mb-4 style="height: calc(100vh - 280px)"
|
||||
.col.d-flex.flex-column style="height: 100%"
|
||||
.d-flex.flex-column style="overflow-y: auto"
|
||||
- for row in 0..((@contestants.length - 1) / 4)
|
||||
.mt-4.d-flex.flex-row
|
||||
- for col in 0..3
|
||||
- if row * 4 + col < @contestants.length
|
||||
.d-flex.flex-column.ms-5 style="align-items: center"
|
||||
= @contestants[row * 4 + col].name
|
||||
- if @contestants[row * 4 + col].qrcode.present?
|
||||
.mt-1 style="width: 200px; height: 200px;"
|
||||
= @contestants[row * 4 + col].qrcode.html_safe
|
||||
- if @contest.code.present?
|
||||
.row.mb-4 style="height: calc(100vh - 280px)"
|
||||
.row
|
||||
.col
|
||||
.alert.alert-info
|
||||
= t("contestants.generate_qrcodes.note")
|
||||
.col.d-flex.flex-column style="height: 100%"
|
||||
.d-flex.flex-column style="overflow-y: auto"
|
||||
- for row in 0..((@contestants.length - 1) / 5)
|
||||
.mt-4.d-flex.flex-row
|
||||
- for col in 0..4
|
||||
- if row * 5 + col < @contestants.length
|
||||
.d-flex.flex-column.ms-5 style="align-items: center"
|
||||
= @contestants[row * 5 + col].name
|
||||
- if @contestants[row * 5 + col].qrcode.present?
|
||||
.mt-1 style="width: 180px; height: 180px;"
|
||||
= @contestants[row * 5 + col].qrcode.html_safe
|
||||
- else
|
||||
.row
|
||||
.col
|
||||
.alert.alert-warning
|
||||
= t("contestants.generate_qrcodes.no_code_note")
|
||||
@@ -20,6 +20,12 @@
|
||||
.form-floating
|
||||
= form.select :ranking_mode, Ranking::AVAILABLE_RANKING_MODES.map { |mode| [ mode[:name], mode[:id] ] }, {}, class: "form-select"
|
||||
= form.label :ranking_mode
|
||||
.row.mt-2.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :code, autocomplete: "off", class: "form-control"
|
||||
= form.label :code, class: "required"
|
||||
.form-text = t("activerecord.attributes.contest.code_description")
|
||||
.row.mt-4.mb-3
|
||||
.col
|
||||
.form-check.form-switch
|
||||
|
||||
Reference in New Issue
Block a user