decidim-forms 0.29.2 → 0.30.0.rc2

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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/forms/step_navigation_cell.rb +18 -5
  3. data/app/commands/decidim/forms/admin/update_questionnaire.rb +1 -82
  4. data/app/commands/decidim/forms/admin/update_questions.rb +109 -0
  5. data/app/commands/decidim/forms/answer_questionnaire.rb +10 -3
  6. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +39 -3
  7. data/app/controllers/decidim/forms/admin/concerns/has_questionnaire_answers.rb +2 -2
  8. data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +12 -4
  9. data/app/forms/decidim/forms/admin/display_condition_form.rb +1 -1
  10. data/app/forms/decidim/forms/admin/questionnaire_form.rb +0 -9
  11. data/app/forms/decidim/forms/admin/questions_form.rb +18 -0
  12. data/app/forms/decidim/forms/answer_choice_form.rb +5 -0
  13. data/app/forms/decidim/forms/answer_form.rb +1 -0
  14. data/app/forms/decidim/forms/questionnaire_form.rb +7 -0
  15. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_pagination_helper.rb +1 -1
  16. data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_url_helper.rb +5 -5
  17. data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +5 -1
  18. data/app/models/decidim/forms/answer_choice.rb +0 -2
  19. data/app/models/decidim/forms/answer_option.rb +1 -1
  20. data/app/models/decidim/forms/question.rb +10 -0
  21. data/app/packs/entrypoints/decidim_forms.js +0 -1
  22. data/app/packs/entrypoints/decidim_forms_admin.js +6 -0
  23. data/app/packs/src/decidim/forms/admin/publish_answers_buttons.js +72 -0
  24. data/app/packs/src/decidim/forms/forms.js +22 -18
  25. data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +1 -1
  26. data/app/presenters/decidim/forms/admin_log/question_presenter.rb +31 -0
  27. data/app/queries/decidim/forms/questionnaire_user_answers.rb +1 -1
  28. data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +1 -1
  29. data/app/views/decidim/forms/admin/questionnaires/_display_condition_template.html.erb +1 -1
  30. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +0 -89
  31. data/app/views/decidim/forms/admin/questionnaires/_matrix_row_template.html.erb +1 -1
  32. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +3 -3
  33. data/app/views/decidim/forms/admin/questionnaires/_questions_form.html.erb +80 -0
  34. data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +0 -20
  35. data/app/views/decidim/forms/admin/questionnaires/edit_questions.html.erb +47 -0
  36. data/app/views/decidim/forms/questionnaires/_questionnaire.html.erb +8 -1
  37. data/app/views/decidim/forms/questionnaires/answers/_files.html.erb +1 -1
  38. data/app/views/decidim/forms/questionnaires/answers/_sorting.html.erb +12 -6
  39. data/app/views/decidim/forms/questionnaires/edit.html.erb +47 -0
  40. data/app/views/decidim/forms/questionnaires/show.html.erb +13 -2
  41. data/config/assets.rb +1 -2
  42. data/config/locales/bg.yml +0 -2
  43. data/config/locales/ca.yml +46 -6
  44. data/config/locales/cs.yml +45 -5
  45. data/config/locales/de.yml +45 -5
  46. data/config/locales/el.yml +0 -2
  47. data/config/locales/en.yml +45 -5
  48. data/config/locales/es-MX.yml +45 -5
  49. data/config/locales/es-PY.yml +45 -5
  50. data/config/locales/es.yml +45 -5
  51. data/config/locales/eu.yml +45 -5
  52. data/config/locales/fi-plain.yml +45 -5
  53. data/config/locales/fi.yml +45 -5
  54. data/config/locales/fr-CA.yml +37 -5
  55. data/config/locales/fr.yml +37 -5
  56. data/config/locales/ja.yml +46 -1
  57. data/config/locales/lt.yml +0 -2
  58. data/config/locales/pl.yml +0 -2
  59. data/config/locales/ro-RO.yml +22 -17
  60. data/config/locales/zh-TW.yml +0 -2
  61. data/db/migrate/20190315203056_add_session_token_to_decidim_forms_answers.rb +1 -1
  62. data/db/migrate/20241122142230_add_survey_answers_published_at_to_questions.rb +7 -0
  63. data/decidim-forms.gemspec +1 -2
  64. data/lib/decidim/api/answer_option_type.rb +1 -1
  65. data/lib/decidim/api/question_type.rb +4 -4
  66. data/lib/decidim/api/questionnaire_type.rb +4 -4
  67. data/lib/decidim/exporters/form_pdf.rb +114 -11
  68. data/lib/decidim/forms/download_your_data_user_answers_serializer.rb +0 -4
  69. data/lib/decidim/forms/test/factories.rb +2 -2
  70. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +44 -4
  71. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +17 -17
  72. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +19 -21
  73. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +70 -94
  74. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +15 -18
  75. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +90 -125
  76. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +4 -25
  77. data/lib/decidim/forms/version.rb +1 -1
  78. data/lib/decidim/forms.rb +0 -1
  79. metadata +18 -32
  80. data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.js +0 -1
  81. data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.scss +0 -1
  82. data/app/packs/stylesheets/decidim/forms/questionnaire-answers-pdf.scss +0 -69
  83. data/app/views/decidim/forms/admin/questionnaires/answers/export/_answer.html.erb +0 -31
  84. data/app/views/decidim/forms/admin/questionnaires/answers/export/pdf.html.erb +0 -13
  85. data/app/views/layouts/decidim/forms/admin/questionnaires/questionnaire_answers.html.erb +0 -12
  86. data/config/initializers/wicked_pdf.rb +0 -26
  87. data/lib/decidim/exporters/form_pdf_controller_helper.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6139d10d03807b7f5cd8dde3b4142988b788f9938d7af7865484a83a02395a5f
