Skip to content

Commit

Permalink
♻️ Refacto import d'une question et fix rubocop
Browse files Browse the repository at this point in the history
  • Loading branch information
marouria committed Oct 31, 2024
1 parent e17c181 commit 70d47a3
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 145 deletions.
19 changes: 15 additions & 4 deletions app/admin/questions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,24 @@
def import_xls
return if params[:file_xls].blank?

import = ImportQuestion.new(params[:type])
@question = import.remplis_donnees(params[:file_xls])

importe_question
flash[:success] = I18n.t('.layouts.succes.import_question')
redirect_to redirection_apres_import
rescue ImportQuestion::Error => e
flash[:error] = e.message
erreur_import(e)
rescue ImportXls::Error => e
raise ImportQuestion::Error, e.message
end

private

def importe_question
import = ImportQuestion.new(params[:type])
@question = import.remplis_donnees(params[:file_xls])
end

def erreur_import(error)
flash[:error] = error.message
redirect_to admin_import_xls_path(type: params[:type])
end

Expand Down
191 changes: 57 additions & 134 deletions app/models/import_question.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# frozen_string_literal: true

class ImportQuestion
class Error < StandardError; end
class ImportQuestion < ImportXls
HEADERS_CLIC_DANS_IMAGE = %i[zone_cliquable image_au_clic].freeze
HEADERS_GLISSER_DEPOSER = %i[zone_depot].freeze
HEADERS_QCM = %i[type_qcm].freeze
Expand All @@ -12,188 +11,112 @@ class Error < StandardError; end
HEADERS_COMMUN = %i[libelle nom_technique illustration intitule_ecrit intitule_audio
consigne_ecrit consigne_audio description].freeze

HEADERS_ATTENDUS = { 'QuestionClicDansImage' => HEADERS_COMMUN + HEADERS_CLIC_DANS_IMAGE,
'QuestionGlisserDeposer' => HEADERS_COMMUN + HEADERS_GLISSER_DEPOSER,
'QuestionQcm' => HEADERS_COMMUN + HEADERS_QCM,
'QuestionSaisie' => HEADERS_COMMUN + HEADERS_SAISIE,
'QuestionSousConsigne' => HEADERS_SOUS_CONSIGNE }.freeze

def initialize(type)
super(type, HEADERS_ATTENDUS)
@type = type
end

def remplis_donnees(file)
sheet = Spreadsheet.open(file.path).worksheet(0)
@data = sheet.rows[1]
@headers = sheet.rows[0]
raise Error, message_erreur_headers unless headers_valides?

creation_question
recupere_data(file)
valide_headers
cree_question
rescue ActiveRecord::RecordInvalid => e
raise Error, message_erreur_validation(e)
rescue Down::Error
raise Error, message_erreur_telechargement
end

private

def message_erreur_validation(exception)
exception.record.errors.full_messages.to_sentence.to_s
end

def message_erreur_telechargement
"Impossible de télécharger un fichier depuis l'url : #{@current_download}"
end

def message_erreur_headers
I18n.t('.layouts.erreurs.import_question.mauvais_format', headers: headers_attendus.map do |h|
h.to_s.tr('_', ' ')
end.join(', '))
end

def headers_valides?
headers_serialises = @headers.map { |header| header.parameterize.underscore.to_sym if header }
headers_serialises[0, headers_attendus.length] == headers_attendus
end

def headers_attendus
headers = {
'QuestionClicDansImage' => HEADERS_COMMUN + HEADERS_CLIC_DANS_IMAGE,
'QuestionGlisserDeposer' => HEADERS_COMMUN + HEADERS_GLISSER_DEPOSER,
'QuestionQcm' => HEADERS_COMMUN + HEADERS_QCM,
'QuestionSaisie' => HEADERS_COMMUN + HEADERS_SAISIE,
'QuestionSousConsigne' => HEADERS_SOUS_CONSIGNE
}

headers[@type]
end

