decidim-consultations 0.18.1 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/decidim_consultations_manifest.css +0 -1
  3. data/app/assets/config/decidim_consultations_manifest.js +1 -1
  4. data/app/assets/javascripts/decidim/consultations/utils_multiple.js +21 -0
  5. data/app/assets/javascripts/decidim/consultations/vote_dialog.js +13 -0
  6. data/app/cells/decidim/consultations/consultation_m/data.erb +2 -2
  7. data/app/cells/decidim/consultations/content_blocks/highlighted_consultations_cell.rb +1 -0
  8. data/app/commands/decidim/consultations/admin/create_consultation.rb +2 -0
  9. data/app/commands/decidim/consultations/admin/create_question.rb +2 -0
  10. data/app/commands/decidim/consultations/admin/create_response.rb +1 -0
  11. data/app/commands/decidim/consultations/admin/update_consultation.rb +1 -0
  12. data/app/commands/decidim/consultations/admin/update_question.rb +1 -0
  13. data/app/commands/decidim/consultations/admin/update_question_configuration.rb +55 -0
  14. data/app/commands/decidim/consultations/admin/update_response.rb +1 -0
  15. data/app/commands/decidim/consultations/multiple_vote_question.rb +47 -0
  16. data/app/controllers/concerns/decidim/consultations/admin/question_admin.rb +1 -0
  17. data/app/controllers/concerns/decidim/consultations/needs_question.rb +24 -2
  18. data/app/controllers/concerns/decidim/consultations/orderable.rb +1 -21
  19. data/app/controllers/decidim/consultations/admin/consultations_controller.rb +7 -1
  20. data/app/controllers/decidim/consultations/admin/question_configuration_controller.rb +54 -0
  21. data/app/controllers/decidim/consultations/admin/question_permissions_controller.rb +36 -0
  22. data/app/controllers/decidim/consultations/admin/questions_controller.rb +1 -0
  23. data/app/controllers/decidim/consultations/authorization_vote_modals_controller.rb +26 -0
  24. data/app/controllers/decidim/consultations/consultations_controller.rb +1 -1
  25. data/app/controllers/decidim/consultations/question_multiple_votes_controller.rb +39 -0
  26. data/app/controllers/decidim/consultations/question_votes_controller.rb +1 -1
  27. data/app/forms/decidim/consultations/admin/question_configuration_form.rb +27 -0
  28. data/app/forms/decidim/consultations/multi_vote_form.rb +41 -0
  29. data/app/forms/decidim/consultations/vote_form.rb +1 -0
  30. data/app/helpers/decidim/consultations/questions_helper.rb +25 -4
  31. data/app/models/decidim/consultation.rb +9 -7
  32. data/app/models/decidim/consultations/question.rb +26 -7
  33. data/app/models/decidim/consultations/vote.rb +11 -1
  34. data/app/permissions/decidim/consultations/admin/permissions.rb +1 -1
  35. data/app/permissions/decidim/consultations/permissions.rb +10 -0
  36. data/app/views/decidim/consultations/admin/consultations/edit.html.erb +4 -1
  37. data/app/views/decidim/consultations/admin/consultations/index.html.erb +2 -2
  38. data/app/views/decidim/consultations/admin/consultations/results.html.erb +42 -0
  39. data/app/views/decidim/consultations/admin/question_configuration/_form.html.erb +19 -0
  40. data/app/views/decidim/consultations/admin/question_configuration/edit.html.erb +12 -0
  41. data/app/views/decidim/consultations/admin/questions/edit.html.erb +1 -0
  42. data/app/views/decidim/consultations/admin/questions/index.html.erb +6 -2
  43. data/app/views/decidim/consultations/consultations/_consultations.html.erb +1 -1
  44. data/app/views/decidim/consultations/consultations/_highlighted_questions.html.erb +7 -5
  45. data/app/views/decidim/consultations/question_multiple_votes/_form.html.erb +14 -0
  46. data/app/views/decidim/consultations/question_multiple_votes/_results_rules.html.erb +14 -0
  47. data/app/views/decidim/consultations/question_multiple_votes/_voting_rules.html.erb +29 -0
  48. data/app/views/decidim/consultations/question_multiple_votes/show.html.erb +36 -0
  49. data/app/views/decidim/consultations/question_votes/update_vote_button.js.erb +9 -0
  50. data/app/views/decidim/consultations/questions/_results.html.erb +4 -0
  51. data/app/views/decidim/consultations/questions/_vote_button.html.erb +29 -4
  52. data/app/views/decidim/consultations/questions/_vote_modal_confirm.html.erb +1 -0
  53. data/app/views/decidim/consultations/questions/show.html.erb +1 -1
  54. data/app/views/layouts/decidim/_question_header.html.erb +2 -14
  55. data/app/views/layouts/decidim/_question_header_buttons.html.erb +11 -0
  56. data/app/views/layouts/decidim/admin/consultation.html.erb +4 -0
  57. data/app/views/layouts/decidim/admin/question.html.erb +66 -44
  58. data/app/views/layouts/decidim/question.html.erb +3 -3
  59. data/app/views/layouts/decidim/question_multivote.html.erb +9 -0
  60. data/config/locales/ar.yml +8 -0
  61. data/config/locales/ca.yml +51 -0
  62. data/config/locales/cs.yml +51 -0
  63. data/config/locales/en.yml +51 -0
  64. data/config/locales/es-MX.yml +13 -0
  65. data/config/locales/es-PY.yml +13 -0
  66. data/config/locales/es.yml +51 -0
  67. data/config/locales/fi-plain.yml +51 -0
  68. data/config/locales/fi.yml +51 -0
  69. data/config/locales/fr.yml +50 -0
  70. data/config/locales/hu.yml +51 -0
  71. data/config/locales/it.yml +15 -0
  72. data/config/locales/nl.yml +52 -1
  73. data/config/locales/sv.yml +9 -0
  74. data/config/locales/tr-TR.yml +5 -0
  75. data/db/migrate/20190702162755_add_options_to_decidim_consultations_questions.rb +8 -0
  76. data/db/migrate/20190710121122_add_free_instructions_field_to_consultations_questions.rb +7 -0
  77. data/lib/decidim/consultations/admin_engine.rb +3 -0
  78. data/lib/decidim/consultations/engine.rb +4 -0
  79. data/lib/decidim/consultations/participatory_space.rb +5 -0
  80. data/lib/decidim/consultations/test/factories.rb +5 -0
  81. data/lib/decidim/consultations/version.rb +1 -1
  82. metadata +29 -11
  83. data/app/assets/javascripts/decidim/consultations/social_share.js +0 -2
  84. data/app/assets/stylesheets/decidim/consultations/social_share.css.scss +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc706fdf5d89c2cd17fbb386c30fee7853848187352cf1474e1c89331d252043