4
- data.tar.gz: b8a81a8442bf4bcdf0af280a4afa3cbc7f0dd31bef6c6d429f7096517fb33d6f
3
+ metadata.gz: f4c080cf4b74aa801c82210112648094d7f7f8c938c0343e8cffa97087ffe372
4
+ data.tar.gz: af06a9fd9157416757f30ea10d4e736ed8b0c10a9bda17644aa9aba2095d08c7
5
5
  SHA512:
6
- metadata.gz: d92feb78364974122b61f1440d5f34056bad5fcfc45b68e474b3d0ad6c397bd0294ca04f10ee7a3fff98a94f5e1f0c428fc89f2cafc021ce25e7323845e674e0
7
- data.tar.gz: 12b71b8d781e6262dad4b1f9a7f32e78766f27f204dd39fa7b645b9d388d2d9435dc6de552dc9aad86307f45b6399e1cfc1df12ca2dd647053bff5c702828604
6
+ metadata.gz: da06fab2cc22f16184e8929dc1509693656b5704956b0f76e2d2d17f758df17fb7495f7e2633bde2d597d48d90a8dc6817867d91443e8cb78dd7cd12fc9bee10
7
+ data.tar.gz: f85cd3907a641d5b5b5d20cebac78ae7dd6139d6e9bb7a97e2a1eb4918242922dad588d023740ad95f13ca06582efef6dba0553b96c942fef6319df9b3b5d987
@@ -40,12 +40,25 @@ module Decidim
40
40
  "step-#{current_step_index}"
41
41
  end
42
42
 
43
+ def allow_editing_answers?
44
+ options[:allow_editing_answers]
45
+ end
46
+
43
47
  def confirm_data
44
- { data: {
45
- confirm: t("decidim.forms.step_navigation.show.are_you_sure"),
46
- disable: true,
47
- data: "survey-buttons"
48
- } }
48
+ {
49
+ data: {
50
+ confirm:,
51
+ disable: true,
52
+ data: "survey-buttons"
53
+ }
54
+ }
55
+ end
56
+
57
+ def confirm
58
+ return t("decidim.forms.step_navigation.show.are_you_sure_no_edit") unless allow_editing_answers?
59
+ return t("decidim.forms.step_navigation.show.are_you_sure_edit_guest") unless current_user
60
+
61
+ t("decidim.forms.step_navigation.show.are_you_sure_edit")
49
62
  end
