decidim-forms 0.23.5 → 0.24.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/decidim/forms/forms.js.es6 +4 -4
- data/app/commands/decidim/forms/admin/update_questionnaire.rb +2 -1
- data/app/commands/decidim/forms/answer_questionnaire.rb +43 -1
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +10 -2
- data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +10 -4
- data/app/forms/decidim/forms/admin/question_form.rb +2 -0
- data/app/forms/decidim/forms/answer_form.rb +27 -0
- data/app/helpers/decidim/forms/admin/application_helper.rb +1 -6
- data/app/helpers/decidim/forms/admin/concerns/has_questionnaire_answers_url_helper.rb +3 -3
- data/app/jobs/decidim/forms/export_questionnaire_answers_job.rb +1 -1
- data/app/models/decidim/forms/answer.rb +8 -0
- data/app/models/decidim/forms/question.rb +9 -3
- data/app/presenters/decidim/forms/admin/questionnaire_answer_presenter.rb +20 -0
- data/app/presenters/decidim/forms/admin/questionnaire_participant_presenter.rb +4 -4
- data/app/queries/decidim/forms/questionnaire_user_answers.rb +2 -1
- data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +3 -3
- data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +11 -0
- data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +1 -1
- data/app/views/decidim/forms/questionnaires/_answer.html.erb +1 -1
- data/app/views/decidim/forms/questionnaires/answers/_files.html.erb +1 -0
- data/app/views/decidim/forms/questionnaires/answers/_long_answer.html.erb +1 -1
- data/app/views/decidim/forms/questionnaires/answers/_matrix_multiple.html.erb +2 -1
- data/app/views/decidim/forms/questionnaires/answers/_matrix_single.html.erb +2 -1
- data/app/views/decidim/forms/questionnaires/answers/_multiple_option.html.erb +2 -1
- data/app/views/decidim/forms/questionnaires/answers/_short_answer.html.erb +1 -1
- data/app/views/decidim/forms/questionnaires/answers/_single_option.html.erb +2 -1
- data/app/views/decidim/forms/questionnaires/show.html.erb +1 -1
- data/config/initializers/wicked_pdf.rb +2 -0
- data/config/locales/ca.yml +8 -2
- data/config/locales/cs.yml +8 -2
- data/config/locales/de.yml +8 -2
- data/config/locales/el.yml +1 -1
- data/config/locales/en.yml +8 -2
- data/config/locales/es-MX.yml +8 -2
- data/config/locales/es-PY.yml +8 -2
- data/config/locales/es.yml +8 -2
- data/config/locales/fi-plain.yml +8 -2
- data/config/locales/fi.yml +8 -2
- data/config/locales/fr-CA.yml +8 -2
- data/config/locales/fr.yml +8 -2
- data/config/locales/gl.yml +1 -2
- data/config/locales/it.yml +1 -2
- data/config/locales/ja.yml +2 -2
- data/config/locales/lv.yml +1 -1
- data/config/locales/nl.yml +4 -5
- data/config/locales/no.yml +1 -2
- data/config/locales/pl.yml +8 -2
- data/config/locales/pt.yml +1 -2
- data/config/locales/ro-RO.yml +8 -2
- data/config/locales/sv.yml +9 -2
- data/config/locales/tr-TR.yml +2 -2
- data/config/locales/zh-CN.yml +1 -2
- data/db/migrate/20210208094442_add_max_characters_to_decidim_forms_questions.rb +7 -0
- data/lib/decidim/api/answer_option_type.rb +13 -0
- data/lib/decidim/api/question_type.rb +21 -0
- data/lib/decidim/api/questionnaire_entity_interface.rb +5 -5
- data/lib/decidim/api/questionnaire_type.rb +19 -0
- data/lib/decidim/exporters/form_pdf_controller_helper.rb +2 -0
- data/lib/decidim/forms.rb +1 -1
- data/lib/decidim/forms/api.rb +3 -0
- data/lib/decidim/forms/data_portability_user_answers_serializer.rb +7 -1
- data/lib/decidim/forms/test/factories.rb +12 -2
- data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +38 -5
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +5 -4
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_display_conditions.rb +7 -3
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/add_questions.rb +1 -1
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires/update_questions.rb +5 -0
- data/lib/decidim/forms/user_answers_serializer.rb +9 -1
- data/lib/decidim/forms/version.rb +1 -1
- metadata +15 -13
- data/app/types/decidim/forms/answer_option_type.rb +0 -14
- data/app/types/decidim/forms/question_type.rb +0 -23
- data/app/types/decidim/forms/questionnaire_type.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0effe89fd4c07703215ade4f4d6f78ad018e8b68594a429d4a000e2b9863dbca
|
4
|
+
data.tar.gz: 42efeed3f98ad01bd7ef4782429e9e0d21f84020683ccf3e78b9e254c2b52182
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fccbf41401a77c3b5acf8db916ff00b66c7f83a75cf136e81313db6ac6c8dd319e7690cd3b0aef19e82ae55da10e6853cddc0a2aea899a402e82150911b66ed0
|
7
|
+
data.tar.gz: fd0bd1608ae6b8067712c6cee7e9206c46c84013e3cd128b13682d6cf31d51b8c27ea9aca8273c099aedb445b69af8e8a04acc3e714dd5ecc83ab6c14436eb27
|
@@ -53,16 +53,16 @@
|
|
53
53
|
window.exitUrl = event.currentTarget.action;
|
54
54
|
});
|
55
55
|
|
56
|
-
window.
|
56
|
+
window.addEventListener("beforeunload", (event) => {
|
57
57
|
const exitUrl = window.exitUrl;
|
58
58
|
const hasChanged = $form.data("changed");
|
59
59
|
window.exitUrl = null;
|
60
60
|
|
61
61
|
if (!hasChanged || (exitUrl && exitUrl.includes(safePath))) {
|
62
|
-
return
|
62
|
+
return;
|
63
63
|
}
|
64
64
|
|
65
|
-
|
66
|
-
}
|
65
|
+
event.returnValue = true;
|
66
|
+
});
|
67
67
|
}
|
68
68
|
})(window);
|
@@ -48,7 +48,8 @@ module Decidim
|
|
48
48
|
position: form_question.position,
|
49
49
|
mandatory: form_question.mandatory,
|
50
50
|
question_type: form_question.question_type,
|
51
|
-
max_choices: form_question.max_choices
|
51
|
+
max_choices: form_question.max_choices,
|
52
|
+
max_characters: form_question.max_characters
|
52
53
|
}
|
53
54
|
|
54
55
|
update_nested_model(form_question, question_attributes, @questionnaire.questions) do |question|
|
@@ -4,6 +4,8 @@ module Decidim
|
|
4
4
|
module Forms
|
5
5
|
# This command is executed when the user answers a Questionnaire.
|
6
6
|
class AnswerQuestionnaire < Rectify::Command
|
7
|
+
include ::Decidim::MultipleAttachmentsMethods
|
8
|
+
|
7
9
|
# Initializes a AnswerQuestionnaire Command.
|
8
10
|
#
|
9
11
|
# form - The form from which to get the data.
|
@@ -21,14 +23,34 @@ module Decidim
|
|
21
23
|
return broadcast(:invalid) if @form.invalid?
|
22
24
|
|
23
25
|
answer_questionnaire
|
24
|
-
|
26
|
+
|
27
|
+
if @errors
|
28
|
+
reset_form_attachments
|
29
|
+
broadcast(:invalid)
|
30
|
+
else
|
31
|
+
broadcast(:ok)
|
32
|
+
end
|
25
33
|
end
|
26
34
|
|
27
35
|
attr_reader :form
|
28
36
|
|
29
37
|
private
|
30
38
|
|
39
|
+
# This method will add an error to the `add_documents` field only if there's
|
40
|
+
# any error in any other field or an error in another answer in the
|
41
|
+
# questionnaire. This is needed because when the form has
|
42
|
+
# an error, the attachments are lost, so we need a way to inform the user
|
43
|
+
# of this problem.
|
44
|
+
def reset_form_attachments
|
45
|
+
@form.responses.each do |answer|
|
46
|
+
answer.errors.add(:add_documents, :needs_to_be_reattached) if answer.has_attachments?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
31
50
|
def answer_questionnaire
|
51
|
+
@main_form = @form
|
52
|
+
@errors = nil
|
53
|
+
|
32
54
|
Answer.transaction do
|
33
55
|
form.responses_by_step.flatten.select(&:display_conditions_fulfilled?).each do |form_answer|
|
34
56
|
answer = Answer.new(
|
@@ -51,7 +73,27 @@ module Decidim
|
|
51
73
|
end
|
52
74
|
|
53
75
|
answer.save!
|
76
|
+
|
77
|
+
next unless form_answer.question.has_attachments?
|
78
|
+
|
79
|
+
# The attachments module expects `@form` to be the form with the
|
80
|
+
# attachments
|
81
|
+
@form = form_answer
|
82
|
+
@attached_to = answer
|
83
|
+
|
84
|
+
build_attachments
|
85
|
+
|
86
|
+
if attachments_invalid?
|
87
|
+
@errors = true
|
88
|
+
next
|
89
|
+
end
|
90
|
+
|
91
|
+
create_attachments if process_attachments?
|
92
|
+
document_cleanup!
|
54
93
|
end
|
94
|
+
|
95
|
+
@form = @main_form
|
96
|
+
raise ActiveRecord::Rollback if @errors
|
55
97
|
end
|
56
98
|
end
|
57
99
|
end
|
@@ -15,8 +15,10 @@ module Decidim
|
|
15
15
|
|
16
16
|
included do
|
17
17
|
helper Decidim::Forms::Admin::ApplicationHelper
|
18
|
+
include Decidim::TranslatableAttributes
|
19
|
+
|
18
20
|
helper_method :questionnaire_for, :questionnaire, :blank_question, :blank_answer_option, :blank_matrix_row,
|
19
|
-
:blank_display_condition, :question_types, :display_condition_types, :update_url, :public_url, :answer_options_url
|
21
|
+
:blank_display_condition, :question_types, :display_condition_types, :update_url, :public_url, :answer_options_url, :edit_questionnaire_title
|
20
22
|
|
21
23
|
if defined? Decidim::Templates::Admin
|
22
24
|
include Decidim::Templates::Admin::Concerns::Templatable
|
@@ -97,7 +99,13 @@ module Decidim
|
|
97
99
|
# Returns the url to get the answer options json (for the display conditions form)
|
98
100
|
# for the question with id = params[:id]
|
99
101
|
def answer_options_url(params)
|
100
|
-
url_for([questionnaire.questionnaire_for, action: :answer_options, format: :json, **params])
|
102
|
+
url_for([questionnaire.questionnaire_for, { action: :answer_options, format: :json, **params }])
|
103
|
+
end
|
104
|
+
|
105
|
+
# Implement this method in your controller to set the title
|
106
|
+
# of the edit form.
|
107
|
+
def edit_questionnaire_title
|
108
|
+
t(:title, scope: "decidim.forms.admin.questionnaires.form", questionnaire_for: translated_attribute(questionnaire_for.try(:title)))
|
101
109
|
end
|
102
110
|
|
103
111
|
private
|
@@ -26,7 +26,7 @@ module Decidim
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def answer
|
29
|
-
|
29
|
+
enforce_permission_to_answer_questionnaire
|
30
30
|
|
31
31
|
@form = form(Decidim::Forms::QuestionnaireForm).from_params(params, session_token: session_token, ip_hash: ip_hash)
|
32
32
|
|
@@ -78,7 +78,7 @@ module Decidim
|
|
78
78
|
# You can implement this method in your controller to change the URL
|
79
79
|
# where the questionnaire will be submitted.
|
80
80
|
def update_url
|
81
|
-
url_for([questionnaire_for, action: :answer])
|
81
|
+
url_for([questionnaire_for, { action: :answer }])
|
82
82
|
end
|
83
83
|
|
84
84
|
# Points to the shortest path accessing the current form. This will be
|
@@ -87,7 +87,7 @@ module Decidim
|
|
87
87
|
#
|
88
88
|
# Overwrite this method at the controller.
|
89
89
|
def form_path
|
90
|
-
url_for([questionnaire_for, only_path: true])
|
90
|
+
url_for([questionnaire_for, { only_path: true }])
|
91
91
|
end
|
92
92
|
|
93
93
|
# Public: Method to be implemented at the controller. You need to
|
@@ -107,7 +107,7 @@ module Decidim
|
|
107
107
|
end
|
108
108
|
|
109
109
|
def spam_detected
|
110
|
-
|
110
|
+
enforce_permission_to_answer_questionnaire
|
111
111
|
|
112
112
|
@form = form(Decidim::Forms::QuestionnaireForm).from_params(params)
|
113
113
|
|
@@ -115,6 +115,12 @@ module Decidim
|
|
115
115
|
render template: "decidim/forms/questionnaires/show"
|
116
116
|
end
|
117
117
|
|
118
|
+
# You can implement this method in your controller to change the
|
119
|
+
# enforce_permission_to arguments.
|
120
|
+
def enforce_permission_to_answer_questionnaire
|
121
|
+
enforce_permission_to :answer, :questionnaire
|
122
|
+
end
|
123
|
+
|
118
124
|
def ip_hash
|
119
125
|
return nil unless request&.remote_ip
|
120
126
|
|
@@ -14,6 +14,7 @@ module Decidim
|
|
14
14
|
attribute :display_conditions, Array[DisplayConditionForm]
|
15
15
|
attribute :matrix_rows, Array[QuestionMatrixRowForm]
|
16
16
|
attribute :max_choices, Integer
|
17
|
+
attribute :max_characters, Integer, default: 0
|
17
18
|
attribute :deleted, Boolean, default: false
|
18
19
|
|
19
20
|
translatable_attribute :body, String
|
@@ -22,6 +23,7 @@ module Decidim
|
|
22
23
|
validates :position, numericality: { greater_than_or_equal_to: 0 }
|
23
24
|
validates :question_type, inclusion: { in: Decidim::Forms::Question::TYPES }
|
24
25
|
validates :max_choices, numericality: { only_integer: true, greater_than: 1, less_than_or_equal_to: ->(form) { form.number_of_options } }, allow_blank: true
|
26
|
+
validates :max_characters, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
25
27
|
validates :body, translatable_presence: true, if: :requires_body?
|
26
28
|
validates :matrix_rows, presence: true, if: :matrix?
|
27
29
|
validates :answer_options, presence: true, if: :matrix?
|
@@ -5,18 +5,23 @@ module Decidim
|
|
5
5
|
# This class holds a Form to save the questionnaire answers from Decidim's public page
|
6
6
|
class AnswerForm < Decidim::Form
|
7
7
|
include Decidim::TranslationsHelper
|
8
|
+
include Decidim::AttachmentAttributes
|
8
9
|
|
9
10
|
attribute :question_id, String
|
10
11
|
attribute :body, String
|
11
12
|
attribute :choices, Array[AnswerChoiceForm]
|
12
13
|
attribute :matrix_choices, Array[AnswerChoiceForm]
|
13
14
|
|
15
|
+
attachments_attribute :documents
|
16
|
+
|
14
17
|
validates :body, presence: true, if: :mandatory_body?
|
15
18
|
validates :selected_choices, presence: true, if: :mandatory_choices?
|
16
19
|
|
17
20
|
validate :max_choices, if: -> { question.max_choices }
|
18
21
|
validate :all_choices, if: -> { question.question_type == "sorting" }
|
19
22
|
validate :min_choices, if: -> { question.matrix? && question.mandatory? }
|
23
|
+
validate :documents_present, if: -> { question.question_type == "files" && question.mandatory? }
|
24
|
+
validate :max_characters, if: -> { question.max_characters.positive? }
|
20
25
|
|
21
26
|
delegate :mandatory_body?, :mandatory_choices?, :matrix?, to: :question
|
22
27
|
|
@@ -49,6 +54,10 @@ module Decidim
|
|
49
54
|
choices.select(&:body)
|
50
55
|
end
|
51
56
|
|
57
|
+
def custom_choices
|
58
|
+
choices.select(&:custom_body)
|
59
|
+
end
|
60
|
+
|
52
61
|
def display_conditions_fulfilled?
|
53
62
|
question.display_conditions.all? do |condition|
|
54
63
|
answer = context.responses&.find { |r| r.question_id&.to_i == condition.condition_question.id }
|
@@ -56,6 +65,10 @@ module Decidim
|
|
56
65
|
end
|
57
66
|
end
|
58
67
|
|
68
|
+
def has_attachments?
|
69
|
+
question.has_attachments? && errors[:add_documents].empty? && add_documents.present?
|
70
|
+
end
|
71
|
+
|
59
72
|
private
|
60
73
|
|
61
74
|
def mandatory_body?
|
@@ -78,6 +91,16 @@ module Decidim
|
|
78
91
|
end
|
79
92
|
end
|
80
93
|
|
94
|
+
def max_characters
|
95
|
+
if body.present?
|
96
|
+
errors.add(:body, :too_long) if body.size > question.max_characters
|
97
|
+
elsif custom_choices.any?
|
98
|
+
custom_choices.each do |choice|
|
99
|
+
errors.add(:body, :too_long) if choice.custom_body.size > question.max_characters
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
81
104
|
def min_choices
|
82
105
|
errors.add(:choices, :missing) if grouped_choices.count != question.matrix_rows.count
|
83
106
|
end
|
@@ -93,6 +116,10 @@ module Decidim
|
|
93
116
|
def max_choices_label
|
94
117
|
I18n.t("questionnaires.question.max_choices", scope: "decidim.forms", n: question.max_choices)
|
95
118
|
end
|
119
|
+
|
120
|
+
def documents_present
|
121
|
+
errors.add(:add_documents, :blank) if add_documents.empty? && errors[:add_documents].empty?
|
122
|
+
end
|
96
123
|
end
|
97
124
|
end
|
98
125
|
end
|
@@ -31,7 +31,7 @@ module Decidim
|
|
31
31
|
"placeholder" => options[:placeholder],
|
32
32
|
"locale" => I18n.locale
|
33
33
|
}
|
34
|
-
|
34
|
+
tag.span(class: options[:class], data: data) do
|
35
35
|
truncate translated_attribute(title), length: options[:max_length], omission: options[:omission]
|
36
36
|
end
|
37
37
|
end
|
@@ -45,11 +45,6 @@ module Decidim
|
|
45
45
|
def templates_defined?
|
46
46
|
defined? Decidim::Templates::Admin::Concerns::Templatable
|
47
47
|
end
|
48
|
-
|
49
|
-
def title_for_questionnaire
|
50
|
-
scope = templates_defined? ? "decidim.templates.admin.questionnaire_templates" : "decidim.forms.admin.questionnaires"
|
51
|
-
t("form.title", scope: scope)
|
52
|
-
end
|
53
48
|
end
|
54
49
|
end
|
55
50
|
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([:index, 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
29
|
def questionnaire_participant_answers_url(session_token)
|
30
|
-
url_for([:show, questionnaire.questionnaire_for, session_token: session_token])
|
30
|
+
url_for([:show, questionnaire.questionnaire_for, { session_token: session_token }])
|
31
31
|
end
|
32
32
|
|
33
33
|
def questionnaire_export_response_url(session_token)
|
34
|
-
url_for([:export_response, questionnaire.questionnaire_for, session_token: session_token, format: "pdf"])
|
34
|
+
url_for([:export_response, questionnaire.questionnaire_for, { session_token: session_token, format: "pdf" }])
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -7,7 +7,7 @@ module Decidim
|
|
7
7
|
|
8
8
|
def perform(user, title, answers)
|
9
9
|
return if user&.email.blank?
|
10
|
-
return if answers
|
10
|
+
return if answers.blank?
|
11
11
|
|
12
12
|
serializer = Decidim::Forms::UserAnswersSerializer
|
13
13
|
export_data = Decidim::Exporters::FormPDF.new(answers, serializer).export
|
@@ -6,6 +6,7 @@ module Decidim
|
|
6
6
|
class Answer < Forms::ApplicationRecord
|
7
7
|
include Decidim::DataPortability
|
8
8
|
include Decidim::NewsletterParticipant
|
9
|
+
include Decidim::HasAttachments
|
9
10
|
|
10
11
|
belongs_to :user, class_name: "Decidim::User", foreign_key: "decidim_user_id", optional: true
|
11
12
|
belongs_to :questionnaire, class_name: "Questionnaire", foreign_key: "decidim_questionnaire_id"
|
@@ -20,6 +21,8 @@ module Decidim
|
|
20
21
|
validate :user_questionnaire_same_organization
|
21
22
|
validate :question_belongs_to_questionnaire
|
22
23
|
|
24
|
+
scope :not_separator, -> { joins(:question).where.not(decidim_forms_questions: { question_type: Decidim::Forms::Question::SEPARATOR_TYPE }) }
|
25
|
+
|
23
26
|
def self.user_collection(user)
|
24
27
|
where(decidim_user_id: user.id)
|
25
28
|
end
|
@@ -39,6 +42,11 @@ module Decidim
|
|
39
42
|
answers.pluck(:decidim_user_id).flatten.compact.uniq
|
40
43
|
end
|
41
44
|
|
45
|
+
def organization
|
46
|
+
user.organization if user.present?
|
47
|
+
questionnaire&.questionnaire_for.try(:organization)
|
48
|
+
end
|
49
|
+
|
42
50
|
private
|
43
51
|
|
44
52
|
def user_questionnaire_same_organization
|
@@ -6,7 +6,7 @@ module Decidim
|
|
6
6
|
class Question < Forms::ApplicationRecord
|
7
7
|
include Decidim::TranslatableResource
|
8
8
|
|
9
|
-
QUESTION_TYPES = %w(short_answer long_answer single_option multiple_option sorting matrix_single matrix_multiple).freeze
|
9
|
+
QUESTION_TYPES = %w(short_answer long_answer single_option multiple_option sorting files matrix_single matrix_multiple).freeze
|
10
10
|
SEPARATOR_TYPE = "separator"
|
11
11
|
TYPES = (QUESTION_TYPES + [SEPARATOR_TYPE]).freeze
|
12
12
|
|
@@ -48,6 +48,8 @@ module Decidim
|
|
48
48
|
|
49
49
|
validates :question_type, inclusion: { in: TYPES }
|
50
50
|
|
51
|
+
scope :not_separator, -> { where.not(question_type: SEPARATOR_TYPE) }
|
52
|
+
|
51
53
|
scope :with_body, -> { where(question_type: %w(short_answer long_answer)) }
|
52
54
|
scope :with_choices, -> { where.not(question_type: %w(short_answer long_answer)) }
|
53
55
|
|
@@ -63,11 +65,11 @@ module Decidim
|
|
63
65
|
end
|
64
66
|
|
65
67
|
def mandatory_body?
|
66
|
-
mandatory? && !multiple_choice?
|
68
|
+
mandatory? && !multiple_choice? && !has_attachments?
|
67
69
|
end
|
68
70
|
|
69
71
|
def mandatory_choices?
|
70
|
-
mandatory? && multiple_choice?
|
72
|
+
mandatory? && multiple_choice? && !has_attachments?
|
71
73
|
end
|
72
74
|
|
73
75
|
def number_of_options
|
@@ -81,6 +83,10 @@ module Decidim
|
|
81
83
|
def separator?
|
82
84
|
question_type.to_s == SEPARATOR_TYPE
|
83
85
|
end
|
86
|
+
|
87
|
+
def has_attachments?
|
88
|
+
question_type.to_s == "files"
|
89
|
+
end
|
84
90
|
end
|
85
91
|
end
|
86
92
|
end
|
@@ -17,6 +17,7 @@ module Decidim
|
|
17
17
|
|
18
18
|
def body
|
19
19
|
return answer.body if answer.body.present?
|
20
|
+
return attachments if answer.attachments.any?
|
20
21
|
return "-" if answer.choices.empty?
|
21
22
|
|
22
23
|
choices = answer.choices.map do |choice|
|
@@ -30,8 +31,27 @@ module Decidim
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
34
|
+
def attachments
|
35
|
+
content_tag(:ul) do
|
36
|
+
safe_join(answer.attachments.map { |a| pretty_attachment(a) })
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
33
40
|
private
|
34
41
|
|
42
|
+
def pretty_attachment(attachment)
|
43
|
+
# rubocop:disable Style/StringConcatenation
|
44
|
+
# Interpolating strings that are `html_safe` is problematic with Rails.
|
45
|
+
content_tag :li do
|
46
|
+
link_to(translated_attribute(attachment.title), attachment.url) +
|
47
|
+
" " +
|
48
|
+
content_tag(:small) do
|
49
|
+
"#{attachment.file_type} #{number_to_human_size(attachment.file_size)}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
# rubocop:enable Style/StringConcatenation
|
53
|
+
end
|
54
|
+
|
35
55
|
def choice(choice_body)
|
36
56
|
content_tag :li do
|
37
57
|
choice_body
|
@@ -36,23 +36,23 @@ module Decidim
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def first_short_answer
|
39
|
-
short = sibilings.where(
|
39
|
+
short = sibilings.where(decidim_forms_questions: { question_type: %w(short_answer) })
|
40
40
|
short.first
|
41
41
|
end
|
42
42
|
|
43
43
|
def completion
|
44
|
-
with_body = sibilings.where(
|
44
|
+
with_body = sibilings.where(decidim_forms_questions: { question_type: %w(short_answer long_answer) })
|
45
45
|
.where.not(body: "").count
|
46
46
|
with_choices = sibilings.where.not("decidim_forms_questions.question_type in (?)", %w(short_answer long_answer))
|
47
47
|
.where("decidim_forms_answers.id IN (SELECT decidim_answer_id FROM decidim_forms_answer_choices)").count
|
48
48
|
|
49
|
-
(with_body + with_choices).to_f / questionnaire.questions.count * 100
|
49
|
+
(with_body + with_choices).to_f / questionnaire.questions.not_separator.count * 100
|
50
50
|
end
|
51
51
|
|
52
52
|
private
|
53
53
|
|
54
54
|
def sibilings
|
55
|
-
Answer.where(questionnaire: questionnaire, session_token: participant.session_token).joins(:question).order("decidim_forms_questions.position ASC")
|
55
|
+
Answer.not_separator.where(questionnaire: questionnaire, session_token: participant.session_token).joins(:question).order("decidim_forms_questions.position ASC")
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|