decidim-surveys 0.15.2 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +15 -9
- data/app/assets/stylesheets/decidim/surveys/surveys.scss +2 -2
- data/app/commands/decidim/surveys/create_survey.rb +1 -1
- data/app/controllers/decidim/surveys/admin/surveys_controller.rb +6 -37
- data/app/controllers/decidim/surveys/surveys_controller.rb +8 -22
- data/app/jobs/decidim/surveys/settings_change_job.rb +6 -3
- data/app/models/decidim/surveys/survey.rb +2 -12
- data/app/permissions/decidim/surveys/admin/permissions.rb +1 -1
- data/app/permissions/decidim/surveys/permissions.rb +1 -1
- data/app/queries/decidim/surveys/metrics/answers_metric_manage.rb +70 -0
- data/app/queries/decidim/surveys/metrics/survey_participants_metric_measure.rb +30 -0
- data/config/locales/ca.yml +5 -66
- data/config/locales/de.yml +5 -66
- data/config/locales/en.yml +5 -66
- data/config/locales/es-PY.yml +5 -66
- data/config/locales/es.yml +5 -66
- data/config/locales/eu.yml +5 -66
- data/config/locales/fi-pl.yml +5 -66
- data/config/locales/fi.yml +5 -66
- data/config/locales/fr.yml +5 -66
- data/config/locales/gl.yml +5 -66
- data/config/locales/hu.yml +5 -66
- data/config/locales/id-ID.yml +0 -70
- data/config/locales/it.yml +5 -66
- data/config/locales/nl.yml +5 -66
- data/config/locales/pl.yml +5 -66
- data/config/locales/pt-BR.yml +5 -66
- data/config/locales/pt.yml +5 -66
- data/config/locales/ru.yml +0 -66
- data/config/locales/sv.yml +5 -66
- data/config/locales/tr-TR.yml +0 -70
- data/config/locales/uk.yml +0 -66
- data/lib/decidim/surveys.rb +0 -2
- data/lib/decidim/surveys/admin_engine.rb +1 -5
- data/lib/decidim/surveys/component.rb +18 -15
- data/lib/decidim/surveys/engine.rb +17 -4
- data/lib/decidim/surveys/test/factories.rb +2 -42
- data/lib/decidim/surveys/version.rb +1 -1
- data/lib/tasks/decidim_surveys_tasks.rake +92 -0
- metadata +28 -42
- data/app/assets/config/admin/decidim_surveys_manifest.js +0 -1
- data/app/assets/config/decidim_surveys_manifest.js +0 -1
- data/app/assets/images/decidim/surveys/icon.svg +0 -19
- data/app/assets/javascripts/decidim/surveys/admin/auto_buttons_by_min_items.component.js.es6 +0 -25
- data/app/assets/javascripts/decidim/surveys/admin/auto_select_options_by_total_items.component.js.es6 +0 -23
- data/app/assets/javascripts/decidim/surveys/admin/surveys.js.es6 +0 -188
- data/app/assets/javascripts/decidim/surveys/autosortable_checkboxes.component.js.es6 +0 -65
- data/app/assets/javascripts/decidim/surveys/option_attached_inputs.component.js.es6 +0 -32
- data/app/assets/javascripts/decidim/surveys/surveys.js.es6 +0 -20
- data/app/commands/decidim/surveys/admin/update_survey.rb +0 -86
- data/app/commands/decidim/surveys/answer_survey.rb +0 -54
- data/app/forms/decidim/surveys/admin/survey_answer_option_form.rb +0 -23
- data/app/forms/decidim/surveys/admin/survey_form.rb +0 -27
- data/app/forms/decidim/surveys/admin/survey_question_form.rb +0 -35
- data/app/forms/decidim/surveys/survey_answer_choice_form.rb +0 -15
- data/app/forms/decidim/surveys/survey_answer_form.rb +0 -69
- data/app/forms/decidim/surveys/survey_form.rb +0 -22
- data/app/helpers/decidim/surveys/admin/application_helper.rb +0 -19
- data/app/models/decidim/surveys/survey_answer.rb +0 -45
- data/app/models/decidim/surveys/survey_answer_choice.rb +0 -15
- data/app/models/decidim/surveys/survey_answer_option.rb +0 -11
- data/app/models/decidim/surveys/survey_question.rb +0 -36
- data/app/queries/decidim/surveys/survey_user_answers.rb +0 -28
- data/app/views/decidim/surveys/admin/surveys/_answer_option.html.erb +0 -44
- data/app/views/decidim/surveys/admin/surveys/_form.html.erb +0 -51
- data/app/views/decidim/surveys/admin/surveys/_question.html.erb +0 -115
- data/app/views/decidim/surveys/admin/surveys/edit.html.erb +0 -7
- data/app/views/decidim/surveys/surveys/_answer.html.erb +0 -94
- data/app/views/decidim/surveys/surveys/show.html.erb +0 -84
- data/lib/decidim/surveys/data_portability_survey_user_answers_serializer.rb +0 -37
- data/lib/decidim/surveys/survey_user_answers_serializer.rb +0 -29
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
# This command is executed when the user answers a Survey.
|
6
|
-
class AnswerSurvey < Rectify::Command
|
7
|
-
# Initializes a AnswerSurvey Command.
|
8
|
-
#
|
9
|
-
# form - The form from which to get the data.
|
10
|
-
# survey - The current instance of the survey to be answered.
|
11
|
-
def initialize(form, current_user, survey)
|
12
|
-
@form = form
|
13
|
-
@current_user = current_user
|
14
|
-
@survey = survey
|
15
|
-
end
|
16
|
-
|
17
|
-
# Answers a survey if it is valid
|
18
|
-
#
|
19
|
-
# Broadcasts :ok if successful, :invalid otherwise.
|
20
|
-
def call
|
21
|
-
return broadcast(:invalid) if @form.invalid?
|
22
|
-
|
23
|
-
answer_survey
|
24
|
-
broadcast(:ok)
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def answer_survey
|
30
|
-
SurveyAnswer.transaction do
|
31
|
-
@form.survey_answers.each do |form_answer|
|
32
|
-
answer = SurveyAnswer.new(
|
33
|
-
user: @current_user,
|
34
|
-
survey: @survey,
|
35
|
-
question: form_answer.question,
|
36
|
-
body: form_answer.body
|
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!
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,23 +0,0 @@
|
|
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
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
module Admin
|
6
|
-
# This class holds a Form to update surveys from Decidim's admin panel.
|
7
|
-
class SurveyForm < Decidim::Form
|
8
|
-
include TranslatableAttributes
|
9
|
-
|
10
|
-
translatable_attribute :title, String
|
11
|
-
translatable_attribute :description, String
|
12
|
-
translatable_attribute :tos, String
|
13
|
-
|
14
|
-
attribute :published_at, Decidim::Attributes::TimeWithZone
|
15
|
-
attribute :questions, Array[SurveyQuestionForm]
|
16
|
-
|
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
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
module Admin
|
6
|
-
# This class holds a Form to update survey questions from Decidim's admin panel.
|
7
|
-
class SurveyQuestionForm < Decidim::Form
|
8
|
-
include TranslatableAttributes
|
9
|
-
|
10
|
-
attribute :position, Integer
|
11
|
-
attribute :mandatory, Boolean, default: false
|
12
|
-
attribute :question_type, String
|
13
|
-
attribute :answer_options, Array[SurveyAnswerOptionForm]
|
14
|
-
attribute :max_choices, Integer
|
15
|
-
attribute :deleted, Boolean, default: false
|
16
|
-
|
17
|
-
translatable_attribute :body, String
|
18
|
-
translatable_attribute :description, String
|
19
|
-
|
20
|
-
validates :position, numericality: { greater_than_or_equal_to: 0 }
|
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
|
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
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,15 +0,0 @@
|
|
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
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
# This class holds a Form to update survey unswers from Decidim's public page
|
6
|
-
class SurveyAnswerForm < Decidim::Form
|
7
|
-
include Decidim::TranslationsHelper
|
8
|
-
|
9
|
-
attribute :question_id, String
|
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?
|
15
|
-
|
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
|
20
|
-
|
21
|
-
attr_writer :question
|
22
|
-
|
23
|
-
def question
|
24
|
-
@question ||= Decidim::Surveys::SurveyQuestion.find(question_id)
|
25
|
-
end
|
26
|
-
|
27
|
-
def label(idx)
|
28
|
-
base = "#{idx + 1}. #{translated_attribute(question.body)}"
|
29
|
-
base += " #{mandatory_label}" if question.mandatory?
|
30
|
-
base += " (#{max_choices_label})" if question.max_choices
|
31
|
-
base
|
32
|
-
end
|
33
|
-
|
34
|
-
# Public: Map the correct fields.
|
35
|
-
#
|
36
|
-
# Returns nothing.
|
37
|
-
def map_model(model)
|
38
|
-
self.question_id = model.decidim_survey_question_id
|
39
|
-
self.question = model.question
|
40
|
-
|
41
|
-
self.choices = model.choices.map do |choice|
|
42
|
-
SurveyAnswerChoiceForm.from_model(choice)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def selected_choices
|
47
|
-
choices.select(&:body)
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def max_choices
|
53
|
-
errors.add(:choices, :too_many) if selected_choices.size > question.max_choices
|
54
|
-
end
|
55
|
-
|
56
|
-
def all_choices
|
57
|
-
errors.add(:choices, :missing) if selected_choices.size != question.number_of_options
|
58
|
-
end
|
59
|
-
|
60
|
-
def mandatory_label
|
61
|
-
"*"
|
62
|
-
end
|
63
|
-
|
64
|
-
def max_choices_label
|
65
|
-
I18n.t("surveys.question.max_choices", scope: "decidim.surveys", n: question.max_choices)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
# This class holds a Form to answer a surveys from Decidim's public page.
|
6
|
-
class SurveyForm < Decidim::Form
|
7
|
-
attribute :survey_answers, Array[SurveyAnswerForm]
|
8
|
-
|
9
|
-
attribute :tos_agreement, Boolean
|
10
|
-
validates :tos_agreement, allow_nil: false, acceptance: true
|
11
|
-
|
12
|
-
# Private: Create the answers from the survey questions
|
13
|
-
#
|
14
|
-
# Returns nothing.
|
15
|
-
def map_model(model)
|
16
|
-
self.survey_answers = model.questions.map do |question|
|
17
|
-
SurveyAnswerForm.from_model(SurveyAnswer.new(question: question))
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
module Admin
|
6
|
-
# Custom helpers, scoped to the surveys engine.
|
7
|
-
#
|
8
|
-
module ApplicationHelper
|
9
|
-
def tabs_id_for_question(question)
|
10
|
-
"survey_question_#{question.to_param}"
|
11
|
-
end
|
12
|
-
|
13
|
-
def tabs_id_for_question_answer_option(question, answer_option)
|
14
|
-
"survey_question_#{question.to_param}_answer_option_#{answer_option.to_param}"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
# The data store for a SurveyAnswer in the Decidim::Surveys component.
|
6
|
-
class SurveyAnswer < Surveys::ApplicationRecord
|
7
|
-
include Decidim::DataPortability
|
8
|
-
|
9
|
-
belongs_to :user, class_name: "Decidim::User", foreign_key: "decidim_user_id"
|
10
|
-
belongs_to :survey, class_name: "Survey", foreign_key: "decidim_survey_id"
|
11
|
-
belongs_to :question, class_name: "SurveyQuestion", foreign_key: "decidim_survey_question_id"
|
12
|
-
|
13
|
-
has_many :choices,
|
14
|
-
class_name: "SurveyAnswerChoice",
|
15
|
-
foreign_key: "decidim_survey_answer_id",
|
16
|
-
dependent: :destroy,
|
17
|
-
inverse_of: :answer
|
18
|
-
|
19
|
-
validates :body, presence: true, if: -> { question.mandatory_body? }
|
20
|
-
validates :choices, presence: true, if: -> { question.mandatory_choices? }
|
21
|
-
|
22
|
-
validate :user_survey_same_organization
|
23
|
-
validate :question_belongs_to_survey
|
24
|
-
|
25
|
-
def self.user_collection(user)
|
26
|
-
where(decidim_user_id: user.id)
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.export_serializer
|
30
|
-
Decidim::Surveys::DataPortabilitySurveyUserAnswersSerializer
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def user_survey_same_organization
|
36
|
-
return if user&.organization == survey&.organization
|
37
|
-
errors.add(:user, :invalid)
|
38
|
-
end
|
39
|
-
|
40
|
-
def question_belongs_to_survey
|
41
|
-
errors.add(:survey, :invalid) if question&.survey != survey
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
class SurveyAnswerChoice < Surveys::ApplicationRecord
|
6
|
-
belongs_to :answer,
|
7
|
-
class_name: "SurveyAnswer",
|
8
|
-
foreign_key: "decidim_survey_answer_id"
|
9
|
-
|
10
|
-
belongs_to :answer_option,
|
11
|
-
class_name: "SurveyAnswerOption",
|
12
|
-
foreign_key: "decidim_survey_answer_option_id"
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
class SurveyAnswerOption < Surveys::ApplicationRecord
|
6
|
-
default_scope { order(arel_table[:id].asc) }
|
7
|
-
|
8
|
-
belongs_to :question, class_name: "SurveyQuestion", foreign_key: "decidim_survey_question_id"
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
# The data store for a SurveyQuestion in the Decidim::Surveys component.
|
6
|
-
class SurveyQuestion < Surveys::ApplicationRecord
|
7
|
-
TYPES = %w(short_answer long_answer single_option multiple_option sorting).freeze
|
8
|
-
|
9
|
-
belongs_to :survey, class_name: "Survey", foreign_key: "decidim_survey_id"
|
10
|
-
|
11
|
-
has_many :answer_options,
|
12
|
-
class_name: "SurveyAnswerOption",
|
13
|
-
foreign_key: "decidim_survey_question_id",
|
14
|
-
dependent: :destroy,
|
15
|
-
inverse_of: :question
|
16
|
-
|
17
|
-
validates :question_type, inclusion: { in: TYPES }
|
18
|
-
|
19
|
-
def multiple_choice?
|
20
|
-
%w(single_option multiple_option sorting).include?(question_type)
|
21
|
-
end
|
22
|
-
|
23
|
-
def mandatory_body?
|
24
|
-
mandatory? && !multiple_choice?
|
25
|
-
end
|
26
|
-
|
27
|
-
def mandatory_choices?
|
28
|
-
mandatory? && multiple_choice?
|
29
|
-
end
|
30
|
-
|
31
|
-
def number_of_options
|
32
|
-
answer_options.size
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Decidim
|
4
|
-
module Surveys
|
5
|
-
# A class used to collect user answers for a survey
|
6
|
-
class SurveyUserAnswers < Rectify::Query
|
7
|
-
# Syntactic sugar to initialize the class and return the queried objects.
|
8
|
-
#
|
9
|
-
# survey - a Survey object
|
10
|
-
def self.for(survey)
|
11
|
-
new(survey).query
|
12
|
-
end
|
13
|
-
|
14
|
-
# Initializes the class.
|
15
|
-
#
|
16
|
-
# survey = a Survey object
|
17
|
-
def initialize(survey)
|
18
|
-
@survey = survey
|
19
|
-
end
|
20
|
-
|
21
|
-
# Finds and group answers by user for each survey's question.
|
22
|
-
def query
|
23
|
-
answers = SurveyAnswer.where(survey: @survey)
|
24
|
-
answers.sort_by { |answer| answer.question.position }.group_by(&:user).values
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
<% answer_option = form.object %>
|
2
|
-
|
3
|
-
<div class="card survey-question-answer-option">
|
4
|
-
<div class="card-divider">
|
5
|
-
<h2 class="card-title">
|
6
|
-
<span><%= t(".answer_option") %></span>
|
7
|
-
<% if editable %>
|
8
|
-
<button class="button small alert hollow remove-answer-option button--title">
|
9
|
-
<%= t(".remove") %>
|
10
|
-
</button>
|
11
|
-
<% end %>
|
12
|
-
</h2>
|
13
|
-
</div>
|
14
|
-
|
15
|
-
<div class="card-section">
|
16
|
-
<div class="row column">
|
17
|
-
<%=
|
18
|
-
form.translated(
|
19
|
-
:text_field,
|
20
|
-
:body,
|
21
|
-
tabs_id: tabs_id_for_question_answer_option(question, answer_option),
|
22
|
-
label: t(".statement"),
|
23
|
-
disabled: !editable
|
24
|
-
)
|
25
|
-
%>
|
26
|
-
</div>
|
27
|
-
|
28
|
-
<div class="row column">
|
29
|
-
<%=
|
30
|
-
form.check_box(
|
31
|
-
:free_text,
|
32
|
-
label: t(".free_text"),
|
33
|
-
disabled: !survey.questions_editable?
|
34
|
-
)
|
35
|
-
%>
|
36
|
-
</div>
|
37
|
-
</div>
|
38
|
-
|
39
|
-
<% if answer_option.persisted? %>
|
40
|
-
<%= form.hidden_field :id, disabled: !editable %>
|
41
|
-
<% end %>
|
42
|
-
|
43
|
-
<%= form.hidden_field :deleted, disabled: !editable %>
|
44
|
-
</div>
|