50
63
  end
51
64
  end
@@ -25,14 +25,7 @@ module Decidim
25
25
  Decidim.traceability.perform_action!("update",
26
26
  @questionnaire,
27
27
  @user) do
28
- Decidim::Forms::Questionnaire.transaction do
29
- if @questionnaire.questions_editable?
30
- update_questionnaire_questions
31
- delete_answers unless @questionnaire.published?
32
- end
33
-
34
- update_questionnaire
35
- end
28
+ update_questionnaire
36
29
  end
37
30
 
38
31
  broadcast(:ok)
@@ -40,85 +33,11 @@ module Decidim
40
33
 
41
34
  private
42
35
 
43
- def update_questionnaire_questions
44
- @form.questions.each do |form_question|
45
- update_questionnaire_question(form_question)
46
- end
47
- end
48
-
49
- def update_questionnaire_question(form_question)
50
- question_attributes = {
51
- body: form_question.body,
52
- description: form_question.description,
53
- position: form_question.position,
54
- mandatory: form_question.mandatory,
55
- question_type: form_question.question_type,
56
- max_choices: form_question.max_choices,
57
- max_characters: form_question.max_characters
58
- }
59
-
60
- update_nested_model(form_question, question_attributes, @questionnaire.questions) do |question|
61
- form_question.answer_options.each do |form_answer_option|
62
- answer_option_attributes = {
63
- body: form_answer_option.body,
64
- free_text: form_answer_option.free_text
65
- }
66
-
67
- update_nested_model(form_answer_option, answer_option_attributes, question.answer_options)
68
- end
69
-
70
- form_question.display_conditions.each do |form_display_condition|
71
- type = form_display_condition.condition_type
72
-
73
- display_condition_attributes = {
74
- condition_question: form_display_condition.condition_question,
75
- condition_type: form_display_condition.condition_type,
76
- condition_value: type == "match" ? form_display_condition.condition_value : nil,
77
- answer_option: %w(equal not_equal).include?(type) ? form_display_condition.answer_option : nil,
78
- mandatory: form_display_condition.mandatory
79
- }
80
-
81
- next if form_display_condition.deleted? && form_display_condition.id.blank?
82
-
83
- update_nested_model(form_display_condition, display_condition_attributes, question.display_conditions)
84
- end
85
-
86
- form_question.matrix_rows_by_position.each_with_index do |form_matrix_row, idx|
87
- matrix_row_attributes = {
88
- body: form_matrix_row.body,
89
- position: form_matrix_row.position || idx
90
- }
91
-
92
- update_nested_model(form_matrix_row, matrix_row_attributes, question.matrix_rows)
93
- end
94
- end
95
- end
96
-
97
- def update_nested_model(form, attributes, parent_association)
98
- record = parent_association.find_by(id: form.id) || parent_association.build(attributes)
99
-
100
- yield record if block_given?
101
-
102
- if record.persisted?
103
- if form.deleted?
104
- record.destroy!
105
- else
106
- record.update!(attributes)
107
- end
108
- else
109
- record.save!
110
- end
111
- end
112
-
113
36
  def update_questionnaire
114
37
  @questionnaire.update!(title: @form.title,
115
38
  description: @form.description,
116
39
  tos: @form.tos)
117
40
  end
118
-
119
- def delete_answers
120
- @questionnaire.answers.destroy_all
121
- end
122
41
  end
123
42
  end
124
43
  end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Forms
