Messages to completions conversion
This commit is contained in:
parent
e65d639ca6
commit
c4902d85d5
@ -27,8 +27,6 @@ class CompletionsController < ApplicationController
|
|||||||
extend_completions!(@completion.contestant)
|
extend_completions!(@completion.contestant)
|
||||||
redirect_to contest_path(@contest)
|
redirect_to contest_path(@contest)
|
||||||
else
|
else
|
||||||
logger = Logger.new(STDOUT)
|
|
||||||
logger.info(@completion.errors)
|
|
||||||
render :new, status: :unprocessable_entity
|
render :new, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -36,9 +34,7 @@ class CompletionsController < ApplicationController
|
|||||||
def update
|
def update
|
||||||
authorize @contest
|
authorize @contest
|
||||||
|
|
||||||
if params[:contestant_id]
|
@completion.contestant_id = params[:contestant_id] if params[:contestant_id]
|
||||||
@completion.contestant_id = params[:contestant_id]
|
|
||||||
end
|
|
||||||
if @completion.update(completion_params)
|
if @completion.update(completion_params)
|
||||||
extend_completions!(@completion.contestant)
|
extend_completions!(@completion.contestant)
|
||||||
redirect_to @contest
|
redirect_to @contest
|
||||||
@ -74,6 +70,6 @@ class CompletionsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def completion_params
|
def completion_params
|
||||||
params.expect(completion: [ :time_seconds, :contestant_id, :puzzle_id ])
|
params.expect(completion: [ :display_time_from_start, :contestant_id, :puzzle_id ])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -17,7 +17,7 @@ class ContestsController < ApplicationController
|
|||||||
@action_path = edit_contest_path(@contest)
|
@action_path = edit_contest_path(@contest)
|
||||||
@contestants = @contest.contestants.order(:name)
|
@contestants = @contest.contestants.order(:name)
|
||||||
@puzzles = @contest.puzzles.order(:id)
|
@puzzles = @contest.puzzles.order(:id)
|
||||||
@messages = @contest.messages.order(:id)
|
@messages = @contest.messages.order(:time_seconds)
|
||||||
set_badges
|
set_badges
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
class MessagesController < ApplicationController
|
class MessagesController < ApplicationController
|
||||||
|
include CompletionsConcern
|
||||||
|
|
||||||
skip_before_action :verify_authenticity_token, only: %i[ create ]
|
skip_before_action :verify_authenticity_token, only: %i[ create ]
|
||||||
|
|
||||||
before_action :set_contest, only: %i[ destroy ]
|
before_action :set_contest, only: %i[ convert destroy ]
|
||||||
before_action :set_message, only: %i[ destroy ]
|
before_action :set_message, only: %i[ convert destroy ]
|
||||||
|
before_action :set_data, only: %i[ convert ]
|
||||||
|
|
||||||
|
def self.local_prefixes
|
||||||
|
super + [ "completions" ]
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
allow_unauthenticated_access
|
allow_unauthenticated_access
|
||||||
@ -10,7 +17,8 @@ class MessagesController < ApplicationController
|
|||||||
|
|
||||||
@message_params = message_params
|
@message_params = message_params
|
||||||
@contest = Contest.find_by_token_for(:token, params[:token])
|
@contest = Contest.find_by_token_for(:token, params[:token])
|
||||||
@message = Message.new(text: params[:text], time_seconds: params[:time_seconds], contest: @contest)
|
@message = Message.new(text: params[:text], time_seconds: params[:time_seconds],
|
||||||
|
display_time: display_time(params[:time_seconds]), contest: @contest)
|
||||||
if @contest && @message.save
|
if @contest && @message.save
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json { render json: {}, status: 200 }
|
format.json { render json: {}, status: 200 }
|
||||||
@ -22,6 +30,15 @@ class MessagesController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def convert
|
||||||
|
authorize @contest
|
||||||
|
|
||||||
|
@completion = Completion.new()
|
||||||
|
@completion.display_time_from_start = @message.display_time
|
||||||
|
|
||||||
|
render "completions/new"
|
||||||
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
authorize @contest
|
authorize @contest
|
||||||
|
|
||||||
@ -36,10 +53,15 @@ class MessagesController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_message
|
def set_message
|
||||||
@message = Message.find(params[:id])
|
@message = Message.find(params[:message_id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_data
|
||||||
|
@contestants = @contest.contestants
|
||||||
|
@puzzles = @contest.puzzles
|
||||||
end
|
end
|
||||||
|
|
||||||
def message_params
|
def message_params
|
||||||
params.expect(message: [ :text, :time_seconds, :token ])
|
params.expect(message: [ :author, :text, :time_seconds, :token ])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -29,7 +29,17 @@ class Completion < ApplicationRecord
|
|||||||
belongs_to :contestant
|
belongs_to :contestant
|
||||||
belongs_to :puzzle
|
belongs_to :puzzle
|
||||||
|
|
||||||
validates :time_seconds, presence: true
|
before_save :add_time_seconds
|
||||||
validates_numericality_of :time_seconds
|
|
||||||
|
validates :display_time_from_start, presence: true, format: { with: /\A((\d\d|\d):\d\d|\d\d|\d):\d\d\z/ }
|
||||||
validates :puzzle_id, uniqueness: { scope: :contestant }
|
validates :puzzle_id, uniqueness: { scope: :contestant }
|
||||||
|
|
||||||
|
def add_time_seconds
|
||||||
|
arr = display_time_from_start.split(":")
|
||||||
|
if arr.size == 3
|
||||||
|
self.time_seconds = arr[0].to_i * 3600 + arr[1].to_i * 60 + arr[2].to_i
|
||||||
|
elsif arr.size == 2
|
||||||
|
self.time_seconds = arr[0].to_i * 60 + arr[1].to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
# Table name: messages
|
# Table name: messages
|
||||||
#
|
#
|
||||||
# id :integer not null, primary key
|
# id :integer not null, primary key
|
||||||
|
# author :string
|
||||||
|
# display_time :string
|
||||||
# text :string not null
|
# text :string not null
|
||||||
# time_seconds :integer not null
|
# time_seconds :integer not null
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
@ -20,5 +22,6 @@
|
|||||||
class Message < ApplicationRecord
|
class Message < ApplicationRecord
|
||||||
belongs_to :contest
|
belongs_to :contest
|
||||||
|
|
||||||
|
validates :author, presence: true
|
||||||
validates :text, presence: true
|
validates :text, presence: true
|
||||||
end
|
end
|
||||||
|
@ -15,6 +15,10 @@ class ContestPolicy < ApplicationPolicy
|
|||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def convert?
|
||||||
|
record.user.id == user.id || user.admin?
|
||||||
|
end
|
||||||
|
|
||||||
def edit?
|
def edit?
|
||||||
record.user.id == user.id || user.admin?
|
record.user.id == user.id || user.admin?
|
||||||
end
|
end
|
||||||
|
@ -1,9 +1,21 @@
|
|||||||
= form_with model: completion, url: url, method: method do |form|
|
= form_with model: completion, url: url, method: method do |form|
|
||||||
|
- if @message
|
||||||
|
.row.mb-3
|
||||||
|
.col
|
||||||
|
h4 = t("messages.singular").capitalize
|
||||||
|
.alert.alert-secondary
|
||||||
|
b
|
||||||
|
= @message.author
|
||||||
|
br
|
||||||
|
= @message.text
|
||||||
|
.row
|
||||||
|
.col
|
||||||
|
h4 = t("completions.singular").capitalize
|
||||||
.row.mb-3
|
.row.mb-3
|
||||||
.col
|
.col
|
||||||
.form-floating
|
.form-floating
|
||||||
= form.text_field :time_seconds, autocomplete: "off", class: "form-control"
|
= form.text_field :display_time_from_start, autocomplete: "off", class: "form-control"
|
||||||
= form.label :time_seconds, class: "required"
|
= form.label :display_time_from_start, class: "required"
|
||||||
.row.mb-3
|
.row.mb-3
|
||||||
.col
|
.col
|
||||||
.form-floating
|
.form-floating
|
||||||
|
@ -51,17 +51,21 @@
|
|||||||
tr
|
tr
|
||||||
th scope="col"
|
th scope="col"
|
||||||
| Time
|
| Time
|
||||||
|
th scope="col"
|
||||||
|
| Author
|
||||||
th scope="col"
|
th scope="col"
|
||||||
| Text
|
| Text
|
||||||
tbody
|
tbody
|
||||||
- @messages.each do |message|
|
- @messages.each do |message|
|
||||||
tr.align-middle scope="row"
|
tr.align-middle scope="row"
|
||||||
td
|
td
|
||||||
= message.time_seconds
|
= message.display_time
|
||||||
|
td
|
||||||
|
= message.author
|
||||||
td
|
td
|
||||||
= message.text
|
= message.text
|
||||||
td
|
td
|
||||||
a.btn.btn-sm.btn-secondary href="" style="white-space: nowrap;"
|
a.btn.btn-sm.btn-secondary href=contest_message_convert_path(@contest, message) style="white-space: nowrap;"
|
||||||
| Add completion
|
| Add completion
|
||||||
td
|
td
|
||||||
= link_to "Delete", contest_message_path(@contest, message), data: { turbo_method: :delete }, class: "btn btn-sm btn-danger"
|
= link_to "Delete", contest_message_path(@contest, message), data: { turbo_method: :delete }, class: "btn btn-sm btn-danger"
|
||||||
|
@ -41,11 +41,20 @@ en:
|
|||||||
email_address: "Email address"
|
email_address: "Email address"
|
||||||
lang: "Language"
|
lang: "Language"
|
||||||
password: "New password"
|
password: "New password"
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
completion:
|
||||||
|
attributes:
|
||||||
|
display_time_from_start:
|
||||||
|
invalid: "Allowed formats: xx:xx:xx, x:xx:xx, xx:xx, x:xx"
|
||||||
|
puzzle_id:
|
||||||
|
taken: "This contestant has already completed this puzzle"
|
||||||
completions:
|
completions:
|
||||||
edit:
|
edit:
|
||||||
title: "Edit completion"
|
title: "Edit completion"
|
||||||
new:
|
new:
|
||||||
title: "New completion"
|
title: "New completion"
|
||||||
|
singular: "completion"
|
||||||
contests:
|
contests:
|
||||||
edit:
|
edit:
|
||||||
title: "Edit contest settings"
|
title: "Edit contest settings"
|
||||||
@ -80,7 +89,10 @@ en:
|
|||||||
create: "Create"
|
create: "Create"
|
||||||
save: "Save"
|
save: "Save"
|
||||||
messages:
|
messages:
|
||||||
|
convert:
|
||||||
|
title: "Convert message into completion"
|
||||||
plural: "messages"
|
plural: "messages"
|
||||||
|
singular: "message"
|
||||||
nav:
|
nav:
|
||||||
users: "Users"
|
users: "Users"
|
||||||
home: "Home"
|
home: "Home"
|
||||||
|
@ -12,11 +12,20 @@ fr:
|
|||||||
email_address: "Adresse email"
|
email_address: "Adresse email"
|
||||||
lang: "Langue de l'interface"
|
lang: "Langue de l'interface"
|
||||||
password: "Nouveau mot de passe"
|
password: "Nouveau mot de passe"
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
completion:
|
||||||
|
attributes:
|
||||||
|
display_time_from_start:
|
||||||
|
invalid: "Formats autorisés: xx:xx:xx, x:xx:xx, xx:xx, x:xx"
|
||||||
|
puzzle_id:
|
||||||
|
taken: "Ce.tte participant.e a déjà complété ce puzzle"
|
||||||
completions:
|
completions:
|
||||||
edit:
|
edit:
|
||||||
title: "Modifier la complétion"
|
title: "Modifier la complétion"
|
||||||
new:
|
new:
|
||||||
title: "Nouvelle complétion"
|
title: "Nouvelle complétion"
|
||||||
|
singular: "complétion"
|
||||||
contests:
|
contests:
|
||||||
edit:
|
edit:
|
||||||
title: "Paramètres du concours"
|
title: "Paramètres du concours"
|
||||||
@ -51,7 +60,10 @@ fr:
|
|||||||
create: "Créer"
|
create: "Créer"
|
||||||
save: "Modifier"
|
save: "Modifier"
|
||||||
messages:
|
messages:
|
||||||
|
convert:
|
||||||
|
title: "Conversion d'un message en complétion"
|
||||||
plural: "messages"
|
plural: "messages"
|
||||||
|
singular: "message"
|
||||||
nav:
|
nav:
|
||||||
users: "Utilisateur.ices"
|
users: "Utilisateur.ices"
|
||||||
home: "Accueil"
|
home: "Accueil"
|
||||||
|
@ -12,7 +12,9 @@ Rails.application.routes.draw do
|
|||||||
resources :completions
|
resources :completions
|
||||||
resources :contestants
|
resources :contestants
|
||||||
resources :puzzles
|
resources :puzzles
|
||||||
resources :messages
|
resources :messages, only: :destroy do
|
||||||
|
get "convert", to: "messages#convert"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
resources :passwords, param: :token
|
resources :passwords, param: :token
|
||||||
resource :session
|
resource :session
|
||||||
|
12
db/migrate/20250515061619_add_author_to_message.rb
Normal file
12
db/migrate/20250515061619_add_author_to_message.rb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class AddAuthorToMessage < ActiveRecord::Migration[8.0]
|
||||||
|
def change
|
||||||
|
add_column :messages, :author, :string
|
||||||
|
|
||||||
|
Message.find_each do |message|
|
||||||
|
message.author = "Unknown"
|
||||||
|
message.save
|
||||||
|
end
|
||||||
|
|
||||||
|
change_column_null :messages, :author, true
|
||||||
|
end
|
||||||
|
end
|
12
db/migrate/20250515062154_add_display_time_to_message.rb
Normal file
12
db/migrate/20250515062154_add_display_time_to_message.rb
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class AddDisplayTimeToMessage < ActiveRecord::Migration[8.0]
|
||||||
|
def change
|
||||||
|
add_column :messages, :display_time, :string
|
||||||
|
|
||||||
|
Message.find_each do |message|
|
||||||
|
message.display_time = "12:30"
|
||||||
|
message.save
|
||||||
|
end
|
||||||
|
|
||||||
|
change_column_null :messages, :display_time, true
|
||||||
|
end
|
||||||
|
end
|
4
db/schema.rb
generated
4
db/schema.rb
generated
@ -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_05_11_173749) do
|
ActiveRecord::Schema[8.0].define(version: 2025_05_15_062154) 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
|
||||||
@ -92,6 +92,8 @@ ActiveRecord::Schema[8.0].define(version: 2025_05_11_173749) do
|
|||||||
t.string "text", null: false
|
t.string "text", null: false
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
|
t.string "author"
|
||||||
|
t.string "display_time"
|
||||||
t.index ["contest_id"], name: "index_messages_on_contest_id"
|
t.index ["contest_id"], name: "index_messages_on_contest_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
# Table name: messages
|
# Table name: messages
|
||||||
#
|
#
|
||||||
# id :integer not null, primary key
|
# id :integer not null, primary key
|
||||||
|
# author :string
|
||||||
|
# display_time :string
|
||||||
# text :string not null
|
# text :string not null
|
||||||
# time_seconds :integer not null
|
# time_seconds :integer not null
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
# Table name: messages
|
# Table name: messages
|
||||||
#
|
#
|
||||||
# id :integer not null, primary key
|
# id :integer not null, primary key
|
||||||
|
# author :string
|
||||||
|
# display_time :string
|
||||||
# text :string not null
|
# text :string not null
|
||||||
# time_seconds :integer not null
|
# time_seconds :integer not null
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
|
Loading…
x
Reference in New Issue
Block a user