Skip to content

Commit

Permalink
✨ Construit l'export xls d'une question et refacto l'import
Browse files Browse the repository at this point in the history
  • Loading branch information
marouria committed Nov 5, 2024
1 parent e656e97 commit 0c8f4c7
Show file tree
Hide file tree
Showing 13 changed files with 635 additions and 230 deletions.
30 changes: 16 additions & 14 deletions app/admin/questions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,30 @@

member_action :export_xls, method: :get do
question = Question.find(params[:id])
export = ImportExportQuestion.new(question)
export.exporte_donnees
export = ImportExportQuestion.new(question).exporte_donnees
send_data export[:xls],
content_type: export[:content_type],
filename: export[:filename]
end

controller do
def import_xls
return if params[:file_xls].blank?

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

private

def importe_question
import = ImportExportQuestion.new(Question.new(type: params[:type]))
@question = import.importe_donnees(params[:file_xls])
def recupere_question
question = Question.new(type: params[:type])
ImportExportQuestion.new(question).importe_donnees(params[:file_xls])
end

def erreur_import(error)
Expand All @@ -36,13 +38,13 @@ def erreur_import(error)

private

def redirection_apres_import
def redirection_apres_import(question)
redirection_paths = {
'QuestionClicDansImage' => edit_admin_question_clic_dans_image_path(@question),
'QuestionGlisserDeposer' => edit_admin_question_glisser_deposer_path(@question),
'QuestionQcm' => edit_admin_question_qcm_path(@question),
'QuestionSaisie' => edit_admin_question_saisie_path(@question),
'QuestionSousConsigne' => edit_admin_question_sous_consigne_path(@question)
'QuestionClicDansImage' => edit_admin_question_clic_dans_image_path(question),
'QuestionGlisserDeposer' => edit_admin_question_glisser_deposer_path(question),
'QuestionQcm' => edit_admin_question_qcm_path(question),
'QuestionSaisie' => edit_admin_question_saisie_path(question),
'QuestionSousConsigne' => edit_admin_question_sous_consigne_path(question)
}

redirection_paths[params[:type]]
Expand Down
4 changes: 2 additions & 2 deletions app/admin/questions_clic_dans_image.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

ActiveAdmin.register QuestionClicDansImage do
before_action :set_question, only: %i[update show]
before_action :set_question, only: %i[update]

menu parent: 'Parcours', if: proc { can? :manage, Compte }

Expand Down Expand Up @@ -40,7 +40,7 @@

action_item :exporter_question, only: :show do
link_to 'Exporter le contenu de la question',
admin_question_export_xls_path(question_id: question.id)
admin_question_export_xls_path(question_id: params[:id])
end

show do
Expand Down
12 changes: 12 additions & 0 deletions app/models/choix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,16 @@ def audio_type
errors.add(:audio, 'doit être un fichier MP3 ou MP4')
audio.purge
end

def audio_url
return unless audio.attached?

cdn_for(audio)
end

def illustration_url
return unless illustration.attached?

cdn_for(illustration)
end
end
120 changes: 120 additions & 0 deletions app/models/export_question.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# frozen_string_literal: true

class ExportQuestion
WORKSHEET_NAME = 'Données'

def initialize(question, headers)
@question = question
@headers = headers
@sheet = sheet
end

def to_xls
initialise_feuille
remplie_la_feuille
retourne_le_contenu_du_xls
end

def content_type_xls
'application/vnd.ms-excel'
end

def nom_du_fichier
date = DateTime.current.strftime('%Y%m%d')
"#{date}-#{@question.nom_technique}.xls"
end

private

def sheet
workbook = Spreadsheet::Workbook.new
workbook.create_worksheet(name: WORKSHEET_NAME)
end

def initialise_feuille
format_premiere_ligne = Spreadsheet::Format.new(weight: :bold)
@sheet.row(0).default_format = format_premiere_ligne
@headers.each_with_index do |entete, colonne|
@sheet[0, colonne] = entete.to_s.humanize
@sheet.column(colonne).width = 20
end
end

def remplie_la_feuille
@headers.each { |_valeur| remplis_champs_commun }
end

def remplis_champs_commun
@sheet[1, 0] = @question.libelle
@sheet[1, 1] = @question.nom_technique
@sheet[1, 2] = @question.illustration_url
@sheet[1, 3] = @question.transcription_intitule&.ecrit
@sheet[1, 4] = @question.transcription_intitule&.audio_url
remplis_champs_additionnels
end

def remplis_champs_additionnels
return if @question.sous_consigne?

@sheet[1, 5] = @question.transcription_modalite_reponse&.ecrit
@sheet[1, 6] = @question.transcription_modalite_reponse&.audio_url
@sheet[1, 7] = @question.description
remplis_champs_specifiques
end

def remplis_champs_specifiques
case @question.type
when 'QuestionClicDansImage' then remplis_champs_clic_dans_image
when 'QuestionGlisserDeposer' then remplis_champs_glisser_deposer
when 'QuestionQcm' then remplis_champs_qcm
when 'QuestionSaisie' then remplis_champs_saisie
end
end

