Start CSV importer feature
All checks were successful
CI / scan_ruby (push) Successful in 20s
CI / scan_js (push) Successful in 12s
CI / lint (push) Successful in 12s
CI / test (push) Successful in 32s

This commit is contained in:
sto
2025-05-17 12:03:10 +02:00
parent 5ec0e264ba
commit 939e2157ab
14 changed files with 153 additions and 1 deletions

View File

@@ -42,6 +42,21 @@ class ContestantsController < ApplicationController
redirect_to contest_path(@contest)
end
def import
authorize @contest
if params[:csv_import]
@csv_import = CsvImport.new(params.require(:csv_import).permit(:file, :separator))
if @csv_import.save
@csv_import = CsvImport.new
else
render :import, status: :unprocessable_entity
end
else
@csv_import = CsvImport.new
end
end
private
def set_contest

46
app/models/csv_import.rb Normal file
View File

@@ -0,0 +1,46 @@
# == Schema Information
#
# Table name: csv_imports
#
# id :integer not null, primary key
# separator :integer not null
# created_at :datetime not null
# updated_at :datetime not null
#
class CsvImport < ApplicationRecord
enum :separator, { comma: ",", semicolon: ";" }, default: :comma
has_one_attached :file
validates :file, presence: true
validate :acceptable_csv, on: :create
def acceptable_csv
return unless file.attached?
if file.blob.byte_size > 20
errors.add(:file, "this csv file is too large, it must be under 20MB")
return
end
if file.content_type != "text/csv"
errors.add(:file, :not_a_csv_file)
return
end
begin
csv = CSV.read(attachment_changes["file"].attachable.path, col_sep: separator)
logger = Logger.new(STDOUT)
logger.info(csv)
errors.add(:file, :empty) if csv.count < 1 || (csv.count == 1 && csv[0].count == 1 && csv[0][0] == "")
rescue CSV::MalformedCSVError => e
errors.add(:file, e.message)
end
end
def options_for_separator
keys = self.class.separators.keys
keys.map(&:humanize).zip(keys).to_h
end
end

View File

@@ -31,6 +31,10 @@ class ContestPolicy < ApplicationPolicy
record.user.id == user.id || user.admin?
end
def import?
record.user.id == user.id || user.admin?
end
def scoreboard?
true
end

View File

@@ -0,0 +1,19 @@
= form_with(model: @csv_import, url: contest_import_path(@contest), html: { novalidate: true }) do |form|
.row.g-3
.col
.mb-3
.form-floating
= form.file_field :file, class: "form-control", accept: ".csv, text/csv"
= form.label :file
.row.g-3
.col
.mb-3
.form-floating
= form.select :separator, @csv_import.options_for_separator, {}, class: "form-select"
= form.label :separator
.row.g-3
.col
.mb-3
= form.submit t("helpers.buttons.import"), class: "btn btn-primary"

View File

@@ -76,6 +76,8 @@
= t("contestants.plural").capitalize
a.ms-3.btn.btn-primary href=new_contest_contestant_path(@contest) style="margin-top: -3px"
| + #{t("helpers.buttons.add")}
a.ms-3.btn.btn-primary href=contest_import_path(@contest) style="margin-top: -3px"
| #{t("helpers.buttons.import")}
table.table.table-striped.table-hover
thead
tr