decidim-surveys 0.10.1 → 0.11.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/app/assets/config/decidim_surveys_manifest.js +1 -0
- data/app/assets/javascripts/decidim/surveys/admin/auto_buttons_by_min_items.component.js.es6 +25 -0
- data/app/assets/javascripts/decidim/surveys/admin/auto_select_options_by_total_items.component.js.es6 +23 -0
- data/app/assets/javascripts/decidim/surveys/admin/surveys.js.es6 +146 -43
- data/app/assets/javascripts/decidim/surveys/autosortable_checkboxes.component.js.es6 +65 -0
- data/app/assets/javascripts/decidim/surveys/option_attached_inputs.component.js.es6 +32 -0
- data/app/assets/javascripts/decidim/surveys/surveys.js.es6 +20 -0
- data/app/assets/stylesheets/decidim/surveys/surveys.scss +20 -3
- data/app/commands/decidim/surveys/admin/update_survey.rb +36 -15
- data/app/commands/decidim/surveys/answer_survey.rb +12 -1
- data/app/commands/decidim/surveys/create_survey.rb +5 -5
- data/app/controllers/decidim/surveys/admin/application_controller.rb +2 -2
- data/app/controllers/decidim/surveys/admin/surveys_controller.rb +3 -3
- data/app/controllers/decidim/surveys/application_controller.rb +2 -2
- data/app/controllers/decidim/surveys/surveys_controller.rb +1 -1
- data/app/forms/decidim/surveys/admin/survey_answer_option_form.rb +23 -0
- data/app/forms/decidim/surveys/admin/survey_form.rb +7 -1
- data/app/forms/decidim/surveys/admin/survey_question_form.rb +12 -2
- data/app/forms/decidim/surveys/survey_answer_choice_form.rb +15 -0
- data/app/forms/decidim/surveys/survey_answer_form.rb +40 -6
- data/app/forms/decidim/surveys/survey_form.rb +1 -1
- data/app/helpers/decidim/surveys/admin/application_helper.rb +3 -19
- data/app/jobs/decidim/surveys/settings_change_job.rb +4 -4
- data/app/models/decidim/surveys/abilities/current_user_ability.rb +8 -8
- data/app/models/decidim/surveys/abilities/participatory_process_admin_ability.rb +1 -1
- data/app/models/decidim/surveys/survey.rb +2 -2
- data/app/models/decidim/surveys/survey_answer.rb +9 -1
- data/app/models/decidim/surveys/survey_answer_choice.rb +15 -0
- data/app/models/decidim/surveys/survey_answer_option.rb +9 -0
- data/app/models/decidim/surveys/survey_question.rb +21 -5
- data/app/views/decidim/surveys/admin/surveys/_answer_option.html.erb +28 -11
- data/app/views/decidim/surveys/admin/surveys/_form.html.erb +18 -14
- data/app/views/decidim/surveys/admin/surveys/_question.html.erb +74 -31
- data/app/views/decidim/surveys/admin/surveys/edit.html.erb +1 -1
- data/app/views/decidim/surveys/surveys/_answer.html.erb +94 -0
- data/app/views/decidim/surveys/surveys/show.html.erb +15 -42
- data/config/locales/ca.yml +33 -13
- data/config/locales/en.yml +33 -13
- data/config/locales/es.yml +33 -13
- data/config/locales/eu.yml +33 -13
- data/config/locales/fi.yml +33 -13
- data/config/locales/fr.yml +33 -13
- data/config/locales/gl.yml +33 -13
- data/config/locales/it.yml +33 -13
- data/config/locales/nl.yml +36 -16
- data/config/locales/pl.yml +33 -13
- data/config/locales/pt-BR.yml +33 -13
- data/config/locales/pt.yml +33 -13
- data/config/locales/ru.yml +0 -6
- data/config/locales/sv.yml +33 -13
- data/config/locales/uk.yml +0 -6
- data/db/migrate/20180305133837_rename_features_to_components_at_surveys.rb +11 -0
- data/db/migrate/20180314225829_add_max_choices_to_survey_questions.rb +7 -0
- data/db/migrate/20180321141024_add_description_to_decidim_survey_questions.rb +7 -0
- data/db/migrate/20180405014929_add_choices_to_decidim_survey_answers.rb +48 -0
- data/db/migrate/20180405015012_create_decidim_survey_answer_options.rb +43 -0
- data/db/migrate/20180405015147_create_decidim_survey_answer_choices.rb +61 -0
- data/db/migrate/20180405015258_add_free_text_to_survey_answer_options.rb +7 -0
- data/db/migrate/20180405015314_add_custom_body_to_survey_answer_choices.rb +7 -0
- data/db/migrate/20180406201818_add_position_to_decidim_survey_answer_choices.rb +7 -0
- data/lib/decidim/surveys.rb +1 -1
- data/lib/decidim/surveys/admin_engine.rb +0 -2
- data/lib/decidim/surveys/{feature.rb → component.rb} +38 -26
- data/lib/decidim/surveys/engine.rb +5 -1
- data/lib/decidim/surveys/test/factories.rb +22 -6
- data/lib/decidim/surveys/version.rb +1 -1
- metadata +33 -30
- data/app/assets/javascripts/decidim/surveys/admin/auto_label_by_position.component.js.es6 +0 -33
- data/app/assets/javascripts/decidim/surveys/admin/dynamic_fields.component.js.es6 +0 -95
- data/app/forms/decidim/surveys/admin/survey_question_answer_option_form.rb +0 -15
@@ -33,24 +33,45 @@ module Decidim
|
|
33
33
|
|
34
34
|
def update_survey_questions
|
35
35
|
@form.questions.each do |form_question|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
36
|
+
update_survey_question(form_question)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def update_survey_question(form_question)
|
41
|
+
question_attributes = {
|
42
|
+
body: form_question.body,
|
43
|
+
description: form_question.description,
|
44
|
+
position: form_question.position,
|
45
|
+
mandatory: form_question.mandatory,
|
46
|
+
question_type: form_question.question_type,
|
47
|
+
max_choices: form_question.max_choices
|
48
|
+
}
|
49
|
+
|
50
|
+
update_nested_model(form_question, question_attributes, @survey.questions) do |question|
|
51
|
+
form_question.answer_options.each do |form_answer_option|
|
52
|
+
answer_option_attributes = {
|
53
|
+
body: form_answer_option.body,
|
54
|
+
free_text: form_answer_option.free_text
|
55
|
+
}
|
56
|
+
|
57
|
+
update_nested_model(form_answer_option, answer_option_attributes, question.answer_options)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_nested_model(form, attributes, parent_association)
|
63
|
+
record = parent_association.find_by(id: form.id) || parent_association.build(attributes)
|
64
|
+
|
65
|
+
yield record if block_given?
|
43
66
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
question.destroy!
|
48
|
-
else
|
49
|
-
question.update!(question_attributes)
|
50
|
-
end
|
67
|
+
if record.persisted?
|
68
|
+
if form.deleted?
|
69
|
+
record.destroy!
|
51
70
|
else
|
52
|
-
|
71
|
+
record.update!(attributes)
|
53
72
|
end
|
73
|
+
else
|
74
|
+
record.save!
|
54
75
|
end
|
55
76
|
end
|
56
77
|
|
@@ -29,12 +29,23 @@ module Decidim
|
|
29
29
|
def answer_survey
|
30
30
|
SurveyAnswer.transaction do
|
31
31
|
@form.answers.each do |form_answer|
|
32
|
-
SurveyAnswer.
|
32
|
+
answer = SurveyAnswer.new(
|
33
33
|
user: @current_user,
|
34
34
|
survey: @survey,
|
35
35
|
question: form_answer.question,
|
36
36
|
body: form_answer.body
|
37
37
|
)
|
38
|
+
|
39
|
+
form_answer.selected_choices.each do |choice|
|
40
|
+
answer.choices.build(
|
41
|
+
body: choice.body,
|
42
|
+
custom_body: choice.custom_body,
|
43
|
+
decidim_survey_answer_option_id: choice.answer_option_id,
|
44
|
+
position: choice.position
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
answer.save!
|
38
49
|
end
|
39
50
|
end
|
40
51
|
end
|
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
module Decidim
|
4
4
|
module Surveys
|
5
|
-
# Command that gets called whenever a
|
6
|
-
# usually happens as a callback when the
|
5
|
+
# Command that gets called whenever a component's survey has to be created. It
|
6
|
+
# usually happens as a callback when the component itself is created.
|
7
7
|
class CreateSurvey < Rectify::Command
|
8
|
-
def initialize(
|
9
|
-
@
|
8
|
+
def initialize(component)
|
9
|
+
@component = component
|
10
10
|
end
|
11
11
|
|
12
12
|
def call
|
13
|
-
@survey = Survey.new(
|
13
|
+
@survey = Survey.new(component: @component)
|
14
14
|
|
15
15
|
@survey.save ? broadcast(:ok) : broadcast(:invalid)
|
16
16
|
end
|
@@ -6,9 +6,9 @@ module Decidim
|
|
6
6
|
# This controller is the abstract class from which all other controllers of
|
7
7
|
# this engine inherit.
|
8
8
|
#
|
9
|
-
# Note that it inherits from `Decidim::Admin::
|
9
|
+
# Note that it inherits from `Decidim::Admin::Components::BaseController`, which
|
10
10
|
# override its layout and provide all kinds of useful methods.
|
11
|
-
class ApplicationController < Decidim::Admin::
|
11
|
+
class ApplicationController < Decidim::Admin::Components::BaseController
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -33,15 +33,15 @@ module Decidim
|
|
33
33
|
private
|
34
34
|
|
35
35
|
def survey
|
36
|
-
@survey ||= Survey.find_by(
|
36
|
+
@survey ||= Survey.find_by(component: current_component)
|
37
37
|
end
|
38
38
|
|
39
39
|
def blank_question
|
40
|
-
@blank_question ||=
|
40
|
+
@blank_question ||= Admin::SurveyQuestionForm.new
|
41
41
|
end
|
42
42
|
|
43
43
|
def blank_answer_option
|
44
|
-
@blank_answer_option ||=
|
44
|
+
@blank_answer_option ||= Admin::SurveyAnswerOptionForm.new
|
45
45
|
end
|
46
46
|
|
47
47
|
def question_types
|
@@ -5,9 +5,9 @@ module Decidim
|
|
5
5
|
# This controller is the abstract class from which all other controllers of
|
6
6
|
# this engine inherit.
|
7
7
|
#
|
8
|
-
# Note that it inherits from `Decidim::
|
8
|
+
# Note that it inherits from `Decidim::Components::BaseController`, which
|
9
9
|
# override its layout and provide all kinds of useful methods.
|
10
|
-
class ApplicationController < Decidim::
|
10
|
+
class ApplicationController < Decidim::Components::BaseController
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
module Admin
|
6
|
+
# This class holds a Form to update survey question answer options
|
7
|
+
class SurveyAnswerOptionForm < Decidim::Form
|
8
|
+
include TranslatableAttributes
|
9
|
+
|
10
|
+
attribute :deleted, Boolean, default: false
|
11
|
+
attribute :free_text, Boolean
|
12
|
+
|
13
|
+
translatable_attribute :body, String
|
14
|
+
|
15
|
+
validates :body, translatable_presence: true, unless: :deleted
|
16
|
+
|
17
|
+
def to_param
|
18
|
+
id || "survey-question-answer-option-id"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -10,11 +10,17 @@ module Decidim
|
|
10
10
|
translatable_attribute :title, String
|
11
11
|
translatable_attribute :description, String
|
12
12
|
translatable_attribute :tos, String
|
13
|
-
attribute :published_at, DateTime
|
14
13
|
|
14
|
+
attribute :published_at, DateTime
|
15
15
|
attribute :questions, Array[SurveyQuestionForm]
|
16
16
|
|
17
17
|
validates :title, :tos, translatable_presence: true
|
18
|
+
|
19
|
+
def map_model(model)
|
20
|
+
self.questions = model.questions.map do |question|
|
21
|
+
SurveyQuestionForm.from_model(question)
|
22
|
+
end
|
23
|
+
end
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
@@ -7,18 +7,28 @@ module Decidim
|
|
7
7
|
class SurveyQuestionForm < Decidim::Form
|
8
8
|
include TranslatableAttributes
|
9
9
|
|
10
|
-
attribute :id, String
|
11
10
|
attribute :position, Integer
|
12
11
|
attribute :mandatory, Boolean, default: false
|
13
12
|
attribute :question_type, String
|
14
|
-
attribute :answer_options, Array[
|
13
|
+
attribute :answer_options, Array[SurveyAnswerOptionForm]
|
14
|
+
attribute :max_choices, Integer
|
15
15
|
attribute :deleted, Boolean, default: false
|
16
16
|
|
17
17
|
translatable_attribute :body, String
|
18
|
+
translatable_attribute :description, String
|
18
19
|
|
19
20
|
validates :position, numericality: { greater_than_or_equal_to: 0 }
|
20
21
|
validates :question_type, inclusion: { in: SurveyQuestion::TYPES }
|
22
|
+
validates :max_choices, numericality: { only_integer: true, greater_than: 1, less_than_or_equal_to: ->(form) { form.number_of_options } }, allow_blank: true
|
21
23
|
validates :body, translatable_presence: true, unless: :deleted
|
24
|
+
|
25
|
+
def to_param
|
26
|
+
id || "survey-question-id"
|
27
|
+
end
|
28
|
+
|
29
|
+
def number_of_options
|
30
|
+
answer_options.size
|
31
|
+
end
|
22
32
|
end
|
23
33
|
end
|
24
34
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Surveys
|
5
|
+
# This class holds a Form to update survey question answer options
|
6
|
+
class SurveyAnswerChoiceForm < Decidim::Form
|
7
|
+
attribute :body, String
|
8
|
+
attribute :custom_body, String
|
9
|
+
attribute :position, Integer
|
10
|
+
attribute :answer_option_id, Integer
|
11
|
+
|
12
|
+
validates :answer_option_id, presence: true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -4,32 +4,66 @@ module Decidim
|
|
4
4
|
module Surveys
|
5
5
|
# This class holds a Form to update survey unswers from Decidim's public page
|
6
6
|
class SurveyAnswerForm < Decidim::Form
|
7
|
+
include Decidim::TranslationsHelper
|
8
|
+
|
7
9
|
attribute :question_id, String
|
8
10
|
attribute :body, String
|
11
|
+
attribute :choices, Array[SurveyAnswerChoiceForm]
|
12
|
+
|
13
|
+
validates :body, presence: true, if: :mandatory_body?
|
14
|
+
validates :selected_choices, presence: true, if: :mandatory_choices?
|
9
15
|
|
10
|
-
|
11
|
-
validate :
|
16
|
+
validate :max_choices, if: -> { question.max_choices }
|
17
|
+
validate :all_choices, if: -> { question.question_type == "sorting" }
|
18
|
+
|
19
|
+
delegate :mandatory_body?, :mandatory_choices?, to: :question
|
12
20
|
|
13
21
|
def question
|
14
22
|
@question ||= survey.questions.find(question_id)
|
15
23
|
end
|
16
24
|
|
25
|
+
def label(idx)
|
26
|
+
base = "#{idx + 1}. #{translated_attribute(question.body)}"
|
27
|
+
base += " #{mandatory_label}" if question.mandatory?
|
28
|
+
base += " (#{max_choices_label})" if question.max_choices
|
29
|
+
base
|
30
|
+
end
|
31
|
+
|
17
32
|
# Public: Map the correct fields.
|
18
33
|
#
|
19
34
|
# Returns nothing.
|
20
35
|
def map_model(model)
|
21
36
|
self.question_id = model.decidim_survey_question_id
|
37
|
+
|
38
|
+
self.choices = model.choices.map do |choice|
|
39
|
+
SurveyAnswerChoiceForm.from_model(choice)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def selected_choices
|
44
|
+
choices.select(&:body)
|
22
45
|
end
|
23
46
|
|
24
47
|
private
|
25
48
|
|
26
49
|
def survey
|
27
|
-
@survey ||= Survey.
|
50
|
+
@survey ||= Survey.find_by(component: current_component)
|
51
|
+
end
|
52
|
+
|
53
|
+
def max_choices
|
54
|
+
errors.add(:choices, :too_many) if selected_choices.size > question.max_choices
|
55
|
+
end
|
56
|
+
|
57
|
+
def all_choices
|
58
|
+
errors.add(:choices, :missing) if selected_choices.size != question.number_of_options
|
59
|
+
end
|
60
|
+
|
61
|
+
def mandatory_label
|
62
|
+
"*"
|
28
63
|
end
|
29
64
|
|
30
|
-
def
|
31
|
-
|
32
|
-
errors.add("body", :blank) if body.all?(&:blank?)
|
65
|
+
def max_choices_label
|
66
|
+
I18n.t("surveys.question.max_choices", scope: "decidim.surveys", n: question.max_choices)
|
33
67
|
end
|
34
68
|
end
|
35
69
|
end
|
@@ -14,7 +14,7 @@ module Decidim
|
|
14
14
|
# Returns nothing.
|
15
15
|
def map_model(model)
|
16
16
|
self.answers = model.questions.map do |question|
|
17
|
-
SurveyAnswerForm.
|
17
|
+
SurveyAnswerForm.from_model(SurveyAnswer.new(question: question))
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -7,27 +7,11 @@ module Decidim
|
|
7
7
|
#
|
8
8
|
module ApplicationHelper
|
9
9
|
def tabs_id_for_question(question)
|
10
|
-
|
11
|
-
"${tabsId}"
|
10
|
+
"survey_question_#{question.to_param}"
|
12
11
|
end
|
13
12
|
|
14
|
-
def tabs_id_for_question_answer_option(question,
|
15
|
-
|
16
|
-
"${tabsId}"
|
17
|
-
end
|
18
|
-
|
19
|
-
def mandatory_id_for_question(question)
|
20
|
-
return "survey_questions_#{question.id}_mandatory" if question.persisted?
|
21
|
-
"${tabsId}_mandatory"
|
22
|
-
end
|
23
|
-
|
24
|
-
def question_type_id_for_question(question)
|
25
|
-
return "survey_questions_#{question.id}_question_type" if question.persisted?
|
26
|
-
"${tabsId}_question_type"
|
27
|
-
end
|
28
|
-
|
29
|
-
def disabled_for_question(survey, question)
|
30
|
-
!question.persisted? || !survey.questions_editable?
|
13
|
+
def tabs_id_for_question_answer_option(question, answer_option)
|
14
|
+
"survey_question_#{question.to_param}_answer_option_#{answer_option.to_param}"
|
31
15
|
end
|
32
16
|
end
|
33
17
|
end
|
@@ -3,10 +3,10 @@
|
|
3
3
|
module Decidim
|
4
4
|
module Surveys
|
5
5
|
class SettingsChangeJob < ApplicationJob
|
6
|
-
def perform(
|
6
|
+
def perform(component_id, previous_settings, current_settings)
|
7
7
|
return if unchanged?(previous_settings, current_settings)
|
8
8
|
|
9
|
-
|
9
|
+
component = Decidim::Component.find(component_id)
|
10
10
|
|
11
11
|
if survey_opened?(previous_settings, current_settings)
|
12
12
|
event = "decidim.events.surveys.survey_opened"
|
@@ -19,8 +19,8 @@ module Decidim
|
|
19
19
|
Decidim::EventsManager.publish(
|
20
20
|
event: event,
|
21
21
|
event_class: event_class,
|
22
|
-
resource:
|
23
|
-
recipient_ids:
|
22
|
+
resource: component,
|
23
|
+
recipient_ids: component.participatory_space.followers.pluck(:id)
|
24
24
|
)
|
25
25
|
end
|
26
26
|
|
@@ -22,24 +22,24 @@ module Decidim
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def authorized?(action)
|
25
|
-
return unless
|
25
|
+
return unless component
|
26
26
|
|
27
|
-
ActionAuthorizer.new(user,
|
27
|
+
ActionAuthorizer.new(user, component, action).authorize.ok?
|
28
28
|
end
|
29
29
|
|
30
30
|
def current_settings
|
31
31
|
context.fetch(:current_settings, nil)
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
35
|
-
context.fetch(:
|
34
|
+
def component_settings
|
35
|
+
context.fetch(:component_settings, nil)
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
39
|
-
|
40
|
-
return nil unless
|
38
|
+
def component
|
39
|
+
component = context.fetch(:current_component, nil)
|
40
|
+
return nil unless component && component.manifest.name == :surveys
|
41
41
|
|
42
|
-
|
42
|
+
component
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -4,9 +4,9 @@ module Decidim
|
|
4
4
|
module Surveys
|
5
5
|
# The data store for a Survey in the Decidim::Surveys component.
|
6
6
|
class Survey < Surveys::ApplicationRecord
|
7
|
-
include Decidim::
|
7
|
+
include Decidim::HasComponent
|
8
8
|
|
9
|
-
|
9
|
+
component_manifest_name "surveys"
|
10
10
|
|
11
11
|
has_many :questions, -> { order(:position) }, class_name: "SurveyQuestion", foreign_key: "decidim_survey_id", dependent: :destroy
|
12
12
|
has_many :answers, class_name: "SurveyAnswer", foreign_key: "decidim_survey_id", dependent: :destroy
|