4
- data.tar.gz: 99a45a9787dc797826602401ec211a76a3fb388196ce2a7306000a83b8416bc6
3
+ metadata.gz: 0e211d930720567fda60e8679412d8b5242242f3e4910268c5621a5cb15843b7
4
+ data.tar.gz: 9f90cf27d78ae903ff0558b2351dc3f746ef4f30a2b70fdc0f1bc56a024bb6f1
5
5
  SHA512:
6
- metadata.gz: e13562d482ad263b61e25a6db96c98d20def973cf41a26140fc656b912787693e4a3ebbd10b8e641f7ad4239315aaf571b1f225b543cfb2b7becbdedf32c2fb7
7
- data.tar.gz: f7861c99459950fa1d7ca9c3c8a6d2b6d2ec529640bd65cc1c7774dcb8fd405cbd44493687edc6e9e5d455c0f502b5ca31d92ee0088f290cac831a9b83aed1e1
6
+ metadata.gz: 12c499d436225a6c0824558b793fc8807277d9b38b71f2e0a40d5567effa7d3b2fc175576fc5a4aa8414010ec48becd108bc08a29847929df6766462e35597fe
7
+ data.tar.gz: b1b4e4ca6e93212b39cf72b01a90be8746586b38db8c5d3068ab6e0b763b036b5a8740be792e4d7f81004a05488595d9177662257c6c4584b222bcbf445aed44
@@ -1,4 +1,3 @@
1
1
  /*
2
- *= link decidim/consultations/social_share.css.scss
3
2
  *= link decidim/consultations/highlighted-content-banner.css.scss
4
3
  */
@@ -1,5 +1,5 @@
1
1
  //= link_directory ../images/decidim/consultations
2
- //= link decidim/consultations/social_share.js
3
2
  //= link decidim/consultations/utils.js
3
+ //= link decidim/consultations/utils_multiple.js
4
4
  //= link decidim/consultations/vote_dialog.js
5
5
  //= link decidim/consultations/show_more.js