5
+ module Admin
6
+ # This command is executed when the user changes a Questionnaire questions from the admin
7
+ # panel.
8
+ class UpdateQuestions < Decidim::Command
9
+ # Initializes a UpdateQuestions Command.
10
+ #
11
+ # form - The form from which to get the data.
12
+ # questionnaire - The current instance of the questionnaire questions to be updated.
13
+ def initialize(form, questionnaire)
14
+ @form = form
15
+ @questionnaire = questionnaire
16
+ end
17
+
18
+ # Updates the questionnaire if valid.
19
+ #
20
+ # Broadcasts :ok if successful, :invalid otherwise.
21
+ def call
22
+ return broadcast(:invalid) if @form.invalid?
23
+
24
+ Decidim.traceability.perform_action!("update",
25
+ @questionnaire,
26
+ @form.current_user) do
27
+ Decidim::Forms::Questionnaire.transaction do
28
+ update_questionnaire_questions if @questionnaire.questions_editable?
29
+ end
30
+ end
31
+
32
+ broadcast(:ok)
33
+ end
34
+
35
+ private
36
+
37
+ def update_questionnaire_questions
38
+ @form.questions.each do |form_question|
39
+ update_questionnaire_question(form_question)
40
+ end
41
+ end
42
+
43
+ def update_questionnaire_question(form_question)
44
+ question_attributes = {
45
+ body: form_question.body,
46
+ description: form_question.description,
47
+ position: form_question.position,
48
+ mandatory: form_question.mandatory,
49
+ question_type: form_question.question_type,
50
+ max_choices: form_question.max_choices,
51
+ max_characters: form_question.max_characters
52
+ }
53
+
54
+ update_nested_model(form_question, question_attributes, @questionnaire.questions) do |question|
55
+ form_question.answer_options.each do |form_answer_option|
56
+ answer_option_attributes = {
57
+ body: form_answer_option.body,
58
+ free_text: form_answer_option.free_text
59
+ }
60
+
61
+ update_nested_model(form_answer_option, answer_option_attributes, question.answer_options)
62
+ end
63
+
64
+ form_question.display_conditions.each do |form_display_condition|
65
+ type = form_display_condition.condition_type
66
+
67
+ display_condition_attributes = {
68
+ condition_question: form_display_condition.condition_question,
69
+ condition_type: form_display_condition.condition_type,
70
+ condition_value: type == "match" ? form_display_condition.condition_value : nil,
71
+ answer_option: %w(equal not_equal).include?(type) ? form_display_condition.answer_option : nil,
72
+ mandatory: form_display_condition.mandatory
73
+ }
74
+
75
+ next if form_display_condition.deleted? && form_display_condition.id.blank?
76
+
77
+ update_nested_model(form_display_condition, display_condition_attributes, question.display_conditions)
78
+ end
79
+
80
+ form_question.matrix_rows_by_position.each_with_index do |form_matrix_row, idx|
81
+ matrix_row_attributes = {
82
+ body: form_matrix_row.body,
83
+ position: form_matrix_row.position || idx
84
+ }
85
+
86
+ update_nested_model(form_matrix_row, matrix_row_attributes, question.matrix_rows)
87
+ end
88
+ end
89
+ end
90
+
91
+ def update_nested_model(form, attributes, parent_association)
92
+ record = parent_association.find_by(id: form.id) || parent_association.build(attributes)
93
+
94
+ yield record if block_given?
95
+
96
+ if record.persisted?
97
+ if form.deleted?
98
+ record.destroy!
99
+ else
100
+ record.update!(attributes)
101
+ end
102
+ else
103
+ record.save!
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -11,18 +11,21 @@ module Decidim
11
11
  #
12
12
  # form - The form from which to get the data.
13
13
  # questionnaire - The current instance of the questionnaire to be answered.
14
- def initialize(form, questionnaire)
14
+ # allow_editing_answers - Flag that ensures a form can or cannot be editable after the questionnaire's answers have been provided.
15
+ def initialize(form, questionnaire, allow_editing_answers: false)
15
16
  @form = form
16
17
  @questionnaire = questionnaire
18
+ @allow_editing_answers = allow_editing_answers
17
19
  end
