From 3dd153d587c5a31f8c3af52b55ae289ec54febd4 Mon Sep 17 00:00:00 2001 From: sto Date: Tue, 18 Nov 2025 11:46:02 +0100 Subject: [PATCH] Require contest durations, prefill end times for unfinished puzzles & allow to modify them --- app/controllers/contests_controller.rb | 5 ++++- app/models/completion.rb | 9 +-------- app/models/contest.rb | 2 +- app/views/completions/_form.html.slim | 11 ++++------- app/views/contests/new.html.slim | 6 ++++++ app/views/layouts/authenticated.html.slim | 2 +- config/locales/en.yml | 1 + config/locales/fr.yml | 1 + 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/app/controllers/contests_controller.rb b/app/controllers/contests_controller.rb index 689c7e9..d2bb182 100644 --- a/app/controllers/contests_controller.rb +++ b/app/controllers/contests_controller.rb @@ -57,6 +57,7 @@ class ContestsController < ApplicationController @contest = Contest.new @title = I18n.t("contests.new.title") + @nonav = true end def create @@ -69,6 +70,8 @@ class ContestsController < ApplicationController 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 @@ -203,7 +206,7 @@ class ContestsController < ApplicationController end def new_contest_params - params.expect(contest: [ :name ]) + params.expect(contest: [ :name, :duration ]) end def settings_general_params diff --git a/app/models/completion.rb b/app/models/completion.rb index 56721a4..f632798 100644 --- a/app/models/completion.rb +++ b/app/models/completion.rb @@ -68,11 +68,7 @@ class Completion < ApplicationRecord self.time_seconds = arr[0].to_i end else - if self.contest.duration_seconds.present? - self.time_seconds = self.contest.duration_seconds - else - self.time_seconds = 2 * 3600 - end + self.time_seconds = self.contest.duration_seconds self.display_time_from_start = display_time(self.time_seconds) end end @@ -82,9 +78,6 @@ class Completion < ApplicationRecord self.remaining_pieces = nil else self.missing_pieces = nil - if !self.offline.present? - self.display_time_from_start = nil - end end end diff --git a/app/models/contest.rb b/app/models/contest.rb index 7464065..9f17ca2 100644 --- a/app/models/contest.rb +++ b/app/models/contest.rb @@ -44,7 +44,7 @@ class Contest < ApplicationRecord validates :name, presence: true validates :lang, inclusion: { in: Languages::AVAILABLE_LANGUAGES.map { |lang| lang[:id] } } validates :ranking_mode, inclusion: { in: Ranking::AVAILABLE_RANKING_MODES.map { |lang| lang[:id] } } - validates :duration, format: { with: /\A(\d\d:\d\d|\d:\d\d)\z/ }, if: -> { duration.present? } + validates :duration, presence: true, format: { with: /\A(\d\d:\d\d|\d:\d\d)\z/ } generates_token_for :token diff --git a/app/views/completions/_form.html.slim b/app/views/completions/_form.html.slim index a9511d6..3c61c48 100644 --- a/app/views/completions/_form.html.slim +++ b/app/views/completions/_form.html.slim @@ -43,19 +43,19 @@ const missingPiecesEl = document.getElementById('missing_pieces'); const remainingPiecesEl = document.getElementById('remaining_pieces'); if (e.target.checked) { - timeEl.style.display = 'block'; + timeEl.value = '#{@completion.display_time_from_start}'; missingPiecesEl.style.display = 'block'; remainingPiecesEl.style.display = 'none'; } else { - timeEl.style.display = 'none'; + timeEl.value = '#{display_time(@contest.duration_seconds)}'; missingPiecesEl.style.display = 'none'; remainingPiecesEl.style.display = 'block'; } }) - .row.mb-3 id="time" + .row.mb-3 .col .form-floating - = form.text_field :display_time_from_start, autocomplete: "off", class: "form-control" + = 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 @@ -69,15 +69,12 @@ = form.label :remaining_pieces javascript: completedEl = document.getElementById('completion_completed'); - timeEl = document.getElementById('time'); missingPiecesEl = document.getElementById('missing_pieces'); remainingPiecesEl = document.getElementById('remaining_pieces'); if (completedEl.checked) { - timeEl.style.display = 'block'; missingPiecesEl.style.display = 'block'; remainingPiecesEl.style.display = 'none'; } else { - timeEl.style.display = 'none'; missingPiecesEl.style.display = 'none'; remainingPiecesEl.style.display = 'block'; } diff --git a/app/views/contests/new.html.slim b/app/views/contests/new.html.slim index fe4fea8..2834e52 100644 --- a/app/views/contests/new.html.slim +++ b/app/views/contests/new.html.slim @@ -4,6 +4,12 @@ .form-floating = form.text_field :name, autocomplete: "off", class: "form-control" = form.label :name, class: "required" + .row.mb-3 + .col + .form-floating + = form.text_field :duration, autocomplete: "off", class: "form-control" + = form.label :duration, class: "required" + .form-text = t("activerecord.attributes.contest.duration_description") .row.mt-4 .col = form.submit t("helpers.buttons.create"), class: "btn btn-primary" \ No newline at end of file diff --git a/app/views/layouts/authenticated.html.slim b/app/views/layouts/authenticated.html.slim index 33558c2..3c3d51d 100644 --- a/app/views/layouts/authenticated.html.slim +++ b/app/views/layouts/authenticated.html.slim @@ -52,7 +52,7 @@ html - else = @title - - if @contest && active_page("/public") != "active" && active_page("/contests/new") != "active" && active_page("/contests/create") != "active" && active_page("/contests") == "active" + - if @contest && active_page("/contests") == "active" && !@nonav = render "contest_nav" = yield \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 529900c..d9cd44d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -117,6 +117,7 @@ en: contest: attributes: duration: + blank: Must be filled invalid: Invalid duration name: blank: The contest name cannot be empty diff --git a/config/locales/fr.yml b/config/locales/fr.yml index a166f44..cb6499c 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -88,6 +88,7 @@ fr: contest: attributes: duration: + blank: Obligatoire invalid: Durée invalide name: blank: Le nom du concours ne peut pas être vide