@@ -0,0 +1,21 @@
1
+ /* eslint-disable no-invalid-this, no-undefined */
2
+
3
+ $(document).ready(function () {
4
+ let $remainingVotesCount = $("#remaining-votes-count");
5
+ $('form .multiple_votes_form input[type="checkbox"]').on("change", function(event) {
6
+ let max = parseInt($remainingVotesCount.text(), 10);
7
+ if ($(this).is(":checked")) {
8
+ max -= 1;
9
+ }
10
+ else {
11
+ max += 1;
12
+ }
13
+ if (max < 0) {
14
+ $(this).attr("checked", false);
15
+ event.preventDefault();
16
+ }
17
+ else {
18
+ $remainingVotesCount.text(max);
19
+ }
20
+ });
21
+ });
@@ -30,7 +30,20 @@ $(document).ready(function () {
30
30
  });
31
31
  }
32
32
 
33
+ $("#confirm-vote-form").on("ajax:beforeSend", function() {
34
+ $("#confirm-vote-form-loader,#confirm-vote-form").toggleClass("hide");
35
+ });
36
+
33
37
  $("#confirm-vote-form").on("ajax:success", function() {
34
38
  voteConfirmDialog.foundation("close");
35
39
  });
40
+
41
+ $("#confirm-vote-form").on("ajax:error", function(event) {
42
+ const error = event && event.detail && event.detail[0].error;
43
+ $("#vote-result-callout").addClass("alert").removeClass("hide warning");
44
+ $("#vote-result-callout .callout-title").text($("#vote-result-callout").data("title-ko"));
45
+ $("#vote-result-callout .callout-message").text(error || $("#vote-result-callout").data("message-ko"));
46
+ $("#confirm-vote-form-loader,#confirm-vote-form").toggleClass("hide");
47
+ voteConfirmDialog.foundation("close");
48
+ });
36
49
  });
@@ -6,14 +6,14 @@
6
6
  <li class="card-data__item">
7
7
  <div class="card-data__item--centerblock">
8
8
  <strong><%= t("activemodel.attributes.consultation.start_voting_date") %></strong>
9
- <br />
9
+ <br>
10
10
  <%= start_date ? l(start_date, format: :decidim_short) : t("decidim.consultations.show.unspecified") %>
11
11
  </div>
12
12
  </li>
13
13
  <li class="card-data__item">
14
14
  <div class="card-data__item--centerblock">
15
15
  <strong><%= t("activemodel.attributes.consultation.end_voting_date") %></strong>
16
- <br />
16
+ <br>
17
17
  <%= end_date ? l(end_date, format: :decidim_short) : t("decidim.consultations.show.unspecified") %>
18
18
  </div>
19
19
  </li>
@@ -32,6 +32,7 @@ module Decidim
32
32
  def voting_ends_text_for(consultation)
33
33
  remaining_days = (consultation.end_voting_date - Time.zone.today).to_i
34
34
  return I18n.t("voting_ends_today", scope: i18n_scope) if remaining_days.zero?
35
+
35
36
  I18n.t("voting_ends_in", scope: i18n_scope, count: remaining_days)
36
37
  end
37
38
  end
@@ -21,6 +21,7 @@ module Decidim
21
21
  # Returns nothing.
22
22
  def call
23
23
  return broadcast(:invalid) if form.invalid?
24
+
24
25
  consultation = create_consultation
25
26
 
26
27
  if consultation.persisted?
@@ -52,6 +53,7 @@ module Decidim
52
53
  )
53
54
 
54
55
  return consultation unless consultation.valid?
56
+
55
57
  consultation.save
56
58
  consultation
57
59
  end
@@ -20,6 +20,7 @@ module Decidim
20
20
  # Returns nothing.
21
21
  def call
22
22
  return broadcast(:invalid) if form.invalid?
23
+
23
24
  question = create_question
24
25
 
25
26
  if question.persisted?
@@ -59,6 +60,7 @@ module Decidim
59
60
  )
60
61
 
61
62
  return question unless question.valid?
63
+
62
64
  question.save
63
65
  question
64
66
  end
@@ -20,6 +20,7 @@ module Decidim
20
20
  # Returns nothing.
21
21
  def call
22
22
  return broadcast(:invalid) if form.invalid?
23
+
23
24
  broadcast(:ok, create_response)
24
25
  end
25
26
 
@@ -23,6 +23,7 @@ module Decidim
23
23
  # Returns nothing.
24
24
  def call
25
25
  return broadcast(:invalid) if form.invalid?
