diff --git a/app/controllers/contests_controller.rb b/app/controllers/contests_controller.rb index 9d49c32..6c3e9c3 100644 --- a/app/controllers/contests_controller.rb +++ b/app/controllers/contests_controller.rb @@ -101,7 +101,7 @@ class ContestsController < ApplicationController def offline_new @contest = Contest.find_by(slug: params[:id]) - unless @contest && @contest.public + unless @contest && @contest.offline_form skip_authorization not_found and return end @@ -127,7 +127,7 @@ class ContestsController < ApplicationController end def contest_params - params.expect(contest: [ :lang, :name, :public, :team, :allow_registration ]) + params.expect(contest: [ :lang, :name, :offline_form, :public, :team, :allow_registration ]) end def filter_contestants_per_category diff --git a/app/models/contest.rb b/app/models/contest.rb index 45cb301..7d38812 100644 --- a/app/models/contest.rb +++ b/app/models/contest.rb @@ -6,6 +6,7 @@ # allow_registration :boolean default(FALSE) # lang :string default("en") # name :string +# offline_form :boolean default(FALSE) # public :boolean default(FALSE) # slug :string # team :boolean default(FALSE) diff --git a/app/views/contests/_form.html.slim b/app/views/contests/_form.html.slim index 85b7c66..8881b12 100644 --- a/app/views/contests/_form.html.slim +++ b/app/views/contests/_form.html.slim @@ -15,6 +15,11 @@ h4.mt-5 = t("contests.form.general") .form-check.form-switch = form.check_box :public, class: "form-check-input" = form.label :public + .row.mb-3 + .col + .form-check.form-switch + = form.check_box :offline_form, class: "form-check-input" + = form.label :offline_form .row.mb-3 .col .form-check.form-switch diff --git a/app/views/contests/show.html.slim b/app/views/contests/show.html.slim index e784e01..12803b4 100644 --- a/app/views/contests/show.html.slim +++ b/app/views/contests/show.html.slim @@ -20,6 +20,12 @@ javascript: - else a.btn.btn-success.disabled = t("contests.show.public_scoreboard_disabled") + - if @contest.offline_form + a.ms-3.btn.btn-success href="/public/#{@contest.slug}/offline" + = t("contests.show.open_offline_form") + - else + a.ms-3.btn.btn-success.disabled + = t("contests.show.offline_form_disabled") button.btn.btn-success.ms-3 onclick="copyExtensionUrlToClipboard()" css: button > svg { diff --git a/config/locales/en.yml b/config/locales/en.yml index ace9a3e..04a90ba 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -53,6 +53,8 @@ en: contest: lang: Language for the public scoreboard name: Name + offline_form: Enable the offline participation form + offline_form_description: Offline participants will have to fill the form by providing an image taken of the undone puzzle, and validate their finish time with an upload of an image of the completed puzzle public: Enable the public scoreboard team: Team contest team_description: For UI display purposes mainly @@ -162,7 +164,9 @@ en: add_participant: Add participant add_puzzle: Add puzzle copy_extension_url: Copy the URL for connecting from the browser extension + open_offline_form: Open offline form open_public_scoreboard: Open public scoreboard + offline_form_disabled: The offline form is disabled public_scoreboard_disabled: The public scoreboard is disabled url_copied: URL copied to the clipboard contestants: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 41c6298..f3ad669 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -24,6 +24,8 @@ fr: contest: lang: Langue pour le classement public name: Nom + offline_form: Activer le formulaire de participation hors-ligne + offline_form_description: Les participant.e.s hors-ligne pourront participer en prenant une photo du puzzle non fait, puis valider leur temps avec une photo du puzzle une fois complété public: Activer le classement public team: Concours par équipes team_description: Principalement pour des raisons d'affichage @@ -133,7 +135,9 @@ fr: add_participant: Ajouter un.e participant.e add_puzzle: Ajouter un puzzle copy_extension_url: Copier l'URL pour la connexion depuis l'extension web + open_offline_form: Ouvrir le formulaire hors-ligne open_public_scoreboard: Ouvrir le classement public + offline_form_disabled: Le formulaire hors-ligne n'est pas activé public_scoreboard_disabled: Le classement public n'est pas activé url_copied: L’URL a été copiée dans le presse-papier contestants: diff --git a/db/migrate/20251030092221_add_offline_form_to_contest.rb b/db/migrate/20251030092221_add_offline_form_to_contest.rb new file mode 100644 index 0000000..d4404ed --- /dev/null +++ b/db/migrate/20251030092221_add_offline_form_to_contest.rb @@ -0,0 +1,5 @@ +class AddOfflineFormToContest < ActiveRecord::Migration[8.0] + def change + add_column :contests, :offline_form, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 4218f98..0f4b1a0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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_10_29_155116) do +ActiveRecord::Schema[8.0].define(version: 2025_10_30_092221) do create_table "active_storage_attachments", force: :cascade do |t| t.string "name", null: false t.string "record_type", null: false @@ -92,6 +92,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_10_29_155116) do t.string "slug" t.string "lang", default: "en" t.boolean "public", default: false + t.boolean "offline_form", default: false t.index ["slug"], name: "index_contests_on_slug", unique: true t.index ["user_id"], name: "index_contests_on_user_id" end diff --git a/spec/factories/contests.rb b/spec/factories/contests.rb index f9be5d0..45e5875 100644 --- a/spec/factories/contests.rb +++ b/spec/factories/contests.rb @@ -6,6 +6,7 @@ # allow_registration :boolean default(FALSE) # lang :string default("en") # name :string +# offline_form :boolean default(FALSE) # public :boolean default(FALSE) # slug :string # team :boolean default(FALSE)