Add public scoreboard slug & URL
Some checks are pending
CI / scan_ruby (push) Waiting to run
CI / scan_js (push) Waiting to run
CI / lint (push) Waiting to run
CI / test (push) Waiting to run

This commit is contained in:
sto 2025-03-22 18:21:13 +01:00
parent d47ebf22ab
commit 9a2a3a6f33
10 changed files with 31 additions and 8 deletions

View File

@ -69,6 +69,6 @@ class ContestsController < ApplicationController
end end
def contest_params def contest_params
params.expect(contest: [ :name, :team, :allow_registration ]) params.expect(contest: [ :name, :team, :allow_registration, :slug ])
end end
end end

View File

@ -1,13 +1,12 @@
class SessionsController < ApplicationController class SessionsController < ApplicationController
allow_unauthenticated_access only: %i[ new create ] allow_unauthenticated_access only: %i[ new create ]
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_url, alert: "Try again later." } rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_url, alert: "Try again later." }
before_action :skip_authorization
def new def new
skip_authorization
end end
def create def create
skip_authorization
if user = User.authenticate_by(params.permit(:email_address, :password)) if user = User.authenticate_by(params.permit(:email_address, :password))
start_new_session_for user start_new_session_for user
redirect_to after_authentication_url redirect_to after_authentication_url

View File

@ -5,6 +5,7 @@
# id :integer not null, primary key # id :integer not null, primary key
# allow_registration :boolean default(FALSE) # allow_registration :boolean default(FALSE)
# name :string # name :string
# slug :string
# team :boolean default(FALSE) # team :boolean default(FALSE)
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
@ -24,4 +25,7 @@ class Contest < ApplicationRecord
has_many :completions, dependent: :destroy has_many :completions, dependent: :destroy
has_many :contestants, dependent: :destroy has_many :contestants, dependent: :destroy
has_many :puzzles, dependent: :destroy has_many :puzzles, dependent: :destroy
validates :name, presence: true
validates :slug, presence: true, format: { with: /\A(\w|-)*\z/, message: 'Only alphanumeric characters, "-" and "_" allowed.' }
end end

View File

@ -4,6 +4,12 @@
.form-floating .form-floating
= form.text_field :name, autocomplete: "off", class: "form-control" = form.text_field :name, autocomplete: "off", class: "form-control"
= form.label :name, class: "required" = form.label :name, class: "required"
.row.mb-3
.col
.form-floating
= form.text_field :slug, autocomplete: "off", class: "form-control"
= form.label :slug, class: "required"
.form-text This will be used for building the public scoreboard URL: https://puzzle-scoreboard.org/public/&lt;slug&gt;.
.row.mb-3 .row.mb-3
.col .col
.form-check.form-switch .form-check.form-switch

View File

@ -1,4 +1,4 @@
.row.mb-2 .row.mb-4
.col .col
css: css:
.badges { margin-top: -18px; position: absolute; } .badges { margin-top: -18px; position: absolute; }
@ -6,10 +6,16 @@
- @badges.each do |badge| - @badges.each do |badge|
span.badge.text-bg-info.me-2 span.badge.text-bg-info.me-2
= badge = badge
.row.mb-4
.col
.float-end .float-end
a.btn.btn-primary href=edit_contest_path(@contest) a.btn.btn-primary href=edit_contest_path(@contest)
| Edit contest | Edit contest
p
|> Public scoreboard:
= link_to root_url + "public/#{@contest.slug}"
.row.mb-4 .row.mb-4
.col-6 .col-6
.row .row

View File

@ -2,9 +2,9 @@ ActionView::Base.field_error_proc = proc do |html_tag, instance|
if html_tag.include? "<label" if html_tag.include? "<label"
appended_html = "" appended_html = ""
if instance.error_message.is_a?(Array) if instance.error_message.is_a?(Array)
appended_html = "<div class='error-message form-text'>#{instance.error_message.map(&:humanize).uniq.join(", ")}</div>" appended_html = "<div class='error-message form-text'>#{instance.error_message.map(&:capitalize).uniq.join(", ")}</div>"
else else
appended_html = "<div class='error-message form-text'>#{instance.error_message.humanize}</div>" appended_html = "<div class='error-message form-text'>#{instance.error_message.capitalize}</div>"
end end
html_tag + appended_html.html_safe html_tag + appended_html.html_safe
else else

View File

@ -0,0 +1,5 @@
class AddSlugToContest < ActiveRecord::Migration[8.0]
def change
add_column :contests, :slug, :string
end
end

3
db/schema.rb generated
View File

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_03_22_071308) do ActiveRecord::Schema[8.0].define(version: 2025_03_22_164205) do
create_table "active_storage_attachments", force: :cascade do |t| create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false t.string "name", null: false
t.string "record_type", null: false t.string "record_type", null: false
@ -67,6 +67,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_22_071308) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.boolean "team", default: false t.boolean "team", default: false
t.boolean "allow_registration", default: false t.boolean "allow_registration", default: false
t.string "slug"
t.index ["user_id"], name: "index_contests_on_user_id" t.index ["user_id"], name: "index_contests_on_user_id"
end end

View File

@ -7,6 +7,7 @@
# id :integer not null, primary key # id :integer not null, primary key
# allow_registration :boolean default(FALSE) # allow_registration :boolean default(FALSE)
# name :string # name :string
# slug :string
# team :boolean default(FALSE) # team :boolean default(FALSE)
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null

View File

@ -5,6 +5,7 @@
# id :integer not null, primary key # id :integer not null, primary key
# allow_registration :boolean default(FALSE) # allow_registration :boolean default(FALSE)
# name :string # name :string
# slug :string
# team :boolean default(FALSE) # team :boolean default(FALSE)
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null