def creation_question
def cree_question
ActiveRecord::Base.transaction do
@question = Question.create!(type: @type, libelle: @data[0],
nom_technique: @data[1], description: @data[7])
telecharge_illustration(@data[2])
intialise_question
cree_transcription(:intitule, @data[4], @data[3])
unless @type == 'QuestionSousConsigne'
cree_transcription(:modalite_reponse, @data[6],
@data[5])
end
cree_transcription(:modalite_reponse, @data[6], @data[5]) unless sous_consigne?
update_champs_specifiques
end

@question
end

def cree_transcription(categorie, audio_url, ecrit)
transcription = Transcription.create!(ecrit: ecrit, question_id: @question.id,
categorie: categorie)
return if audio_url.blank?

transcription.audio.attach(telecharge_fichier(audio_url))
def intialise_question
@question = Question.create!(type: @type, libelle: @data[0],
nom_technique: @data[1], description: @data[7])
attache_fichier(@question.illustration, @data[2])
end

def telecharge_illustration(url)
return if url.blank?

@question.illustration.attach(telecharge_fichier(url))
def cree_transcription(categorie, audio_url, ecrit)
t = Transcription.create!(ecrit: ecrit, question_id: @question.id, categorie: categorie)
attache_fichier(t.audio, audio_url)
end

def update_champs_specifiques
case @type
when 'QuestionClicDansImage'
update_clic_dans_image
when 'QuestionGlisserDeposer'
update_glisser_deposer
when 'QuestionQcm'
update_qcm
when 'QuestionSaisie'
update_saisie
end
updates = {
'QuestionClicDansImage' => :update_clic_dans_image,
'QuestionGlisserDeposer' => :update_glisser_deposer,
'QuestionQcm' => :update_qcm,
'QuestionSaisie' => :update_saisie
}
send(updates[@type]) if updates.key?(@type)
end

def update_clic_dans_image
@question.zone_cliquable.attach(telecharge_fichier(@data[8]))
@question.image_au_clic.attach(telecharge_fichier(@data[9]))
attache_fichier(@question.image_au_clic, @data[9])
end

def update_glisser_deposer
@question.zone_depot.attach(telecharge_fichier(@data[8]))
cree_reponses
cree_reponses('reponse', method(:cree_reponse))
attache_fichier(@question.zone_depot, @data[8])
end

def update_qcm
@question.update!(type_qcm: @data[8])
cree_choix
cree_reponses('choix', method(:cree_chaque_choix))
end

def update_saisie
@question.update!(suffix_reponse: @data[8], reponse_placeholder: @data[9],
type_saisie: @data[10])
cree_bonne_reponse
cree_reponse_generique(@data[11], @data[12], 'bon')
end

def cree_choix
extraie_colonne('choix').each_value do |data_choix|
cree_chaque_choix(data_choix)
end
end

def cree_reponses
extraie_colonne('reponse').each_value do |data_reponse|
cree_reponse(data_reponse)
end
end

def cree_bonne_reponse
Choix.create!(
intitule: @data[11],
nom_technique: @data[12],
question_id: @question.id,
type_choix: 'bon'
)
def cree_reponses(type, creation_method)
extrait_colonnes_reponses(type).each_value { |data| creation_method.call(data) }
end

def cree_chaque_choix(data)
choix = Choix.create!(
intitule: data['intitule'],
nom_technique: data['nom_technique'],
question_id: @question.id,
type_choix: data['type_choix']
)
choix.audio.attach(telecharge_fichier(data['audio']))
choix = cree_reponse_generique(data['intitule'], data['nom_technique'], data['type_choix'])
attache_fichier(choix.audio, data['audio'])
end

def cree_reponse(data)
reponse = Choix.create!(
nom_technique: data['nom_technique'],
position_client: data['position_client'],
type_choix: data['type_choix'],
question_id: @question.id
)
reponse.illustration.attach(telecharge_fichier(data['illustration']))
end

def telecharge_fichier(url)
@current_download = url
return unless url