18
20
 
19
21
  # Answers a questionnaire if it is valid
20
22
  #
21
23
  # Broadcasts :ok if successful, :invalid otherwise.
22
24
  def call
23
- return broadcast(:invalid) if @form.invalid? || user_already_answered?
25
+ return broadcast(:invalid) if @form.invalid? || (user_already_answered? && !allow_editing_answers)
24
26
 
25
27
  with_events do
28
+ clear_answers! if allow_editing_answers
26
29
  answer_questionnaire
27
30
  end
28
31
 
@@ -34,7 +37,7 @@ module Decidim
34
37
  end
35
38
  end
36
39
 
37
- attr_reader :form, :questionnaire
40
+ attr_reader :form, :questionnaire, :allow_editing_answers
38
41
 
39
42
  private
40
43
 
@@ -75,6 +78,10 @@ module Decidim
75
78
  end
76
79
  end
77
80
 
81
+ def clear_answers!
82
+ Answer.where(questionnaire: questionnaire, user: current_user, session_token: form.context.session_token, ip_hash: form.context.ip_hash).destroy_all
83
+ end
84
+
78
85
  def answer_questionnaire
79
86
  @main_form = @form
80
87
  @errors = nil
@@ -38,13 +38,12 @@ module Decidim
38
38
 
39
39
  @form = form(Admin::QuestionnaireForm).from_model(questionnaire)
40
40
 
41
- render template: "decidim/forms/admin/questionnaires/edit"
41
+ render template: edit_template
42
42
  end
43
43
 
44
44
  def update
45
45
  enforce_permission_to(:update, :questionnaire, questionnaire:)
46
46
 
47
- params["published_at"] = Time.current if params.has_key? "save_and_publish"
48
47
  @form = form(Admin::QuestionnaireForm).from_params(params)
49
48
 
50
49
  Admin::UpdateQuestionnaire.call(@form, questionnaire, current_user) do
@@ -57,7 +56,30 @@ module Decidim
57
56
  on(:invalid) do
58
57
  # i18n-tasks-use t("decidim.forms.admin.questionnaires.update.invalid")
59
58
  flash.now[:alert] = I18n.t("update.invalid", scope: i18n_flashes_scope)
60
- render template: "decidim/forms/admin/questionnaires/edit"
59
+ render template: edit_template
60
+ end
61
+ end
62
+ end
63
+
64
+ def edit_questions
65
+ @form = form(Admin::QuestionsForm).from_model(questionnaire)
66
+
67
+ render template: edit_questions_template
68
+ end
69
+
70
+ # i18n-tasks-use t("decidim.forms.admin.questionnaires.questions_form.update.success")
71
+ # i18n-tasks-use t("decidim.forms.admin.questionnaires.update.invalid")
72
+ def update_questions
73
+ @form = form(Admin::QuestionsForm).from_params(params)
74
+ Admin::UpdateQuestions.call(@form, questionnaire) do
75
+ on(:ok) do
76
+ flash[:notice] = I18n.t("update.success", scope: i18n_questions_flashes_scope)
77
+ redirect_to after_update_url
78
+ end
79
+
80
+ on(:invalid) do
81
+ flash.now[:alert] = I18n.t("update.invalid", scope: i18n_flashes_scope)
82
+ render template: edit_questions_template
61
83
  end
62
84
  end
63
85
  end
@@ -96,6 +118,12 @@ module Decidim
96
118
  raise "#{self.class.name} is expected to implement #public_url"
97
119
  end
98
120
 
121
+ # Implement this method in your controller to set the URL
122
+ # where the user will be render while editing the questionnaire questions
123
+ def edit_questions_template
124
+ "decidim/forms/admin/questionnaires/edit_questions"
125
+ end
126
+
99
127
  # Returns the url to get the answer options json (for the display conditions form)
100
128
  # for the question with id = params[:id]
101
129
  def answer_options_url(params)
@@ -110,10 +138,18 @@ module Decidim
110
138
 
