decidim-forms 0.29.2 → 0.30.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/forms/step_navigation_cell.rb +18 -5
- data/app/commands/decidim/forms/admin/update_questionnaire.rb +1 -82
- data/app/commands/decidim/forms/admin/update_questions.rb +109 -0
- data/app/commands/decidim/forms/answer_questionnaire.rb +10 -3
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +39 -3
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire_answers.rb +2 -2
- data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +12 -4
- data/app/forms/decidim/forms/admin/display_condition_form.rb +1 -1
- data/app/forms/decidim/forms/admin/questionnaire_form.rb +0 -9
- data/app/forms/decidim/forms/admin/questions_form.rb +18 -0
- data/app/forms/decidim/forms/answer_choice_form.rb +5 -0
- data/app/forms/decidim/forms/answer_form.rb +1 -0
- data/app/forms/decidim/forms/questionnaire_form.rb +7 -0
- data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_pagination_helper.rb +1 -1
- data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_url_helper.rb +5 -5
- data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +5 -1
- data/app/models/decidim/forms/answer_choice.rb +0 -2
- data/app/models/decidim/forms/answer_option.rb +1 -1
- data/app/models/decidim/forms/question.rb +10 -0
- data/app/packs/entrypoints/decidim_forms.js +0 -1
- data/app/packs/entrypoints/decidim_forms_admin.js +6 -0
- data/app/packs/src/decidim/forms/admin/publish_answers_buttons.js +72 -0
- data/app/packs/src/decidim/forms/forms.js +22 -18
- data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +1 -1
- data/app/presenters/decidim/forms/admin_log/question_presenter.rb +31 -0
- data/app/queries/decidim/forms/questionnaire_user_answers.rb +1 -1
- data/app/views/decidim/forms/admin/questionnaires/_answer_option_template.html.erb +1 -1
- data/app/views/decidim/forms/admin/questionnaires/_display_condition_template.html.erb +1 -1
- data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +0 -89
- data/app/views/decidim/forms/admin/questionnaires/_matrix_row_template.html.erb +1 -1
- data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +3 -3
- data/app/views/decidim/forms/admin/questionnaires/_questions_form.html.erb +80 -0
- data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +0 -20
- data/app/views/decidim/forms/admin/questionnaires/edit_questions.html.erb +47 -0
- data/app/views/decidim/forms/questionnaires/_questionnaire.html.erb +8 -1
- data/app/views/decidim/forms/questionnaires/answers/_files.html.erb +1 -1
- data/app/views/decidim/forms/questionnaires/answers/_sorting.html.erb +12 -6
- data/app/views/decidim/forms/questionnaires/edit.html.erb +47 -0
- data/app/views/decidim/forms/questionnaires/show.html.erb +13 -2
- data/config/assets.rb +1 -2
- data/config/locales/bg.yml +0 -2
- data/config/locales/ca.yml +46 -6
- data/config/locales/cs.yml +45 -5
- data/config/locales/de.yml +45 -5
- data/config/locales/el.yml +0 -2
- data/config/locales/en.yml +45 -5
- data/config/locales/es-MX.yml +45 -5
- data/config/locales/es-PY.yml +45 -5
- data/config/locales/es.yml +45 -5
- data/config/locales/eu.yml +45 -5
- data/config/locales/fi-plain.yml +45 -5
- data/config/locales/fi.yml +45 -5
- data/config/locales/fr-CA.yml +37 -5
- data/config/locales/fr.yml +37 -5
- data/config/locales/ja.yml +1 -1
- data/config/locales/lt.yml +0 -2
- data/config/locales/pl.yml +0 -2
- data/config/locales/ro-RO.yml +8 -3
- data/config/locales/zh-TW.yml +0 -2
- data/db/migrate/20190315203056_add_session_token_to_decidim_forms_answers.rb +1 -1
- data/db/migrate/20241122142230_add_survey_answers_published_at_to_questions.rb +7 -0
- data/decidim-forms.gemspec +1 -2
- data/lib/decidim/api/answer_option_type.rb +1 -1
- data/lib/decidim/api/question_type.rb +4 -4
- data/lib/decidim/api/questionnaire_type.rb +4 -4
- data/lib/decidim/exporters/form_pdf.rb +114 -11
- data/lib/decidim/forms/download_your_data_user_answers_serializer.rb +0 -4
- data/lib/decidim/forms/test/factories.rb +2 -2
- data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +44 -4
- data/lib/decidim/forms/test/shared_examples/manage_questionnaire_answers.rb +17 -17
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +19 -21
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +70 -94
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_display_conditions.rb +15 -18
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +90 -125
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +4 -25
- data/lib/decidim/forms/version.rb +1 -1
- data/lib/decidim/forms.rb +0 -1
- metadata +18 -32
- data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.js +0 -1
- data/app/packs/entrypoints/decidim_questionnaire_answers_pdf.scss +0 -1
- data/app/packs/stylesheets/decidim/forms/questionnaire-answers-pdf.scss +0 -69
- data/app/views/decidim/forms/admin/questionnaires/answers/export/_answer.html.erb +0 -31
- data/app/views/decidim/forms/admin/questionnaires/answers/export/pdf.html.erb +0 -13
- data/app/views/layouts/decidim/forms/admin/questionnaires/questionnaire_answers.html.erb +0 -12
- data/config/initializers/wicked_pdf.rb +0 -26
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88f55a44bfdc1edbc0cddbc6be9c92218449a7f0cfc0b846815c6be47fa1fe54
|
4
|
+
data.tar.gz: c743a5ff7aeca3316201d4cc29bdec1d2f04761c138fcddf2d4885972a5b60a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
{
|
45
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
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
|
-
|
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:
|
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:
|
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[:
|
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[:
|
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" =>
|
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
|
@@ -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]
|
@@ -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([
|
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(
|
30
|
-
url_for([
|
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(
|
34
|
-
url_for([
|
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
|
-
|
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:
|
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
|
@@ -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
|
+
});
|