26
+
26
27
  update_consultation
27
28
 
28
29
  if consultation.valid?
@@ -23,6 +23,7 @@ module Decidim
23
23
  # Returns nothing.
24
24
  def call
25
25
  return broadcast(:invalid) if form.invalid?
26
+
26
27
  update_question
27
28
 
28
29
  if question.valid?
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Consultations
5
+ module Admin
6
+ # A command that configures how many and how much questions can be voted.
7
+ class UpdateQuestionConfiguration < Rectify::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # question - the Question to update
11
+ # form - A form object with the params.
12
+ def initialize(question, form)
13
+ @question = question
14
+ @form = form
15
+ end
16
+
17
+ # Executes the command. Broadcasts these events:
18
+ #
19
+ # - :ok when everything is valid.
20
+ # - :invalid if the form wasn't valid and we couldn't proceed.
21
+ #
22
+ # Returns nothing.
23
+ def call
24
+ return broadcast(:invalid) if form.invalid?
25
+
26
+ # We don't have other question fields in this forms so any additional
27
+ # validation error will be just shown in a flash message
28
+ begin
29
+ update_question!
30
+ broadcast(:ok, question)
31
+ rescue StandardError => e
32
+ broadcast(:invalid, question, e.message)
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :form, :question
39
+
40
+ def update_question!
41
+ question.assign_attributes(attributes)
42
+ question.save!
43
+ end
44
+
45
+ def attributes
46
+ {
47
+ max_votes: form.max_votes,
48
+ min_votes: form.min_votes,
49
+ instructions: form.instructions
50
+ }
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -22,6 +22,7 @@ module Decidim
22
22
  # Returns nothing.
23
23
  def call
24
24
  return broadcast(:invalid) if form.invalid?
25
+
25
26
  update_response
26
27
  broadcast(:ok, response)
27
28
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Consultations
5
+ # A command with all the business logic when a user votes a multivote question.
6
+ class MultipleVoteQuestion < Rectify::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # form - A Decidim::Consultations::MultiVoteForm object.
10
+ # current_user - The current user.
11
+ def initialize(form, current_user)
12
+ @form = form
13
+ @current_user = current_user
14
+ end
15
+
16
+ # Executes the command. Broadcasts these events:
17
+ #
18
+ # - :ok when everything is valid, together with the vote.
19
+ # - :invalid if the form wasn't valid and we couldn't proceed.
20
+ #
21
+ # Returns nothing.
22
+ def call
23
+ return broadcast(:invalid, form, form.errors[:responses].first) if form.invalid?
24
+
25
+ ActiveRecord::Base.transaction do
26
+ form.vote_forms.each do |form|
27
+ create_vote! form
28
+ end
29
+ broadcast(:ok, form)
30
+ rescue StandardError => e
31
+ broadcast(:invalid, form, e.message)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :form
38
+
39
+ def create_vote!(vote_form)
40
+ @form.context.current_question.votes.create!(
41
+ author: @current_user,
42
+ response: vote_form.response
43
+ )
44
+ end
45
+ end
46
+ end
47
+ end
@@ -24,6 +24,7 @@ module Decidim
24
24
 
25
25
  def current_participatory_space
26
26
  return current_consultation if params.has_key? :consultation_slug
27
+
27
28
  current_question
28
29
  end
29
30
 
@@ -7,8 +7,8 @@ module Decidim
7
7
  module NeedsQuestion
8
8
  def self.enhance_controller(instance_or_module)
9
9
  instance_or_module.class_eval do
10
- helper_method :current_question, :previous_question, :next_question, :current_consultation, :current_participatory_space, :stats,
11
- :sorted_results
10
+ helper_method :current_question, :previous_question, :next_question, :previous_published_question, :next_published_question,
11
+ :current_consultation, :current_participatory_space, :stats, :sorted_results
12
12
 
13
13
  helper Decidim::WidgetUrlsHelper
14
14
  end
@@ -55,6 +55,20 @@ module Decidim
55
55
  current_consultation_questions.at(current_question_index + 1)
56
56
  end
57
57
 
58
+ # same as next_question but for published questions only
59
+ def next_published_question
60
+ return nil if current_published_question_index + 1 >= current_consultation_published_questions.size
61
+
62
+ current_consultation_published_questions.at(current_published_question_index + 1)
63
+ end
64
+
65
+ # same as previous_question but for published questions only
66
+ def previous_published_question
67
+ return nil if (current_published_question_index - 1).negative?
68
+
69
+ current_consultation_published_questions.at(current_published_question_index - 1)
70
+ end
71
+
58
72
  # Public: Finds the current Consultation given this controller's