111
139
  private
112
140
 
141
+ def edit_template
142
+ "decidim/forms/admin/questionnaires/edit"
143
+ end
144
+
113
145
  def i18n_flashes_scope
114
146
  "decidim.forms.admin.questionnaires"
115
147
  end
116
148
 
149
+ def i18n_questions_flashes_scope
150
+ "decidim.forms.admin.questionnaires.questions_form"
151
+ end
152
+
117
153
  def questionnaire
118
154
  @questionnaire ||= Questionnaire.find_by(questionnaire_for:)
119
155
  end
@@ -37,7 +37,7 @@ module Decidim
37
37
  def show
38
38
  enforce_permission_to :show, :questionnaire_answers
39
39
 
40
- @participant = participant(participants_query.participant(params[:session_token]))
40
+ @participant = participant(participants_query.participant(params[:id]))
41
41
 
42
42
  render template: "decidim/forms/admin/questionnaires/answers/show"
43
43
  end
@@ -45,7 +45,7 @@ module Decidim
45
45
  def export_response
46
46
  enforce_permission_to :export_response, :questionnaire_answers
47
47
 
48
- session_token = params[:session_token]
48
+ session_token = params[:id]
49
49
  answers = QuestionnaireUserAnswers.for(questionnaire)
50
50
 
51
51
  # i18n-tasks-use t("decidim.forms.admin.questionnaires.answers.export_response.title")
@@ -16,7 +16,7 @@ module Decidim
16
16
  helper Decidim::Forms::ApplicationHelper
17
17
  include FormFactory
18
18
 
19
- helper_method :questionnaire_for, :questionnaire, :allow_answers?, :visitor_can_answer?, :visitor_already_answered?, :update_url, :form_path
19
+ helper_method :questionnaire_for, :questionnaire, :allow_answers?, :visitor_can_answer?, :visitor_already_answered?, :update_url, :visitor_can_edit_answers?, :form_path
20
20
 
21
21
  invisible_captcha on_spam: :spam_detected
22
22
 
@@ -25,20 +25,20 @@ module Decidim
25
25
  render template: "decidim/forms/questionnaires/show"
26
26
  end
27
27
 
28
+ # i18n-tasks-use t("decidim.forms.questionnaires.answer.success")
29
+ # i18n-tasks-use t("decidim.forms.questionnaires.answer.invalid")
28
30
  def answer
29
31
  enforce_permission_to_answer_questionnaire
30
32
 
31
33
  @form = form(Decidim::Forms::QuestionnaireForm).from_params(params, session_token:, ip_hash:)
32
34
 
33
- Decidim::Forms::AnswerQuestionnaire.call(@form, questionnaire) do
35
+ Decidim::Forms::AnswerQuestionnaire.call(@form, questionnaire, allow_editing_answers: allow_editing_answers?) do
34
36
  on(:ok) do
35
- # i18n-tasks-use t("decidim.forms.questionnaires.answer.success")
36
37
  flash[:notice] = I18n.t("answer.success", scope: i18n_flashes_scope)
37
38
  redirect_to after_answer_path
38
39
  end
39
40
 
40
41
  on(:invalid) do
41
- # i18n-tasks-use t("decidim.forms.questionnaires.answer.invalid")
42
42
  flash.now[:alert] = I18n.t("answer.invalid", scope: i18n_flashes_scope)
43
43
  render template: "decidim/forms/questionnaires/show"
44
44
  end
@@ -98,6 +98,14 @@ module Decidim
98
98
 
99
99
  private
100
100
 
101
+ def allow_editing_answers?
102
+ false
103
+ end
104
+
105
+ def visitor_can_edit_answers?
106
+ current_user.present? && questionnaire_for.try(:allow_editing_answers?)
107
+ end
108
+
101
109
  def i18n_flashes_scope
102
110
  "decidim.forms.questionnaires"
103
111
  end
@@ -44,7 +44,7 @@ module Decidim
44
44
  question.translated_body,
