diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 52e483bb7..d553d2f3f 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -17,4 +17,9 @@ def cdn_for(attachment) ApplicationController.helpers.cdn_for(attachment) end + + def fichier_encode_base64(attachment) + file_content = attachment.download + ApplicationController.helpers.fichier_encode_en_base64(file_content) + end end diff --git a/app/models/question_clic_dans_image.rb b/app/models/question_clic_dans_image.rb index 211f31bbd..61f7d7f4a 100644 --- a/app/models/question_clic_dans_image.rb +++ b/app/models/question_clic_dans_image.rb @@ -60,9 +60,4 @@ def valide_zone_cliquable_avec_reponse errors.add(:zone_cliquable, "doit contenir la classe 'bonne_reponse'") throw(:abort) end - - def fichier_encode_base64(attachment) - file_content = attachment.download - ApplicationController.helpers.fichier_encode_en_base64(file_content) - end end diff --git a/app/models/question_glisser_deposer.rb b/app/models/question_glisser_deposer.rb index 879112a6b..f5f4bbf81 100644 --- a/app/models/question_glisser_deposer.rb +++ b/app/models/question_glisser_deposer.rb @@ -19,7 +19,7 @@ class QuestionGlisserDeposer < Question def as_json(_options = nil) json = base_json - json['zone_depot_url'] = zone_depot if zone_depot.attached? + json['zone_depot_url'] = fichier_encode_base64(zone_depot) if zone_depot.attached? json.merge!(json_audio_fields, reponses_fields) end @@ -27,7 +27,7 @@ def as_json(_options = nil) def base_json slice(:id, :nom_technique, :description).tap do |json| - json['type'] = 'glisser-deposer-billets' + json['type'] = 'glisser-deposer' json['illustration'] = cdn_for(illustration) if illustration.attached? json['modalite_reponse'] = transcription_modalite_reponse&.ecrit json['intitule'] = transcription_intitule&.ecrit @@ -37,7 +37,7 @@ def base_json def reponses_fields reponses_non_classees = reponses.map do |reponse| illustration_url = cdn_for(reponse.illustration) if reponse.illustration.attached? - reponse.slice(:id, :position, :position_client).merge( + reponse.slice(:id, :position, :nom_technique, :position_client).merge( 'illustration' => illustration_url ) end diff --git a/docs/tech-dive-in/EVA-193-les-zones-deposables-du-jeu-sont-automatiquement-utilisees-depuis-le-masque/readme.md b/docs/tech-dive-in/EVA-193-les-zones-deposables-du-jeu-sont-automatiquement-utilisees-depuis-le-masque/readme.md new file mode 100644 index 000000000..90a550f4f --- /dev/null +++ b/docs/tech-dive-in/EVA-193-les-zones-deposables-du-jeu-sont-automatiquement-utilisees-depuis-le-masque/readme.md @@ -0,0 +1,21 @@ + +# Les zones déposables du jeu sont automatiquement utilisées depuis le masque + +> [EVA-193](https://captive-team.atlassian.net/browse/EVA-193) + +## Backend + +- Envoyer au front les données nécessaires au paramétrage dans le json d'une question GlisserDeposer +```ruby + json['zone_depot_url'] = zone_depot if zone_depot.attached? +``` +- Restituer le fichier de test `models/question_glisser_deposer_spec.rb` comme avant +- Modifier le type de QuestionGlisserDeposer et envoyé au front le type `glisser-deposer` + +# Frontend + +- Cleaner les données en dur de `numeratie.js` et `rattrapage.js` qui ne sont plus utiles +- Si question.zone_depot_url retourner l'extensionVue `glisser-deposer-depot-multiple` sinon retourner `glisser-deposer-billets` +- Renommer le composant `GlisserDeposerDepotMultiple` en `GlisserDeposerMultiple` +- Renommer le composant `GlisserDeposerBillets` en `GlisserDeposerSimple` +- Gérer le calcul des points en vérifiant que chaque élement est déposé dans la zone-depot qui contient la class avec le nom technique de la réponse `zone-depot--nomTechniqueReponse` diff --git a/spec/models/question_glisser_deposer_spec.rb b/spec/models/question_glisser_deposer_spec.rb index 4cbb1f0d5..87863558f 100644 --- a/spec/models/question_glisser_deposer_spec.rb +++ b/spec/models/question_glisser_deposer_spec.rb @@ -2,184 +2,79 @@ require 'rails_helper' -describe 'Admin - Question Glisser Deposer', type: :feature do - before(:each) { se_connecter_comme_superadmin } - - describe 'show' do - let!(:question) do - create :question_glisser_deposer, libelle: 'Libellé de la question' - end - let!(:transcription) do - create :transcription, question_id: question.id, ecrit: 'Comment ça va ?' - end - - before(:each) { visit admin_question_glisser_deposer_path(question) } - - it 'affiche le libellé de la question et la transcription associée' do - expect(page).to have_content 'Libellé de la question' - expect(page).to have_content 'Comment ça va ?' - end +describe QuestionGlisserDeposer, type: :model do + let!(:question) do + create(:question_glisser_deposer, + illustration: Rack::Test::UploadedFile.new( + Rails.root.join('spec/support/programme_tele.png') + ), + zone_depot: Rack::Test::UploadedFile.new( + Rails.root.join('spec/support/N1Pse1-zone-depot-valide.svg') + )) end - - describe 'index' do - let!(:question) do - create :question_glisser_deposer - end - let!(:transcription) do - create :transcription, question_id: question.id, ecrit: 'Comment ça va ?' - end - - before(:each) { visit admin_questions_glisser_deposer_path } - - it do - expect(page).to have_content 'Comment ça va ?' - end + let(:json) { question.as_json } + let!(:reponse1) do + create(:choix, :avec_illustration, :bon, question_id: question.id, position_client: 2) + end + let!(:reponse2) { create(:choix, :avec_illustration, :bon, question_id: question.id) } + let!(:modalite) do + create(:transcription, :avec_audio, question_id: question.id, + categorie: :modalite_reponse) end - describe 'création' do - before(:each) do - visit new_admin_question_glisser_deposer_path - end - - context 'sans transcriptions' do - before(:each) do - fill_in :question_glisser_deposer_libelle, with: 'Question' - fill_in :question_glisser_deposer_nom_technique, with: 'question' - end - - it 'créé une nouvelle question' do - expect { click_on 'Créer' }.to(change { Question.count }) - expect(Question.first.transcriptions).to be_empty - end - end - - context 'quand une transcription pour intitule est ajouté' do - before(:each) do - fill_in :question_glisser_deposer_libelle, with: 'Question' - fill_in :question_glisser_deposer_nom_technique, with: 'question' - fill_in :question_glisser_deposer_transcriptions_attributes_0_ecrit, with: 'Intitulé' - click_on 'Créer' - end - - it do - expect(Question.first.transcriptions.count).to eq 1 - expect(Question.first.transcription_intitule&.ecrit).to eq 'Intitulé' - end - end - - context 'quand une transcription pour modalité réponse est ajoutée' do - before(:each) do - fill_in :question_glisser_deposer_libelle, with: 'Question' - fill_in :question_glisser_deposer_nom_technique, with: 'question' - fill_in :question_glisser_deposer_transcriptions_attributes_1_ecrit, with: 'Consigne' - click_on 'Créer' - end + it { is_expected.to have_many(:reponses).with_foreign_key(:question_id) } + it { is_expected.to have_one_attached(:zone_depot) } - it do - expect(Question.first.transcriptions.count).to eq 1 - expect(Question.first.transcription_modalite_reponse&.ecrit).to eq 'Consigne' - end + describe '#as_json' do + it 'serialise les champs' do + expect(json.keys).to match_array(%w[id intitule audio_url nom_technique + description illustration modalite_reponse type + reponsesNonClassees zone_depot_url]) + expect(json['type']).to eql('glisser-deposer') + expect(json['modalite_reponse']).to eql(modalite.ecrit) + expect(json['illustration']).to eql(Rails.application.routes.url_helpers.url_for( + question.illustration + )) + expect(json['zone_depot_url']).to start_with('data:image/svg+xml;base64,') end - context 'quand une illustration est ajoutée' do - before(:each) do - fill_in :question_glisser_deposer_libelle, with: 'Question' - fill_in :question_glisser_deposer_nom_technique, with: 'question' - attach_file(:question_glisser_deposer_illustration, - Rails.root.join('spec/support/programme_tele.png')) - click_on 'Créer' - end - + describe 'les reponsesNonClassees' do it do - expect(Question.first.illustration.attached?).to eq true + expect(json['reponsesNonClassees'].size).to be(2) + expect(json['reponsesNonClassees'].first['illustration']).not_to be_nil + expect(json['reponsesNonClassees'].first['position']).to be(1) + expect(json['reponsesNonClassees'].first['position_client']).to be(2) + expect(json['reponsesNonClassees'].first['nom_technique']).to eql(reponse1.nom_technique) end end end - describe 'modification' do - let!(:question) do - create :question_glisser_deposer, - illustration: Rack::Test::UploadedFile.new( - Rails.root.join('spec/support/programme_tele.png') - ) - end - let!(:transcription) do - create :transcription, question_id: question.id, ecrit: 'Comment ça va ?' - end - - let!(:modalite_reponse) do - create :transcription, :avec_audio, question_id: question.id, ecrit: 'Comment ça va ?', - categorie: :modalite_reponse - end - - context "quand l'admin supprime l'écrit d'une transcription et qu'il n'y a pas d'audio" do - before(:each) do - visit edit_admin_question_glisser_deposer_path(question) - fill_in :question_glisser_deposer_transcriptions_attributes_0_ecrit, with: nil - end - - it 'supprime la transcription' do - expect(Question.first.transcriptions.count).to eq 2 - click_on 'Enregistrer' - expect(Question.first.transcriptions.count).to eq 1 - end - end - - context "quand l'admin coche supprimer l'illustration" do - before(:each) do - visit edit_admin_question_glisser_deposer_path(question) - check 'question_glisser_deposer_supprimer_illustration' - end - - it "supprime l'illustration" do - expect(question.illustration.attached?).to eq true - click_on 'Enregistrer' - question.reload - expect(question.illustration.attached?).to eq false - end + describe 'validations' do + let(:question) do + build(:question_glisser_deposer) end - context "quand l'admin coche supprimer l'audio de l'intitulé" do - before(:each) do - Question.first.transcriptions.find_by(categorie: :intitule) - .update(audio: Rack::Test::UploadedFile.new( - Rails.root.join('spec/support/alcoolique.mp3') - )) - visit edit_admin_question_glisser_deposer_path(question) - check 'question_glisser_deposer_supprimer_audio_intitule' - end - - it "supprime l'audio" do - expect( - Question.first.transcriptions.find_by(categorie: :intitule).audio.attached? - ).to eq true - click_on 'Enregistrer' - question.reload - expect( - Question.first.transcriptions.find_by(categorie: :intitule).audio.attached? - ).to eq false + context 'avec un attachment au format svg' do + it 'est valide' do + question.zone_depot.attach( + io: Rails.root.join('spec/support/accessibilite-sans-reponse.svg').open, + filename: 'valid.svg', + content_type: 'image/svg+xml' + ) + expect(question).to be_valid end end - context "quand l'admin coche supprimer l'audio de la consigne" do - before(:each) do - Question.first.transcriptions.find_by(categorie: :modalite_reponse) - .update(audio: Rack::Test::UploadedFile.new( - Rails.root.join('spec/support/alcoolique.mp3') - )) - visit edit_admin_question_glisser_deposer_path(question) - check 'question_glisser_deposer_supprimer_audio_modalite_reponse' - end - - it "supprime l'audio" do - expect( - Question.first.transcriptions.find_by(categorie: :modalite_reponse).audio.attached? - ).to eq true - click_on 'Enregistrer' - question.reload - expect( - Question.first.transcriptions.find_by(categorie: :modalite_reponse).audio.attached? - ).to eq false + context "avec un attachement d'un autre format" do + it "n'est pas valide" do + question.zone_depot.attach( + io: Rails.root.join('spec/support/programme_tele.png').open, + filename: 'invalid.png', + content_type: 'image/png' + ) + expect(question).not_to be_valid + erreur = question.errors[:zone_depot] + expect(erreur).to include("n'est pas un format de fichier valide") end end end