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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -9
  3. data/app/assets/stylesheets/decidim/surveys/surveys.scss +2 -2
  4. data/app/commands/decidim/surveys/create_survey.rb +1 -1
  5. data/app/controllers/decidim/surveys/admin/surveys_controller.rb +6 -37
  6. data/app/controllers/decidim/surveys/surveys_controller.rb +8 -22
  7. data/app/jobs/decidim/surveys/settings_change_job.rb +6 -3
  8. data/app/models/decidim/surveys/survey.rb +2 -12
  9. data/app/permissions/decidim/surveys/admin/permissions.rb +1 -1
  10. data/app/permissions/decidim/surveys/permissions.rb +1 -1
  11. data/app/queries/decidim/surveys/metrics/answers_metric_manage.rb +70 -0
  12. data/app/queries/decidim/surveys/metrics/survey_participants_metric_measure.rb +30 -0
  13. data/config/locales/ca.yml +5 -66
  14. data/config/locales/de.yml +5 -66
  15. data/config/locales/en.yml +5 -66
  16. data/config/locales/es-PY.yml +5 -66
  17. data/config/locales/es.yml +5 -66
  18. data/config/locales/eu.yml +5 -66
  19. data/config/locales/fi-pl.yml +5 -66
  20. data/config/locales/fi.yml +5 -66
  21. data/config/locales/fr.yml +5 -66
  22. data/config/locales/gl.yml +5 -66
  23. data/config/locales/hu.yml +5 -66
  24. data/config/locales/id-ID.yml +0 -70
  25. data/config/locales/it.yml +5 -66
  26. data/config/locales/nl.yml +5 -66
  27. data/config/locales/pl.yml +5 -66
  28. data/config/locales/pt-BR.yml +5 -66
  29. data/config/locales/pt.yml +5 -66
  30. data/config/locales/ru.yml +0 -66
  31. data/config/locales/sv.yml +5 -66
  32. data/config/locales/tr-TR.yml +0 -70
  33. data/config/locales/uk.yml +0 -66
  34. data/lib/decidim/surveys.rb +0 -2
  35. data/lib/decidim/surveys/admin_engine.rb +1 -5
  36. data/lib/decidim/surveys/component.rb +18 -15
  37. data/lib/decidim/surveys/engine.rb +17 -4
  38. data/lib/decidim/surveys/test/factories.rb +2 -42
  39. data/lib/decidim/surveys/version.rb +1 -1
  40. data/lib/tasks/decidim_surveys_tasks.rake +92 -0
  41. metadata +28 -42
  42. data/app/assets/config/admin/decidim_surveys_manifest.js +0 -1
  43. data/app/assets/config/decidim_surveys_manifest.js +0 -1
  44. data/app/assets/images/decidim/surveys/icon.svg +0 -19
  45. data/app/assets/javascripts/decidim/surveys/admin/auto_buttons_by_min_items.component.js.es6 +0 -25
  46. data/app/assets/javascripts/decidim/surveys/admin/auto_select_options_by_total_items.component.js.es6 +0 -23
  47. data/app/assets/javascripts/decidim/surveys/admin/surveys.js.es6 +0 -188
  48. data/app/assets/javascripts/decidim/surveys/autosortable_checkboxes.component.js.es6 +0 -65
  49. data/app/assets/javascripts/decidim/surveys/option_attached_inputs.component.js.es6 +0 -32
  50. data/app/assets/javascripts/decidim/surveys/surveys.js.es6 +0 -20
  51. data/app/commands/decidim/surveys/admin/update_survey.rb +0 -86
  52. data/app/commands/decidim/surveys/answer_survey.rb +0 -54
  53. data/app/forms/decidim/surveys/admin/survey_answer_option_form.rb +0 -23
  54. data/app/forms/decidim/surveys/admin/survey_form.rb +0 -27
  55. data/app/forms/decidim/surveys/admin/survey_question_form.rb +0 -35
  56. data/app/forms/decidim/surveys/survey_answer_choice_form.rb +0 -15
  57. data/app/forms/decidim/surveys/survey_answer_form.rb +0 -69
  58. data/app/forms/decidim/surveys/survey_form.rb +0 -22
  59. data/app/helpers/decidim/surveys/admin/application_helper.rb +0 -19
  60. data/app/models/decidim/surveys/survey_answer.rb +0 -45
  61. data/app/models/decidim/surveys/survey_answer_choice.rb +0 -15
  62. data/app/models/decidim/surveys/survey_answer_option.rb +0 -11
  63. data/app/models/decidim/surveys/survey_question.rb +0 -36
  64. data/app/queries/decidim/surveys/survey_user_answers.rb +0 -28
  65. data/app/views/decidim/surveys/admin/surveys/_answer_option.html.erb +0 -44
  66. data/app/views/decidim/surveys/admin/surveys/_form.html.erb +0 -51
  67. data/app/views/decidim/surveys/admin/surveys/_question.html.erb +0 -115
  68. data/app/views/decidim/surveys/admin/surveys/edit.html.erb +0 -7
  69. data/app/views/decidim/surveys/surveys/_answer.html.erb +0 -94
  70. data/app/views/decidim/surveys/surveys/show.html.erb +0 -84
  71. data/lib/decidim/surveys/data_portability_survey_user_answers_serializer.rb +0 -37
  72. 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>