45
45
  question.id,
46
46
  {
47
- "disabled" => (question.question_type == "sorting" || question.id == id),
47
+ "disabled" => question.question_type == "sorting" || question.id == id,
48
48
  "data-type" => question.question_type
49
49
  }
50
50
  ]
@@ -11,16 +11,7 @@ module Decidim
11
11
  translatable_attribute :description, Decidim::Attributes::RichText
12
12
  translatable_attribute :tos, Decidim::Attributes::RichText
13
13
 
14
- attribute :published_at, Decidim::Attributes::TimeWithZone
15
- attribute :questions, Array[QuestionForm]
16
-
17
14
  validates :title, :tos, translatable_presence: true
18
-
19
- def map_model(model)
20
- self.questions = model.questions.map do |question|
21
- QuestionForm.from_model(question)
22
- end
23
- end
24
15
  end
25
16
  end
26
17
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Forms
5
+ module Admin
6
+ # This class holds a Form to update questionnaires questions from Decidim's admin panel.
7
+ class QuestionsForm < Decidim::Form
8
+ attribute :questions, Array[QuestionForm]
9
+
10
+ def map_model(model)
11
+ self.questions = model.questions.map do |question|
12
+ QuestionForm.from_model(question)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -11,6 +11,11 @@ module Decidim
11
11
  attribute :matrix_row_id, Integer
12
12
 
13
13
  validates :answer_option_id, presence: true
14
+
15
+ def map_model(model)
16
+ self.answer_option_id = model.decidim_answer_option_id
17
+ self.matrix_row_id = model.decidim_question_matrix_row_id
18
+ end
14
19
  end
15
20
  end
16
21
  end
@@ -44,6 +44,7 @@ module Decidim
44
44
  def map_model(model)
45
45
  self.question_id = model.decidim_question_id
46
46
  self.question = model.question
47
+ self.documents = model.attachments
47
48
 
48
49
  self.choices = model.choices.map do |choice|
49
50
  AnswerChoiceForm.from_model(choice)
@@ -13,6 +13,7 @@ module Decidim
13
13
  attribute :public_participation, Boolean, default: false
14
14
 
15
15
  attribute :tos_agreement, Boolean
16
+ attribute :allow_editing_answers, Boolean, default: false
16
17
 
17
18
  before_validation :before_validation
18
19
 
@@ -28,6 +29,12 @@ module Decidim
28
29
  end
29
30
  end
30
31
 
32
+ def add_answers!(questionnaire:, session_token:, ip_hash:)
33
+ self.responses = questionnaire.questions.map do |question|
34
+ AnswerForm.from_model(Decidim::Forms::Answer.where(question:, user: current_user, session_token:, ip_hash:).first_or_initialize)
35
+ end
36
+ end
37
+
31
38
  # Add other responses to the context so AnswerForm can validate conditional questions
32
39
  def before_validation
33
40
  context.responses = attributes[:responses]
@@ -40,7 +40,7 @@ module Decidim
40
40
  end
41
41
 
42
42
  def current_idx
43
- participant_ids.index(params[:session_token])
43
+ participant_ids.index(params[:id])
44
44
  end
45
45
  end
46
46
  end
@@ -21,17 +21,17 @@ module Decidim
21
21
  # You can implement this method in your controller to change the URL
22
22
  # where the questionnaire participants' info will be shown.
23
23
  def questionnaire_participants_url
24
- url_for([:index, questionnaire.questionnaire_for, { format: nil }])
24
+ url_for([questionnaire.questionnaire_for, { format: nil }])
25
25
  end
26
26
 
27
27
  # You can implement this method in your controller to change the URL
28
28
  # where the user's questionnaire answers will be shown.
29
- def questionnaire_participant_answers_url(session_token)
30
- url_for([:show, questionnaire.questionnaire_for, { session_token: }])
29
+ def questionnaire_participant_answers_url(id)
30
+ url_for([questionnaire.questionnaire_for, { id: }])
31
31
  end
