decidim-forms 0.29.1 → 0.30.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) 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 +2 -11
  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_option.rb +1 -1
  19. data/app/models/decidim/forms/question.rb +10 -0
  20. data/app/packs/entrypoints/decidim_forms.js +0 -1
  21. data/app/packs/entrypoints/decidim_forms_admin.js +6 -0
  22. data/app/packs/src/decidim/forms/admin/publish_answers_buttons.js +72 -0
  23. data/app/packs/src/decidim/forms/forms.js +22 -18
  24. data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +1 -1
  25. data/app/presenters/decidim/forms/admin_log/question_presenter.rb +31 -0
  26. data/app/queries/decidim/forms/questionnaire_user_answers.rb +1 -1
  27. data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +1 -1
  28. data/app/views/decidim/forms/admin/questionnaires/_display_condition_template.html.erb +1 -1
  29. data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +0 -89
  30. data/app/views/decidim/forms/admin/questionnaires/_matrix_row_template.html.erb +1 -1
  31. data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +3 -3
  32. data/app/views/decidim/forms/admin/questionnaires/_questions_form.html.erb +80 -0
  33. data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +0 -20
  34. data/app/views/decidim/forms/admin/questionnaires/edit_questions.html.erb +47 -0
  35. data/app/views/decidim/forms/questionnaires/_answer.html.erb +11 -1
  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/ar.yml +3 -2
  43. data/config/locales/bg.yml +0 -7
  44. data/config/locales/bn-BD.yml +1 -0
  45. data/config/locales/bs-BA.yml +1 -0
  46. data/config/locales/ca.yml +46 -6
  47. data/config/locales/cs.yml +45 -5
  48. data/config/locales/de.yml +47 -7
  49. data/config/locales/el.yml +0 -7
  50. data/config/locales/en.yml +45 -5
  51. data/config/locales/es-MX.yml +45 -5
  52. data/config/locales/es-PY.yml +45 -5
  53. data/config/locales/es.yml +45 -5
  54. data/config/locales/eu.yml +50 -10
  55. data/config/locales/fi-plain.yml +45 -5
  56. data/config/locales/fi.yml +45 -5
  57. data/config/locales/fr-CA.yml +37 -5
  58. data/config/locales/fr.yml +37 -5
  59. data/config/locales/gl.yml +0 -3
  60. data/config/locales/hu.yml +0 -3
  61. data/config/locales/id-ID.yml +0 -2
  62. data/config/locales/it.yml +0 -4
  63. data/config/locales/ja.yml +1 -6
  64. data/config/locales/lb.yml +0 -4
  65. data/config/locales/lt.yml +0 -7
  66. data/config/locales/lv.yml +0 -3
  67. data/config/locales/nl.yml +0 -5
  68. data/config/locales/no.yml +0 -5
  69. data/config/locales/pl.yml +0 -7
  70. data/config/locales/pt-BR.yml +0 -5
  71. data/config/locales/pt.yml +0 -4
  72. data/config/locales/ro-RO.yml +8 -7
  73. data/config/locales/sk.yml +0 -2
  74. data/config/locales/sv.yml +0 -5
  75. data/config/locales/tr-TR.yml +0 -4
  76. data/config/locales/val-ES.yml +0 -2
  77. data/config/locales/zh-CN.yml +0 -4
  78. data/config/locales/zh-TW.yml +0 -7
  79. data/db/migrate/20190315203056_add_session_token_to_decidim_forms_answers.rb +1 -1
  80. data/db/migrate/20241122142230_add_survey_answers_published_at_to_questions.rb +7 -0
  81. data/decidim-forms.gemspec +2 -7
  82. data/lib/decidim/api/answer_option_type.rb +1 -1
  83. data/lib/decidim/api/question_type.rb +4 -4
  84. data/lib/decidim/api/questionnaire_type.rb +4 -4
  85. data/lib/decidim/exporters/form_pdf.rb +114 -11
  86. data/lib/decidim/forms/download_your_data_user_answers_serializer.rb +0 -4
  87. data/lib/decidim/forms/test/factories.rb +2 -2
  88. data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +70 -4
  89. data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +17 -17
  90. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +19 -21
  91. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +70 -94
  92. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +15 -18
  93. data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +90 -125
  94. data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +4 -25
  95. data/lib/decidim/forms/user_answers_serializer.rb +1 -1
  96. data/lib/decidim/forms/version.rb +1 -1
  97. data/lib/decidim/forms.rb +0 -1
  98. metadata +21 -47
  99. data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.js +0 -1
  100. data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.scss +0 -1
  101. data/app/packs/stylesheets/decidim/forms/questionnaire-answers-pdf.scss +0 -69
  102. data/app/views/decidim/forms/admin/questionnaires/answers/export/_answer.html.erb +0 -31
  103. data/app/views/decidim/forms/admin/questionnaires/answers/export/pdf.html.erb +0 -13
  104. data/app/views/layouts/decidim/forms/admin/questionnaires/questionnaire_answers.html.erb +0 -12
  105. data/config/initializers/wicked_pdf.rb +0 -27
  106. 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: e3538292d4f18c87b2db6997a34a46b00c4bf71803383a5f24a8fbd21b8dc569
4
- data.tar.gz: 9cd1f427d6a6dff2a437c70954edca296f410cef40033096d7ee64c4033cc047
3
+ metadata.gz: 88f55a44bfdc1edbc0cddbc6be9c92218449a7f0cfc0b846815c6be47fa1fe54
4
+ data.tar.gz: c743a5ff7aeca3316201d4cc29bdec1d2f04761c138fcddf2d4885972a5b60a9
5
5
  SHA512:
6
- metadata.gz: 3705165bf5657f09dd1c0abc0b63b8e9695644e80a2f4ea1946e38631dfcdce7da647cc6698c060c76e90fdac306daf3f9347647491a2a68790659e4dc385134
7
- data.tar.gz: 5da1fe15aecb9b91820e69a1e87fea6e30a24e6df3dc332fe917957a5960ca4770424a933b9e447dd4571df971e4697b503519d2d038b3bb08a7103bc91a83fa
6
+ metadata.gz: 92256e91c6951c78dc7579825fbe5ce644b3963d7c50eae712177db4bdd5364157084dad33d5b3a50d057bb540ce6c0e82083c7658a5f9e45189515625ed7009
7
+ data.tar.gz: 4cc6461edd3c41995e38f1f0d80582c5c1e12f5062d5ebbc4a321573d98ff4d2c80758aa7ed8180eb0b210f731de03ff5961874ca4e4b5952226b0392f13000a
@@ -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
  ]
@@ -8,19 +8,10 @@ module Decidim
8
8
  include TranslatableAttributes
9
9
 
10
10
  translatable_attribute :title, String
11
- translatable_attribute :description, String
12
- translatable_attribute :tos, String
13
-
14
- attribute :published_at, Decidim::Attributes::TimeWithZone
15
- attribute :questions, Array[QuestionForm]
11
+ translatable_attribute :description, Decidim::Attributes::RichText
12
+ translatable_attribute :tos, Decidim::Attributes::RichText
16
13
 
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
@@ -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
+ });