Support remaining pieces in completions and scoreboards
This commit is contained in:
@@ -109,6 +109,6 @@ class CompletionsController < ApplicationController
|
||||
end
|
||||
|
||||
def completion_params
|
||||
params.expect(completion: [ :display_time_from_start, :contestant_id, :message_id, :puzzle_id ])
|
||||
params.expect(completion: [ :display_time_from_start, :remaining_pieces, :contestant_id, :message_id, :puzzle_id ])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,7 +15,12 @@ class ContestsController < ApplicationController
|
||||
@title = I18n.t("contests.show.title", name: @contest.name)
|
||||
@action_name = t("helpers.buttons.edit")
|
||||
@action_path = edit_contest_path(@contest)
|
||||
@contestants = @contest.contestants.sort_by { |contestant| [ -contestant.completions.size, contestant.time_seconds ] }
|
||||
@contestants = @contest.contestants.sort_by { |contestant| [
|
||||
-contestant.completions.where(remaining_pieces: nil).size,
|
||||
(contestant.completions.where(remaining_pieces: nil).size == @contest.puzzles.length ? 1 : 0) * contestant.time_seconds,
|
||||
contestant.completions.size > 0 && contestant.completions[-1].remaining_pieces ? contestant.completions[-1].remaining_pieces : 1000000,
|
||||
contestant.time_seconds
|
||||
] }
|
||||
filter_contestants_per_category
|
||||
@puzzles = @contest.puzzles.order(:id)
|
||||
@messages = @contest.messages.order(:time_seconds)
|
||||
@@ -77,7 +82,12 @@ class ContestsController < ApplicationController
|
||||
I18n.locale = @contest.lang
|
||||
|
||||
@title = I18n.t("contests.scoreboard.title", name: @contest.name)
|
||||
@contestants = @contest.contestants.sort_by { |contestant| [ -contestant.completions.size, contestant.time_seconds ] }
|
||||
@contestants = @contest.contestants.sort_by { |contestant| [
|
||||
-contestant.completions.where(remaining_pieces: nil).size,
|
||||
(contestant.completions.where(remaining_pieces: nil).size == @contest.puzzles.length ? 1 : 0) * contestant.time_seconds,
|
||||
contestant.completions.size > 0 && contestant.completions[-1].remaining_pieces ? contestant.completions[-1].remaining_pieces : 1000000,
|
||||
contestant.time_seconds
|
||||
] }
|
||||
filter_contestants_per_category
|
||||
@puzzles = @contest.puzzles.order(:id)
|
||||
@action_name = t("helpers.buttons.refresh")
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
# id :integer not null, primary key
|
||||
# display_relative_time :string
|
||||
# display_time_from_start :string
|
||||
# remaining_pieces :integer
|
||||
# time_seconds :integer
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
@@ -34,10 +35,25 @@ class Completion < ApplicationRecord
|
||||
belongs_to :message, optional: true
|
||||
|
||||
before_save :add_time_seconds
|
||||
before_save :nullify_display_time
|
||||
|
||||
validates :display_time_from_start, presence: true, format: { with: /\A(((\d\d|\d):\d\d|\d\d|\d):\d\d|\d\d|\d)\z/ }
|
||||
validates :display_time_from_start, presence: true, format: { with: /\A(((\d\d|\d):\d\d|\d\d|\d):\d\d|\d\d|\d)\z/ }, if: -> { remaining_pieces == nil }
|
||||
validates :contestant_id, uniqueness: { scope: :puzzle }, if: -> { contest.puzzles.size == 1 }
|
||||
validates :puzzle_id, uniqueness: { scope: :contestant }, if: -> { contest.puzzles.size > 1 }
|
||||
validate :remaining_pieces_is_correct
|
||||
|
||||
def remaining_pieces_is_correct
|
||||
if self.remaining_pieces && self.remaining_pieces > self.puzzle.pieces
|
||||
errors.add(:remaining_pieces, "Cannot be greater than the number of pieces for this puzzle")
|
||||
end
|
||||
end
|
||||
|
||||
def nullify_display_time
|
||||
if self.remaining_pieces
|
||||
self.display_time_from_start = nil
|
||||
self.display_relative_time = nil
|
||||
end
|
||||
end
|
||||
|
||||
def add_time_seconds
|
||||
arr = display_time_from_start.split(":")
|
||||
|
||||
@@ -9,14 +9,9 @@
|
||||
= @message.author
|
||||
br
|
||||
= @message.text
|
||||
.row
|
||||
.col
|
||||
h4 = t("completions.singular").capitalize
|
||||
.row.mb-3
|
||||
.row
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :display_time_from_start, autocomplete: "off", class: "form-control"
|
||||
= form.label :display_time_from_start, class: "required"
|
||||
h4 = t("completions.singular").capitalize
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
@@ -36,6 +31,18 @@
|
||||
= form.hidden_field :puzzle_id, value: @puzzles.first.id
|
||||
- else
|
||||
= form.hidden_field :puzzle_id
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :display_time_from_start, autocomplete: "off", class: "form-control"
|
||||
= form.label :display_time_from_start, class: "required"
|
||||
.row.mb-3
|
||||
.col
|
||||
.form-floating
|
||||
= form.text_field :remaining_pieces, autocomplete: "off", class: "form-control"
|
||||
= form.label :remaining_pieces
|
||||
.form-text
|
||||
= t("activerecord.attributes.completion.remaining_pieces_description")
|
||||
.row
|
||||
.col
|
||||
= form.submit submit_text, class: "btn btn-primary"
|
||||
@@ -44,6 +44,8 @@
|
||||
- else
|
||||
th scope="col"
|
||||
= t("activerecord.attributes.completion.display_time")
|
||||
th scope="col"
|
||||
= t("activerecord.attributes.completion.remaining_pieces")
|
||||
th scope="col"
|
||||
= t("activerecord.attributes.completion.puzzle")
|
||||
tbody
|
||||
@@ -54,6 +56,8 @@
|
||||
- if @contest.puzzles.size > 1
|
||||
td
|
||||
= completion.display_relative_time
|
||||
td
|
||||
= completion.remaining_pieces
|
||||
td
|
||||
- if !completion.puzzle.brand.blank?
|
||||
| #{completion.puzzle.name} - #{completion.puzzle.brand}
|
||||
|
||||
@@ -42,13 +42,13 @@ css:
|
||||
= contestant.name
|
||||
- if @contest.puzzles.size > 1
|
||||
td
|
||||
= contestant.completions.length
|
||||
= contestant.completions.where(remaining_pieces: nil).length
|
||||
td style="position: relative"
|
||||
- if index > 0 && contestant.time_seconds > 0
|
||||
- if index > 0 && contestant.time_seconds > 0 && contestant.completions.where(remaining_pieces: nil).size > 0
|
||||
.relative-time style="position:absolute; margin: 1px 0 0 64px; font-size: 14px; color: grey"
|
||||
|> +
|
||||
= display_time(contestant.time_seconds - @contestants[index - 1].time_seconds)
|
||||
= contestant.display_time
|
||||
= contestant.completions.size > 0 && contestant.completions[-1].remaining_pieces ? "#{contestant.completions.map{|completion| completion.puzzle.pieces}.sum - contestant.completions[-1].remaining_pieces}p" : contestant.display_time
|
||||
.col-1
|
||||
.col-5
|
||||
- @contest.puzzles.each do |puzzle|
|
||||
@@ -89,6 +89,6 @@ css:
|
||||
= contestant.name
|
||||
- if @contest.puzzles.size > 1
|
||||
td
|
||||
= contestant.completions.length
|
||||
= contestant.completions.where(remaining_pieces: nil).length
|
||||
td
|
||||
= contestant.display_time
|
||||
= contestant.completions.size > 0 && contestant.completions[-1].remaining_pieces ? "#{contestant.completions.map{|completion| completion.puzzle.pieces}.sum - contestant.completions[-1].remaining_pieces}p" : contestant.display_time
|
||||
@@ -85,9 +85,9 @@ javascript:
|
||||
td
|
||||
= contestant.name
|
||||
td
|
||||
= contestant.completions.length
|
||||
= contestant.completions.where(remaining_pieces: nil).length
|
||||
td
|
||||
= contestant.display_time
|
||||
= contestant.completions.size > 0 && contestant.completions[-1].remaining_pieces ? "#{contestant.completions.map{|completion| completion.puzzle.pieces}.sum - contestant.completions[-1].remaining_pieces}p" : contestant.display_time
|
||||
td
|
||||
a.btn.btn-sm.btn-secondary href=edit_contest_contestant_path(@contest, contestant)
|
||||
= t("helpers.buttons.open")
|
||||
|
||||
@@ -48,6 +48,8 @@ en:
|
||||
display_time_from_start: Time since start
|
||||
display_relative_time: Time for this puzzle
|
||||
puzzle: Puzzle
|
||||
remaining_pieces: Remaining pieces
|
||||
remaining_pieces_description: When this field is filled, the above time will not be taken into account
|
||||
contest:
|
||||
lang: Language for the public scoreboard
|
||||
name: Name
|
||||
|
||||
@@ -19,6 +19,8 @@ fr:
|
||||
display_time_from_start: Temps depuis le début
|
||||
display_relative_time: Temps pour ce puzzle
|
||||
puzzle: Puzzle
|
||||
remaining_pieces: Nombre de pièces restantes
|
||||
remaining_pieces_description: Si ce champ est rempli, le temps ci-dessus ne sera pas pris en compte
|
||||
contest:
|
||||
lang: Langue pour le classement public
|
||||
name: Nom
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddRemainingPiecesToCompletion < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
add_column :completions, :remaining_pieces, :integer
|
||||
end
|
||||
end
|
||||
3
db/schema.rb
generated
3
db/schema.rb
generated
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_07_14_115208) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_10_28_131431) do
|
||||
create_table "active_storage_attachments", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.string "record_type", null: false
|
||||
@@ -64,6 +64,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_07_14_115208) do
|
||||
t.string "display_time_from_start"
|
||||
t.string "display_relative_time"
|
||||
t.integer "message_id"
|
||||
t.integer "remaining_pieces"
|
||||
t.index ["contest_id"], name: "index_completions_on_contest_id"
|
||||
t.index ["contestant_id"], name: "index_completions_on_contestant_id"
|
||||
t.index ["message_id"], name: "index_completions_on_message_id"
|
||||
|
||||
Reference in New Issue
Block a user