def remplis_champs_clic_dans_image
@sheet[1, 8] = @question.zone_cliquable_url
@sheet[1, 9] = @question.image_au_clic_url
end

def remplis_champs_glisser_deposer
@sheet[1, 8] = @question.zone_depot_url
@question.reponses.each_with_index { |choix, index| ajoute_reponses(choix, 1, index) }
end

def remplis_champs_saisie
@sheet[1, 8] = @question.suffix_reponse
@sheet[1, 9] = @question.reponse_placeholder
@sheet[1, 10] = @question.type_saisie
return unless @question.bonne_reponse

@sheet[1, 11] = @question.bonne_reponse.intitule
@sheet[1, 12] = @question.bonne_reponse.nom_technique
end

def remplis_champs_qcm
@sheet[1, 8] = @question.type_qcm
@question.choix.each_with_index { |choix, index| ajoute_choix(choix, 1, index) }
end

def ajoute_choix(choix, ligne, index)
columns = %w[intitule nom_technique type_choix audio]
columns.each_with_index do |col, i|
@sheet[0, 9 + (index * 4) + i] = "choix_#{index + 1}_#{col}"
@sheet[ligne, 9 + (index * 4) + i] = choix.send(col)
end
end

def ajoute_reponses(choix, ligne, index)
columns = %w[nom_technique position_client type_choix illustration]
columns.each_with_index do |col, i|
@sheet[0, 9 + (index * 4) + i] = "reponse_#{index + 1}_#{col}"
@sheet[ligne, 9 + (index * 4) + i] = choix.send(col)
end
end

def retourne_le_contenu_du_xls
file_contents = StringIO.new
@sheet.workbook.write file_contents
file_contents.string
end
end
37 changes: 11 additions & 26 deletions app/models/import_export_question.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,27 @@ class ImportExportQuestion
'QuestionSaisie' => HEADERS_COMMUN + HEADERS_SAISIE,
'QuestionSousConsigne' => HEADERS_SOUS_CONSIGNE }.freeze

delegate :message_erreur_headers, to: :@import

def initialize(question)
@question = question
@type = question.type
@import = ImportQuestion.new(@question, HEADERS_ATTENDUS[@type])
end

def importe_donnees(file)
@import.recupere_data(file)
@import.valide_headers
@import.cree_question
ImportQuestion.new(@question, HEADERS_ATTENDUS[@type]).import_from_xls(file)
rescue ActiveRecord::RecordInvalid => e
raise Error, message_erreur_validation(e)
raise ImportQuestion::Error, message_erreur_validation(e)
end

def exporte_donnees
send_data to_xls,
content_type: content_type_xls,
filename: nom_du_fichier
export = ExportQuestion.new(@question, HEADERS_ATTENDUS[@type])
{
xls: export.to_xls,
content_type: export.content_type_xls,
filename: export.nom_du_fichier
}
end

# def to_xls
# workbook = Spreadsheet::Workbook.new
# sheet = workbook.create_worksheet(name: 'worksheet name')
# initialise_sheet(sheet)
# remplie_la_feuille(sheet)
# retourne_le_contenu_du_xls(workbook)
# end

# def content_type_xls
# 'application/vnd.ms-excel'
# end

# def nom_du_fichier
# date = DateTime.current.strftime('%Y%m%d')
# "#{date}-#{@question.nom_technique}.xls"
# end
def message_erreur_validation(exception)
exception.record.errors.full_messages.to_sentence.to_s
end
end
6 changes: 6 additions & 0 deletions app/models/import_question.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ def initialize(question, headers_attendus)
@type = question.type
end

def import_from_xls(file)
recupere_data(file)
valide_headers
cree_question
end

def cree_question
ActiveRecord::Base.transaction do
intialise_question
Expand Down
4 changes: 0 additions & 4 deletions app/models/import_xls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ def telecharge_fichier(url)
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
Expand Down
6 changes: 6 additions & 0 deletions app/models/question.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ def sous_consigne?
type == 'QuestionSousConsigne'
end

def illustration_url
return unless illustration.attached?

cdn_for(illustration)
end

private

def audio_url
Expand Down
8 changes: 8 additions & 0 deletions app/models/question_clic_dans_image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ def clic_multiple?
svg_contient_class_bonne_reponse?(svg_content, 2)
end

def zone_cliquable_url
cdn_for(zone_cliquable) if zone_cliquable.attached?
end

def image_au_clic_url
cdn_for(image_au_clic) if image_au_clic.attached?
end

private

def base_json
Expand Down
4 changes: 4 additions & 0 deletions app/models/question_glisser_deposer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ def as_json(_options = nil)
json.merge!(json_audio_fields, reponses_fields)
end

def zone_depot_url
cdn_for(zone_depot) if zone_depot.attached?
end

private

def base_json
Expand Down
Loading

0 comments on commit 0c8f4c7

Please sign in to comment.