59
73
  # context.
60
74
  #
@@ -89,9 +103,17 @@ module Decidim
89
103
  @current_consultation_questions ||= current_question.consultation.questions.to_a
90
104
  end
91
105
 
106
+ def current_consultation_published_questions
107
+ @current_consultation_published_questions ||= current_question.consultation.questions.published.to_a
108
+ end
109
+
92
110
  def current_question_index
93
111
  current_consultation_questions.find_index(current_question)
94
112
  end
113
+
114
+ def current_published_question_index
115
+ current_consultation_published_questions.find_index(current_question)
116
+ end
95
117
  end
96
118
  end
97
119
  end
@@ -9,29 +9,15 @@ module Decidim
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  included do
12
- helper_method :order, :available_orders, :random_seed
12
+ include Decidim::Orderable
13
13
 
14
14
  private
15
15
 
16
- # Gets how the proposals should be ordered based on the choice
17
- # made by the user.
18
- def order
19
- @order ||= detect_order(params[:order]) || default_order
20
- end
21
-
22
- def detect_order(candidate)
23
- available_orders.detect { |order| order == candidate }
24
- end
25
-
26
16
  # Available orders based on enabled settings
27
17
  def available_orders
28
18
  %w(random recent)
29
19
  end
30
20
 
31
- def default_order
32
- "random"
33
- end
34
-
35
21
  def reorder(consultations)
36
22
  case order
37
23
  when "recent"
@@ -40,12 +26,6 @@ module Decidim
40
26
  consultations.order_randomly(random_seed)
41
27
  end
42
28
  end
43
-
44
- # Returns: A random float number between -1 and 1 to be used as a
45
- # random seed at the database.
46
- def random_seed
47
- @random_seed ||= (params[:random_seed] ? params[:random_seed].to_f : (rand * 2 - 1))
48
- end
49
29
  end
50
30
  end
51
31
  end
@@ -44,7 +44,7 @@ module Decidim
44
44
  render layout: "decidim/admin/consultation"
45
45
  end
46
46
 
47
- # PUT /admin/initiatives/:id
47
+ # PUT /admin/consultations/:slug
48
48
  def update
49
49
  enforce_permission_to :update, :consultation, consultation: current_consultation
50
50
 
@@ -64,6 +64,12 @@ module Decidim
64
64
  end
65
65
  end
66
66
 
67
+ # GET /admin/consultations/:slug/results
68
+ def results
69
+ enforce_permission_to :read, :consultation, consultation: current_consultation
70
+ render layout: "decidim/admin/consultation"
71
+ end
72
+
67
73
  private
68
74
 
69
75
  def current_consultation
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Consultations
5
+ module Admin
6
+ class QuestionConfigurationController < Decidim::Consultations::Admin::ApplicationController
7
+ include QuestionAdmin
8
+
9
+ before_action :check_external_voting
10
+
11
+ def edit
12
+ enforce_permission_to :configure, :question, question: current_question
13
+ @form = question_form.from_model(current_question, current_consultation: current_consultation)
14
+ render layout: "decidim/admin/question"
15
+ end
16
+
17
+ def update
18
+ enforce_permission_to :configure, :question, question: current_question
19
+
20
+ @form = question_form
21
+ .from_params(params, question_id: current_question.id, current_consultation: current_consultation)
22
+
23
+ UpdateQuestionConfiguration.call(current_question, @form) do
24
+ on(:ok) do |question|
25
+ flash[:notice] = I18n.t("questions.update.success", scope: "decidim.admin")
26
+ redirect_to edit_question_configuration_path(question)
27
+ end
28
+
29
+ on(:invalid) do |_question, error|
30
+ flash[:error] = I18n.t("questions.update.error", scope: "decidim.admin")
31
+ flash[:error] << " (#{error})" if error
32
+ render :edit, layout: "decidim/admin/question"
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def question_form
40
+ form(QuestionConfigurationForm)
41
+ end
42
+
43
+ # This is checked here (and not in permissions) to warn the user
44
+ # specifically about disabling external voting before using multivote questions
45
+ def check_external_voting
46
+ return unless current_question.external_voting
47
+
48
+ flash[:alert] = I18n.t("question_configuration.disable_external_voting", scope: "decidim.admin")
49
+ redirect_to edit_question_path(current_question)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end