32
32
 
33
- def questionnaire_export_response_url(session_token)
34
- url_for([:export_response, questionnaire.questionnaire_for, { session_token:, format: "pdf" }])
33
+ def questionnaire_export_response_url(id)
34
+ url_for([questionnaire.questionnaire_for, { id:, format: "pdf" }])
35
35
  end
36
36
  end
37
37
  end
@@ -3,6 +3,8 @@
3
3
  module Decidim
4
4
  module Forms
5
5
  class ExportQuestionnaireAnswersJob < ApplicationJob
6
+ include Decidim::PrivateDownloadHelper
7
+
6
8
  queue_as :exports
7
9
 
8
10
  def perform(user, title, answers)
@@ -12,7 +14,9 @@ module Decidim
12
14
  serializer = Decidim::Forms::UserAnswersSerializer
13
15
  export_data = Decidim::Exporters::FormPDF.new(answers, serializer).export
14
16
 
15
- ExportMailer.export(user, title, export_data).deliver_now
17
+ private_export = attach_archive(export_data, title, user)
18
+
19
+ ExportMailer.export(user, private_export).deliver_later
16
20
  end
17
21
  end
18
22
  end
@@ -17,8 +17,6 @@ module Decidim
17
17
  optional: true
18
18
 
19
19
  validates :matrix_row, presence: true, if: -> { answer.question.matrix? }
20
-
21
- default_scope { left_outer_joins(:matrix_row).order(arel_table[:position].asc, Decidim::Forms::QuestionMatrixRow.arel_table[:position].asc, arel_table[:id].asc) }
22
20
  end
23
21
  end
24
22
  end
@@ -9,7 +9,7 @@ module Decidim
9
9
 
10
10
  translatable_fields :body
11
11
 
12
- belongs_to :question, class_name: "Question", foreign_key: "decidim_question_id", counter_cache: true
12
+ belongs_to :question, class_name: "Question", foreign_key: "decidim_question_id", counter_cache: :answer_options_count
13
13
 
14
14
  has_many :display_conditions,
15
15
  class_name: "DisplayCondition",
@@ -47,6 +47,12 @@ module Decidim
47
47
  foreign_key: "decidim_condition_question_id",
48
48
  class_name: "Question"
49
49
 
50
+ has_many :answers,
51
+ class_name: "Answer",
52
+ foreign_key: "decidim_question_id",
53
+ dependent: :destroy,
54
+ inverse_of: :question
55
+
50
56
  validates :question_type, inclusion: { in: TYPES }
51
57
 
52
58
  scope :not_separator, -> { where.not(question_type: SEPARATOR_TYPE) }
@@ -97,6 +103,10 @@ module Decidim
97
103
  def answers_count
98
104
  questionnaire.answers.where(question: self).count
99
105
  end
106
+
107
+ def self.log_presenter_class_for(_log)
108
+ Decidim::Forms::AdminLog::QuestionPresenter
109
+ end
100
110
  end
101
111
  end
102
112
  end
@@ -2,7 +2,6 @@ import "src/decidim/forms/forms"
2
2
 
3
3
  // CSS
4
4
  import "stylesheets/decidim/forms/forms.scss"
5
- import "stylesheets/decidim/forms/questionnaire-answers-pdf.scss"
6
5
 
7
6
  // Images
8
7
  require.context("../images", true)
@@ -1,4 +1,10 @@
1
1
  import "src/decidim/forms/admin/collapsible_questions"
2
2
 
3
3
  import createEditableForm from "src/decidim/forms/admin/forms"
4
+ import createPublicableQuestionAnswersButtons from "src/decidim/forms/admin/publish_answers_buttons"
5
+
4
6
  window.Decidim.createEditableForm = createEditableForm
7
+
8
+ document.addEventListener("DOMContentLoaded", function() {
9
+ document.querySelectorAll("[data-publish-question-answer-action]").forEach((el) => createPublicableQuestionAnswersButtons(el));
10
+ });