decidim-forms 0.30.3 → 0.31.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +10 -10
- data/app/cells/decidim/forms/matrix_readonly/show.erb +1 -1
- data/app/cells/decidim/forms/matrix_readonly_cell.rb +3 -3
- data/app/cells/decidim/forms/question_readonly/show.erb +5 -5
- data/app/cells/decidim/forms/question_readonly/title_and_description.erb +3 -3
- data/app/cells/decidim/forms/response_readonly_cell.rb +9 -0
- data/app/cells/decidim/forms/step_navigation/show.erb +3 -3
- data/app/cells/decidim/forms/step_navigation_cell.rb +3 -3
- data/app/commands/decidim/forms/admin/update_questions.rb +6 -6
- data/app/commands/decidim/forms/{answer_questionnaire.rb → response_questionnaire.rb} +35 -35
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +12 -12
- data/app/controllers/decidim/forms/admin/concerns/{has_questionnaire_answers.rb → has_questionnaire_responses.rb} +23 -19
- data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +38 -33
- data/app/forms/decidim/forms/admin/display_condition_form.rb +14 -14
- data/app/forms/decidim/forms/admin/question_form.rb +3 -3
- data/app/forms/decidim/forms/admin/{answer_option_form.rb → response_option_form.rb} +3 -3
- data/app/forms/decidim/forms/questionnaire_form.rb +8 -9
- data/app/forms/decidim/forms/{answer_choice_form.rb → response_choice_form.rb} +5 -5
- data/app/forms/decidim/forms/{answer_form.rb → response_form.rb} +9 -9
- data/app/helpers/decidim/forms/admin/application_helper.rb +2 -2
- data/app/helpers/decidim/forms/admin/concerns/{has_questionnaire_answers_pagination_helper.rb → has_questionnaire_responses_pagination_helper.rb} +4 -4
- data/app/helpers/decidim/forms/admin/concerns/{has_questionnaire_answers_url_helper.rb → has_questionnaire_responses_url_helper.rb} +5 -5
- data/app/helpers/decidim/forms/admin/questionnaire_responses_helper.rb +32 -0
- data/app/helpers/decidim/forms/application_helper.rb +1 -2
- data/app/jobs/decidim/forms/{export_questionnaire_answers_job.rb → export_questionnaire_responses_job.rb} +5 -5
- data/app/models/decidim/forms/display_condition.rb +20 -20
- data/app/models/decidim/forms/question.rb +14 -13
- data/app/models/decidim/forms/question_matrix_row.rb +1 -1
- data/app/models/decidim/forms/questionnaire.rb +11 -6
- data/app/models/decidim/forms/{answer.rb → response.rb} +9 -9
- data/app/models/decidim/forms/response_choice.rb +22 -0
- data/app/models/decidim/forms/{answer_option.rb → response_option.rb} +5 -5
- data/app/packs/entrypoints/decidim_forms_admin.js +3 -3
- data/app/packs/src/decidim/forms/admin/collapsible_questions.js +12 -10
- data/app/packs/src/decidim/forms/admin/forms.js +35 -35
- data/app/packs/src/decidim/forms/admin/{publish_answers_buttons.js → publish_responses_buttons.js} +12 -12
- data/app/packs/src/decidim/forms/display_conditions.component.js +12 -12
- data/app/packs/src/decidim/forms/forms.js +8 -29
- data/app/packs/stylesheets/decidim/forms/forms.scss +2 -2
- data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +13 -13
- data/app/presenters/decidim/forms/admin/{questionnaire_answer_presenter.rb → questionnaire_response_presenter.rb} +15 -15
- data/app/presenters/decidim/forms/admin_log/question_presenter.rb +3 -3
- data/app/presenters/decidim/forms/{answer_option_presenter.rb → response_option_presenter.rb} +2 -2
- data/app/queries/decidim/forms/questionnaire_participant.rb +5 -5
- data/app/queries/decidim/forms/questionnaire_participants.rb +6 -6
- data/app/queries/decidim/forms/questionnaire_user_responses.rb +32 -0
- data/app/views/decidim/forms/admin/questionnaires/_display_condition.html.erb +9 -9
- data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +2 -2
- data/app/views/decidim/forms/admin/questionnaires/_matrix_row.html.erb +3 -3
- data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +21 -11
- data/app/views/decidim/forms/admin/questionnaires/_questions_form.html.erb +13 -41
- data/app/views/decidim/forms/admin/questionnaires/{_answer_option.html.erb → _response_option.html.erb} +7 -7
- data/app/views/decidim/forms/admin/questionnaires/_response_option_template.html.erb +7 -0
- data/app/views/decidim/forms/admin/questionnaires/_separator.html.erb +11 -1
- data/app/views/decidim/forms/admin/questionnaires/_title_and_description.html.erb +12 -2
- data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +1 -1
- data/app/views/decidim/forms/admin/questionnaires/edit_questions.html.erb +8 -8
- data/app/views/decidim/forms/admin/questionnaires/responses/index.html.erb +80 -0
- data/app/views/decidim/forms/admin/questionnaires/responses/show.html.erb +43 -0
- data/app/views/decidim/forms/questionnaires/_questionnaire.html.erb +22 -26
- data/app/views/decidim/forms/questionnaires/_questionnaire_readonly.html.erb +8 -3
- data/app/views/decidim/forms/questionnaires/_response.html.erb +61 -0
- data/app/views/decidim/forms/questionnaires/edit.html.erb +2 -2
- data/app/views/decidim/forms/questionnaires/responses/_files.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/responses/_long_response.html.erb +3 -0
- data/app/views/decidim/forms/questionnaires/{answers → responses}/_matrix_multiple.html.erb +16 -15
- data/app/views/decidim/forms/questionnaires/{answers → responses}/_matrix_single.html.erb +17 -16
- data/app/views/decidim/forms/questionnaires/responses/_multiple_option.html.erb +26 -0
- data/app/views/decidim/forms/questionnaires/responses/_separator.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/responses/_short_response.html.erb +3 -0
- data/app/views/decidim/forms/questionnaires/responses/_single_option.html.erb +33 -0
- data/app/views/decidim/forms/questionnaires/responses/_sorting.html.erb +26 -0
- data/app/views/decidim/forms/questionnaires/responses/_title_and_description.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/show.html.erb +10 -10
- data/config/assets.rb +2 -2
- data/config/locales/ar.yml +2 -22
- data/config/locales/bg.yml +10 -36
- data/config/locales/ca-IT.yml +80 -74
- data/config/locales/ca.yml +80 -74
- data/config/locales/cs.yml +79 -76
- data/config/locales/de.yml +79 -72
- data/config/locales/el.yml +10 -36
- data/config/locales/en.yml +90 -84
- data/config/locales/es-MX.yml +82 -76
- data/config/locales/es-PY.yml +82 -76
- data/config/locales/es.yml +80 -74
- data/config/locales/eu.yml +78 -72
- data/config/locales/fi-plain.yml +78 -72
- data/config/locales/fi.yml +76 -70
- data/config/locales/fr-CA.yml +77 -68
- data/config/locales/fr.yml +77 -68
- data/config/locales/ga-IE.yml +4 -7
- data/config/locales/gl.yml +4 -22
- data/config/locales/hu.yml +4 -22
- data/config/locales/id-ID.yml +2 -22
- data/config/locales/it.yml +8 -40
- data/config/locales/ja.yml +87 -81
- data/config/locales/lb.yml +8 -36
- data/config/locales/lt.yml +10 -36
- data/config/locales/lv.yml +4 -22
- data/config/locales/nl.yml +10 -36
- data/config/locales/no.yml +10 -36
- data/config/locales/pl.yml +10 -36
- data/config/locales/pt-BR.yml +10 -36
- data/config/locales/pt.yml +8 -36
- data/config/locales/ro-RO.yml +29 -51
- data/config/locales/ru.yml +2 -9
- data/config/locales/sk.yml +2 -22
- data/config/locales/sl.yml +0 -5
- data/config/locales/sv.yml +89 -55
- data/config/locales/tr-TR.yml +8 -36
- data/config/locales/val-ES.yml +2 -0
- data/config/locales/zh-CN.yml +8 -36
- data/config/locales/zh-TW.yml +10 -36
- data/db/migrate/20190315203056_add_session_token_to_decidim_forms_answers.rb +1 -1
- data/db/migrate/20250314150250_rename_answer_to_response_in_decidim_forms.rb +30 -0
- data/db/migrate/20250319130003_change_question_types_in_questions.rb +14 -0
- data/lib/decidim/api/question_matrix_row_type.rb +13 -0
- data/lib/decidim/api/question_type.rb +4 -3
- data/lib/decidim/api/questionnaire_type.rb +1 -0
- data/lib/decidim/api/response_option_type.rb +13 -0
- data/lib/decidim/exporters/form_pdf.rb +33 -33
- data/lib/decidim/forms/api.rb +2 -1
- data/lib/decidim/forms/{download_your_data_user_answers_serializer.rb → download_your_data_user_responses_serializer.rb} +3 -3
- data/lib/decidim/forms/engine.rb +2 -2
- data/lib/decidim/forms/test/factories.rb +24 -24
- data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +176 -176
- data/lib/decidim/forms/test/shared_examples/manage_questionnaire_responses.rb +159 -0
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +19 -19
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +44 -44
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +10 -10
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +43 -140
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +4 -4
- data/lib/decidim/forms/test.rb +1 -1
- data/lib/decidim/forms/user_responses_serializer.rb +110 -0
- data/lib/decidim/forms/version.rb +1 -1
- data/lib/decidim/forms.rb +2 -2
- metadata +48 -45
- data/app/cells/decidim/forms/answer_readonly_cell.rb +0 -9
- data/app/helpers/decidim/forms/admin/questionnaire_answers_helper.rb +0 -30
- data/app/models/decidim/forms/answer_choice.rb +0 -22
- data/app/queries/decidim/forms/questionnaire_user_answers.rb +0 -32
- data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +0 -7
- data/app/views/decidim/forms/admin/questionnaires/answers/index.html.erb +0 -49
- data/app/views/decidim/forms/admin/questionnaires/answers/show.html.erb +0 -43
- data/app/views/decidim/forms/questionnaires/_answer.html.erb +0 -61
- data/app/views/decidim/forms/questionnaires/answers/_files.html.erb +0 -1
- data/app/views/decidim/forms/questionnaires/answers/_long_answer.html.erb +0 -3
- data/app/views/decidim/forms/questionnaires/answers/_multiple_option.html.erb +0 -25
- data/app/views/decidim/forms/questionnaires/answers/_separator.html.erb +0 -1
- data/app/views/decidim/forms/questionnaires/answers/_short_answer.html.erb +0 -3
- data/app/views/decidim/forms/questionnaires/answers/_single_option.html.erb +0 -32
- data/app/views/decidim/forms/questionnaires/answers/_sorting.html.erb +0 -26
- data/app/views/decidim/forms/questionnaires/answers/_title_and_description.html.erb +0 -1
- data/lib/decidim/api/answer_option_type.rb +0 -13
- data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +0 -149
- data/lib/decidim/forms/user_answers_serializer.rb +0 -105
- /data/app/cells/decidim/forms/{answer_readonly → response_readonly}/show.erb +0 -0
|
@@ -16,7 +16,7 @@ shared_examples_for "update questions" do
|
|
|
16
16
|
fill_in "questions_questions_#{question.id}_body_en", with: "Modified question"
|
|
17
17
|
fill_in "questions_questions_#{question.id}_max_characters", with: 30
|
|
18
18
|
check "Mandatory"
|
|
19
|
-
select "Long
|
|
19
|
+
select "Long response", from: "Type"
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
click_on "Save"
|
|
@@ -29,7 +29,7 @@ shared_examples_for "update questions" do
|
|
|
29
29
|
expect(page).to have_no_css("input[value='This is the first question']")
|
|
30
30
|
expect(page).to have_css("input#questions_questions_#{question.id}_mandatory[checked]")
|
|
31
31
|
expect(page).to have_css("input#questions_questions_#{question.id}_max_characters[value='30']")
|
|
32
|
-
expect(page).to have_css("select#questions_questions_#{question.id}_question_type option[value='
|
|
32
|
+
expect(page).to have_css("select#questions_questions_#{question.id}_question_type option[value='long_response'][selected]")
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it "re-renders the form when the information is invalid and displays errors" do
|
|
@@ -85,7 +85,7 @@ shared_examples_for "update questions" do
|
|
|
85
85
|
|
|
86
86
|
expect(page).to have_admin_callout("successfully")
|
|
87
87
|
|
|
88
|
-
click_on "
|
|
88
|
+
click_on "Questions"
|
|
89
89
|
|
|
90
90
|
expect(page).to have_css(".questionnaire-question", count: 0)
|
|
91
91
|
end
|
|
@@ -169,7 +169,7 @@ shared_examples_for "update questions" do
|
|
|
169
169
|
|
|
170
170
|
expect(page).to have_admin_callout("successfully")
|
|
171
171
|
|
|
172
|
-
click_on "
|
|
172
|
+
click_on "Questions"
|
|
173
173
|
|
|
174
174
|
expect(page).to have_css(".questionnaire-question", count: 0)
|
|
175
175
|
end
|
|
@@ -187,7 +187,7 @@ shared_examples_for "update questions" do
|
|
|
187
187
|
end
|
|
188
188
|
end
|
|
189
189
|
|
|
190
|
-
context "when a questionnaire has an existing question with
|
|
190
|
+
context "when a questionnaire has an existing question with response options" do
|
|
191
191
|
let!(:question) do
|
|
192
192
|
create(
|
|
193
193
|
:questionnaire_question,
|
|
@@ -205,13 +205,13 @@ shared_examples_for "update questions" do
|
|
|
205
205
|
|
|
206
206
|
before do
|
|
207
207
|
click_on "Save"
|
|
208
|
-
click_on "
|
|
208
|
+
click_on "Questions"
|
|
209
209
|
end
|
|
210
210
|
|
|
211
|
-
it "allows deleting
|
|
211
|
+
it "allows deleting response options" do
|
|
212
212
|
expand_all_questions
|
|
213
213
|
|
|
214
|
-
within ".questionnaire-question-
|
|
214
|
+
within ".questionnaire-question-response-option:last-of-type" do
|
|
215
215
|
click_on "Remove"
|
|
216
216
|
end
|
|
217
217
|
|
|
@@ -219,7 +219,7 @@ shared_examples_for "update questions" do
|
|
|
219
219
|
|
|
220
220
|
visit_manage_questions_and_expand_all
|
|
221
221
|
|
|
222
|
-
expect(page).to have_css(".questionnaire-question-
|
|
222
|
+
expect(page).to have_css(".questionnaire-question-response-option", count: 2)
|
|
223
223
|
end
|
|
224
224
|
|
|
225
225
|
it "still removes the question even if previous editions rendered the options invalid" do
|
|
@@ -227,7 +227,7 @@ shared_examples_for "update questions" do
|
|
|
227
227
|
|
|
228
228
|
expand_all_questions
|
|
229
229
|
|
|
230
|
-
within ".questionnaire-question-
|
|
230
|
+
within ".questionnaire-question-response-option:first-of-type" do
|
|
231
231
|
fill_in find_nested_form_field_locator("body_en"), with: ""
|
|
232
232
|
end
|
|
233
233
|
|
|
@@ -283,7 +283,7 @@ shared_examples_for "update questions" do
|
|
|
283
283
|
|
|
284
284
|
within ".questionnaire-question:last-of-type" do
|
|
285
285
|
expect(page).to have_css(".questionnaire-question-matrix-row", count: 2)
|
|
286
|
-
expect(page).to have_css(".questionnaire-question-
|
|
286
|
+
expect(page).to have_css(".questionnaire-question-response-option", count: 3)
|
|
287
287
|
end
|
|
288
288
|
end
|
|
289
289
|
|
|
@@ -317,10 +317,6 @@ shared_examples_for "update questions" do
|
|
|
317
317
|
create(:questionnaire_question, questionnaire:, body: second_body, position: 1)
|
|
318
318
|
end
|
|
319
319
|
|
|
320
|
-
let!(:question3) do
|
|
321
|
-
create(:questionnaire_question, questionnaire:, body: third_body, position: 2)
|
|
322
|
-
end
|
|
323
|
-
|
|
324
320
|
let(:first_body) do
|
|
325
321
|
{ en: "First", ca: "Primera", es: "Primera" }
|
|
326
322
|
end
|
|
@@ -329,10 +325,6 @@ shared_examples_for "update questions" do
|
|
|
329
325
|
{ en: "Second", ca: "Segona", es: "Segunda" }
|
|
330
326
|
end
|
|
331
327
|
|
|
332
|
-
let(:third_body) do
|
|
333
|
-
{ en: "Third", ca: "Tercera", es: "Tercera" }
|
|
334
|
-
end
|
|
335
|
-
|
|
336
328
|
before do
|
|
337
329
|
click_on "Save"
|
|
338
330
|
visit_manage_questions_and_expand_all
|
|
@@ -352,6 +344,26 @@ shared_examples_for "update questions" do
|
|
|
352
344
|
end
|
|
353
345
|
end
|
|
354
346
|
|
|
347
|
+
context "when moving a question up" do
|
|
348
|
+
before do
|
|
349
|
+
within ".questionnaire-question:last-of-type" do
|
|
350
|
+
click_on "Up"
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
it_behaves_like "switching questions order"
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
context "when moving a question down" do
|
|
358
|
+
before do
|
|
359
|
+
within ".questionnaire-question:first-of-type" do
|
|
360
|
+
click_on "Down"
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
it_behaves_like "switching questions order"
|
|
365
|
+
end
|
|
366
|
+
|
|
355
367
|
describe "collapsible questions" do
|
|
356
368
|
context "when clicking on Expand all button" do
|
|
357
369
|
it "expands all questions" do
|
|
@@ -447,37 +459,16 @@ shared_examples_for "update questions" do
|
|
|
447
459
|
click_on "Add question"
|
|
448
460
|
expand_all_questions
|
|
449
461
|
|
|
450
|
-
|
|
451
|
-
expect(
|
|
452
|
-
|
|
453
|
-
within question_cards[1] do
|
|
454
|
-
expect(find("input[name*='[body_en]']").value).to eq("Second")
|
|
455
|
-
end
|
|
456
|
-
within question_cards[2] do
|
|
457
|
-
expect(find("input[name*='[body_en]']").value).to eq("Third")
|
|
458
|
-
end
|
|
462
|
+
expect(page.find(".questionnaire-question:nth-of-type(1)")).to look_like_first_question
|
|
463
|
+
expect(page.find(".questionnaire-question:nth-of-type(2)")).to look_like_intermediate_question
|
|
464
|
+
expect(page.find(".questionnaire-question:nth-of-type(3)")).to look_like_last_question
|
|
459
465
|
|
|
460
466
|
within ".questionnaire-question:first-of-type" do
|
|
461
467
|
click_on "Remove"
|
|
462
468
|
end
|
|
463
469
|
|
|
464
|
-
|
|
465
|
-
expect(
|
|
466
|
-
|
|
467
|
-
# Check that the first question is now what was previously the second
|
|
468
|
-
within remaining_cards.first do
|
|
469
|
-
expect(find("input[name*='[body_en]']").value).to eq("Second")
|
|
470
|
-
end
|
|
471
|
-
|
|
472
|
-
# Check that the second question is now what was previously the third
|
|
473
|
-
within remaining_cards[1] do
|
|
474
|
-
expect(find("input[name*='[body_en]']").value).to eq("Third")
|
|
475
|
-
end
|
|
476
|
-
|
|
477
|
-
# The last question should be the new empty question
|
|
478
|
-
within remaining_cards.last do
|
|
479
|
-
expect(find("input[name*='[body_en]']").value).to eq("")
|
|
480
|
-
end
|
|
470
|
+
expect(page.all(".questionnaire-question").first).to look_like_first_question
|
|
471
|
+
expect(page.all(".questionnaire-question").last).to look_like_last_question
|
|
481
472
|
end
|
|
482
473
|
|
|
483
474
|
it "does not duplicate editors when adding new questions" do
|
|
@@ -487,26 +478,26 @@ shared_examples_for "update questions" do
|
|
|
487
478
|
end.to change { page.all(".editor-toolbar").size }.by(1)
|
|
488
479
|
end
|
|
489
480
|
|
|
490
|
-
it "properly decides which button to show after adding/removing
|
|
481
|
+
it "properly decides which button to show after adding/removing response options" do
|
|
491
482
|
click_on "Add question"
|
|
492
483
|
expand_all_questions
|
|
493
484
|
|
|
494
485
|
within ".questionnaire-question:last-of-type" do
|
|
495
486
|
select "Single option", from: "Type"
|
|
496
487
|
|
|
497
|
-
within ".questionnaire-question-
|
|
488
|
+
within ".questionnaire-question-response-options-list" do
|
|
498
489
|
expect(page).to have_no_button("Remove")
|
|
499
490
|
end
|
|
500
491
|
|
|
501
|
-
click_on "Add
|
|
492
|
+
click_on "Add response option"
|
|
502
493
|
|
|
503
|
-
expect(page.all(".questionnaire-question-
|
|
494
|
+
expect(page.all(".questionnaire-question-response-option")).to all(have_button("Remove"))
|
|
504
495
|
|
|
505
|
-
within ".questionnaire-question-
|
|
496
|
+
within ".questionnaire-question-response-option:first-of-type" do
|
|
506
497
|
click_on "Remove"
|
|
507
498
|
end
|
|
508
499
|
|
|
509
|
-
within ".questionnaire-question-
|
|
500
|
+
within ".questionnaire-question-response-options-list" do
|
|
510
501
|
expect(page).to have_no_button("Remove")
|
|
511
502
|
end
|
|
512
503
|
end
|
|
@@ -515,100 +506,12 @@ shared_examples_for "update questions" do
|
|
|
515
506
|
expand_all_questions
|
|
516
507
|
|
|
517
508
|
within ".questionnaire-question:last-of-type" do
|
|
518
|
-
within ".questionnaire-question-
|
|
509
|
+
within ".questionnaire-question-response-options-list" do
|
|
519
510
|
expect(page).to have_no_button("Remove")
|
|
520
511
|
end
|
|
521
512
|
end
|
|
522
513
|
end
|
|
523
514
|
|
|
524
|
-
context "when reordering questions with drag and drop", :js do
|
|
525
|
-
before do
|
|
526
|
-
expand_all_questions
|
|
527
|
-
end
|
|
528
|
-
|
|
529
|
-
it "allows moving questions using drag and drop" do
|
|
530
|
-
question_cards = all(".questionnaire-question")
|
|
531
|
-
|
|
532
|
-
# Verify initial order by checking the body field values
|
|
533
|
-
within question_cards[0] do
|
|
534
|
-
expect(find("input[name*='[body_en]']").value).to eq("First")
|
|
535
|
-
end
|
|
536
|
-
within question_cards[1] do
|
|
537
|
-
expect(find("input[name*='[body_en]']").value).to eq("Second")
|
|
538
|
-
end
|
|
539
|
-
within question_cards[2] do
|
|
540
|
-
expect(find("input[name*='[body_en]']").value).to eq("Third")
|
|
541
|
-
end
|
|
542
|
-
|
|
543
|
-
# JavaScript to simulate drag and drop.
|
|
544
|
-
page.execute_script(<<~JS)
|
|
545
|
-
var questions = document.querySelectorAll('.questionnaire-question');
|
|
546
|
-
var container = questions[0].parentNode;
|
|
547
|
-
var second = questions[1];
|
|
548
|
-
var first = questions[0];
|
|
549
|
-
|
|
550
|
-
// Move second question before first
|
|
551
|
-
container.insertBefore(second, first);
|
|
552
|
-
|
|
553
|
-
// Update position values
|
|
554
|
-
var updatedQuestions = container.querySelectorAll('.questionnaire-question');
|
|
555
|
-
updatedQuestions.forEach(function(question, index) {
|
|
556
|
-
var positionInput = question.querySelector('input[name$="[position]"]');
|
|
557
|
-
if (positionInput) positionInput.value = index;
|
|
558
|
-
});
|
|
559
|
-
JS
|
|
560
|
-
|
|
561
|
-
sleep 0.5
|
|
562
|
-
|
|
563
|
-
question_cards = all(".questionnaire-question")
|
|
564
|
-
within question_cards[0] do
|
|
565
|
-
expect(find("input[name*='[body_en]']").value).to eq("Second")
|
|
566
|
-
end
|
|
567
|
-
within question_cards[1] do
|
|
568
|
-
expect(find("input[name*='[body_en]']").value).to eq("First")
|
|
569
|
-
end
|
|
570
|
-
within question_cards[2] do
|
|
571
|
-
expect(find("input[name*='[body_en]']").value).to eq("Third")
|
|
572
|
-
end
|
|
573
|
-
end
|
|
574
|
-
|
|
575
|
-
it "persists drag and drop changes when saving" do
|
|
576
|
-
# Move second question to last position
|
|
577
|
-
page.execute_script(<<~JS)
|
|
578
|
-
var questions = document.querySelectorAll('.questionnaire-question');
|
|
579
|
-
var container = questions[0].parentNode;
|
|
580
|
-
var second = questions[1];
|
|
581
|
-
|
|
582
|
-
container.appendChild(second);
|
|
583
|
-
|
|
584
|
-
// Update the positions of questions
|
|
585
|
-
var updatedQuestions = container.querySelectorAll('.questionnaire-question');
|
|
586
|
-
updatedQuestions.forEach(function(question, index) {
|
|
587
|
-
var positionInput = question.querySelector('input[name$="[position]"]');
|
|
588
|
-
if (positionInput) positionInput.value = index;
|
|
589
|
-
});
|
|
590
|
-
JS
|
|
591
|
-
|
|
592
|
-
sleep 0.5
|
|
593
|
-
|
|
594
|
-
click_on "Save"
|
|
595
|
-
expect(page).to have_admin_callout("successfully")
|
|
596
|
-
|
|
597
|
-
visit_manage_questions_and_expand_all
|
|
598
|
-
|
|
599
|
-
question_cards = all(".questionnaire-question")
|
|
600
|
-
within question_cards[0] do
|
|
601
|
-
expect(find("input[name*='[body_en]']").value).to eq("First")
|
|
602
|
-
end
|
|
603
|
-
within question_cards[1] do
|
|
604
|
-
expect(find("input[name*='[body_en]']").value).to eq("Third")
|
|
605
|
-
end
|
|
606
|
-
within question_cards[2] do
|
|
607
|
-
expect(find("input[name*='[body_en]']").value).to eq("Second")
|
|
608
|
-
end
|
|
609
|
-
end
|
|
610
|
-
end
|
|
611
|
-
|
|
612
515
|
private
|
|
613
516
|
|
|
614
517
|
def look_like_first_question
|
|
@@ -24,7 +24,7 @@ shared_examples_for "manage questionnaires" do
|
|
|
24
24
|
}
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
context "when the questionnaire is not already
|
|
27
|
+
context "when the questionnaire is not already responded" do
|
|
28
28
|
before do
|
|
29
29
|
visit manage_questions_path
|
|
30
30
|
end
|
|
@@ -35,9 +35,9 @@ shared_examples_for "manage questionnaires" do
|
|
|
35
35
|
it_behaves_like "update display conditions"
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
context "when the questionnaire is already
|
|
38
|
+
context "when the questionnaire is already responded" do
|
|
39
39
|
let!(:question) { create(:questionnaire_question, questionnaire:, body:, question_type: "multiple_option") }
|
|
40
|
-
let!(:
|
|
40
|
+
let!(:response) { create(:response, questionnaire:, question:) }
|
|
41
41
|
|
|
42
42
|
it "cannot modify questionnaire questions" do
|
|
43
43
|
visit manage_questions_path
|
|
@@ -92,7 +92,7 @@ shared_examples_for "manage questionnaires" do
|
|
|
92
92
|
end
|
|
93
93
|
|
|
94
94
|
def visit_manage_questions_and_expand_all
|
|
95
|
-
click_on "
|
|
95
|
+
click_on "Questions"
|
|
96
96
|
expand_all_questions
|
|
97
97
|
end
|
|
98
98
|
end
|
data/lib/decidim/forms/test.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "decidim/forms/test/shared_examples/has_questionnaire"
|
|
4
4
|
require "decidim/forms/test/shared_examples/manage_questionnaires"
|
|
5
|
-
require "decidim/forms/test/shared_examples/
|
|
5
|
+
require "decidim/forms/test/shared_examples/manage_questionnaire_responses"
|
|
6
6
|
|
|
7
7
|
if defined? Decidim::Templates
|
|
8
8
|
require "decidim/templates/test/shared_examples/uses_questionnaire_templates"
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Forms
|
|
5
|
+
# This class serializes the responses given by a User for questionnaire so can be
|
|
6
|
+
# exported to CSV, JSON or other formats.
|
|
7
|
+
class UserResponsesSerializer < Decidim::Exporters::Serializer
|
|
8
|
+
include Decidim::TranslationsHelper
|
|
9
|
+
|
|
10
|
+
# Public: Initializes the serializer with a collection of Responses.
|
|
11
|
+
def initialize(responses)
|
|
12
|
+
@responses = responses
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# i18n-tasks-use t('decidim.forms.user_responses_serializer.body')
|
|
16
|
+
# i18n-tasks-use t('decidim.forms.user_responses_serializer.id')
|
|
17
|
+
# i18n-tasks-use t('decidim.forms.user_responses_serializer.question')
|
|
18
|
+
# i18n-tasks-use t('decidim.forms.user_responses_serializer.registered')
|
|
19
|
+
# i18n-tasks-use t('decidim.forms.user_responses_serializer.unregistered')
|
|
20
|
+
# Public: Exports a hash with the serialized data for the user responses.
|
|
21
|
+
def serialize
|
|
22
|
+
responses_hash = hash_for(@responses.first)
|
|
23
|
+
responses_hash.merge!(questions_hash)
|
|
24
|
+
|
|
25
|
+
@responses.each do |response|
|
|
26
|
+
responses_hash[translated_question_key(response.question.position, response.question.body)] = normalize_body(response)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
responses_hash
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
attr_reader :responses
|
|
35
|
+
alias resource responses
|
|
36
|
+
|
|
37
|
+
def hash_for(response)
|
|
38
|
+
{
|
|
39
|
+
response_translated_attribute_name(:id) => response&.session_token,
|
|
40
|
+
response_translated_attribute_name(:created_at) => response&.created_at,
|
|
41
|
+
response_translated_attribute_name(:ip_hash) => response&.ip_hash,
|
|
42
|
+
response_translated_attribute_name(:user_status) => response_translated_attribute_name(response&.decidim_user_id.present? ? "registered" : "unregistered")
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def questions_hash
|
|
47
|
+
questionnaire_id = @responses.first&.decidim_questionnaire_id
|
|
48
|
+
return {} unless questionnaire_id
|
|
49
|
+
|
|
50
|
+
questions = Decidim::Forms::Question.where(decidim_questionnaire_id: questionnaire_id).order(:position)
|
|
51
|
+
return {} if questions.none?
|
|
52
|
+
|
|
53
|
+
questions.each.inject({}) do |serialized, question|
|
|
54
|
+
serialized.update(
|
|
55
|
+
translated_question_key(question.position, question.body) => ""
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def translated_question_key(idx, body)
|
|
61
|
+
"#{idx + 1}. #{translated_attribute(body)}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def normalize_body(response)
|
|
65
|
+
response.body ||
|
|
66
|
+
normalize_attachments(response) ||
|
|
67
|
+
normalize_choices(response, response.choices)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def normalize_attachments(response)
|
|
71
|
+
return if response.attachments.blank?
|
|
72
|
+
|
|
73
|
+
response.attachments.map(&:url)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def normalize_choices(response, choices)
|
|
77
|
+
if response.question.matrix?
|
|
78
|
+
normalize_matrix_choices(response, choices)
|
|
79
|
+
else
|
|
80
|
+
choices.map do |choice|
|
|
81
|
+
format_free_text_for choice
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def normalize_matrix_choices(response, choices)
|
|
87
|
+
response.question.matrix_rows.to_h do |matrix_row|
|
|
88
|
+
row_body = translated_attribute(matrix_row.body)
|
|
89
|
+
|
|
90
|
+
row_choices = response.question.response_options.map do |response_option|
|
|
91
|
+
choice = choices.find_by(matrix_row:, response_option:)
|
|
92
|
+
choice.try(:custom_body) || choice.try(:body)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
[row_body, row_choices]
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def response_translated_attribute_name(attribute)
|
|
100
|
+
I18n.t(attribute.to_sym, scope: "decidim.forms.user_responses_serializer")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def format_free_text_for(choice)
|
|
104
|
+
return choice.try(:body) if choice.try(:custom_body).blank?
|
|
105
|
+
|
|
106
|
+
"#{choice.try(:body)} (#{choice.try(:custom_body)})"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
data/lib/decidim/forms.rb
CHANGED
|
@@ -8,8 +8,8 @@ require "decidim/forms/admin_engine"
|
|
|
8
8
|
module Decidim
|
|
9
9
|
# This namespace holds the logic of the `Forms`.
|
|
10
10
|
module Forms
|
|
11
|
-
autoload :
|
|
12
|
-
autoload :
|
|
11
|
+
autoload :UserResponsesSerializer, "decidim/forms/user_responses_serializer"
|
|
12
|
+
autoload :DownloadYourDataUserResponsesSerializer, "decidim/forms/download_your_data_user_responses_serializer"
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
module Exporters
|