fichier = Down.download(url)
content_type = Marcel::MimeType.for(fichier.path, name: fichier.original_filename)

{
io: fichier,
filename: fichier.original_filename,
content_type: content_type
}
reponse = cree_reponse_generique(nil, data['nom_technique'], data['type_choix'],
data['position_client'])
attache_fichier(reponse.illustration, data['illustration'])
end

def extraie_colonne(reponse)
headers_data = {}

@headers.each_with_index do |header, index|
next unless header.to_s.match(/#{reponse}_(\d+)_/)

item = header.match(/#{reponse}_(\d+)_/)[1].to_i
data_type = header.match(/#{reponse}_\d+_(.*)/)[1]
def cree_reponse_generique(intitule, nom_technique, type_choix, position_client = nil)
Choix.create!(intitule: intitule,
nom_technique: nom_technique,
question_id: @question.id,
type_choix: type_choix,
position_client: position_client)
end

headers_data[item] = {} if headers_data[item].nil?
headers_data[item][data_type] = @data[index]
def extrait_colonnes_reponses(reponse)
@headers.each_with_index.with_object({}) do |(header, index), headers_data|
if (match = header.to_s.match(/#{reponse}_(\d+)_(.*)/))
item, data_type = match.captures
headers_data[item.to_i] ||= {}
headers_data[item.to_i][data_type] = @data[index]
end
end
end

headers_data
def sous_consigne?
@type == 'QuestionSousConsigne'
end
end
68 changes: 68 additions & 0 deletions app/models/import_xls.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# frozen_string_literal: true

class ImportXls
class Error < StandardError; end

def initialize(type, headers)
@type = type
@headers_attendus = headers[type]
end

def valide_headers
return if headers_valides?

raise Error, message_erreur_headers
end

private

def message_erreur_headers
I18n.t('.layouts.erreurs.import_question.mauvais_format',
headers: headers_attendus_to_s)
end

def headers_valides?
headers_serialises = @headers.map do |header|
header.parameterize.underscore.to_sym if header
end
headers_serialises[0, @headers_attendus.length] == @headers_attendus
end

def headers_attendus_to_s
@headers_attendus.map do |h|
h.to_s.tr('_', ' ')
end.join(', ')
end

def recupere_data(file)
sheet = Spreadsheet.open(file.path).worksheet(0)
@data = sheet.rows[1]
@headers = sheet.rows[0]
end

def telecharge_fichier(url)
@current_download = url
return unless url

fichier = Down.download(url)
content_type = Marcel::MimeType.for(fichier.path, name: fichier.original_filename)

{ io: fichier,
filename: fichier.original_filename,
content_type: content_type }
rescue Down::Error
raise Error, message_erreur_telechargement(@current_download)
end

def message_erreur_validation(exception)
exception.record.errors.full_messages.to_sentence.to_s
end

def message_erreur_telechargement(current_download)
"Impossible de télécharger un fichier depuis l'url : #{current_download}"
end

def attache_fichier(attachment, url)
attachment.attach(telecharge_fichier(url)) if url.present?
end
end
8 changes: 1 addition & 7 deletions spec/models/import_question_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,6 @@
fixture_file_upload('spec/support/import_question_glisser.xls', 'text/xls')
end

it 'importe les données spécifiques' do
service.remplis_donnees(file)
question = Question.last
expect(question.zone_depot.attached?).to eq true
end

it 'crée les réponses' do
service.remplis_donnees(file)
reponses = Question.last.reponses
Expand Down Expand Up @@ -132,7 +126,7 @@
it 'importe les données spécifiques' do
service.remplis_donnees(file)
question = Question.last
expect(question.image_au_clic.attached?).to eq true
expect(question.image_au_clic.attached?).to be true
end
end

Expand Down
Binary file modified spec/support/import_question_clic.xls
Binary file not shown.
Binary file modified spec/support/import_question_glisser.xls
Binary file not shown.

0 comments on commit 70d47a3

Please sign in to comment.