decidim-forms 0.23.6 → 0.24.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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 +4 -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 +2 -2
- data/config/locales/es-PY.yml +2 -2
- data/config/locales/es.yml +2 -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 +0 -3
- 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 +1 -7
- data/config/locales/sv.yml +1 -4
- 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/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/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/test/shared_examples/manage_questionnaires.rb +5 -4
- data/lib/decidim/forms/user_answers_serializer.rb +9 -1
- data/lib/decidim/forms/version.rb +1 -1
- data/lib/decidim/forms.rb +1 -1
- metadata +17 -15
- 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: 1f06c183113352ec8c74d0d958b1f1936a71f81ddd55c890e7254e1480b044f2
|
4
|
+
data.tar.gz: aafe2af6840afd6e2c757916bd44e185bbb2b4474380860e6c0d08641d246cb0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ed91cbe536d809e93dd5a7b4f8723b04d982f25cc98aca21eca9b4a7c4a31d4c7f9c78f9aca9c7eeed8c139bdcc33dee163f0838d84c009f6d8d081585bdaa0
|
7
|
+
data.tar.gz: c0eadff0a39fcd19d392dbc4b49db1c7f0715f378a9e4287e4af562e8a008fcac3dc70c281376c00fb83f02d177cb5f1e5b89376af2cc5921288a56bf202330f
|
@@ -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
|