decidim-consultations 0.11.2 → 0.12.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/decidim_consultations_manifest.css +4 -0
  3. data/app/assets/stylesheets/decidim/consultations/consultations.scss +0 -1
  4. data/app/cells/decidim/consultations/consultation_cell.rb +19 -0
  5. data/app/cells/decidim/consultations/consultation_m/data.erb +21 -0
  6. data/app/cells/decidim/consultations/consultation_m/footer.erb +5 -0
  7. data/app/cells/decidim/consultations/consultation_m_cell.rb +94 -0
  8. data/app/commands/decidim/consultations/admin/update_consultation.rb +2 -1
  9. data/app/controllers/concerns/decidim/consultations/action_authorization.rb +2 -2
  10. data/app/controllers/concerns/decidim/consultations/admin/consultation_admin.rb +7 -0
  11. data/app/controllers/concerns/decidim/consultations/admin/question_admin.rb +7 -0
  12. data/app/controllers/concerns/decidim/consultations/needs_consultation.rb +0 -4
  13. data/app/controllers/concerns/decidim/consultations/needs_question.rb +0 -7
  14. data/app/controllers/decidim/consultations/admin/application_controller.rb +15 -0
  15. data/app/controllers/decidim/consultations/admin/consultation_publications_controller.rb +3 -3
  16. data/app/controllers/decidim/consultations/admin/consultation_results_publications_controller.rb +3 -3
  17. data/app/controllers/decidim/consultations/admin/consultations_controller.rb +6 -10
  18. data/app/controllers/decidim/consultations/admin/question_attachments_controller.rb +1 -1
  19. data/app/controllers/decidim/consultations/admin/question_publications_controller.rb +3 -3
  20. data/app/controllers/decidim/consultations/admin/questions_controller.rb +6 -10
  21. data/app/controllers/decidim/consultations/admin/responses_controller.rb +7 -7
  22. data/app/controllers/decidim/consultations/application_controller.rb +25 -0
  23. data/app/controllers/decidim/consultations/consultations_controller.rb +3 -17
  24. data/app/controllers/decidim/consultations/question_votes_controller.rb +3 -3
  25. data/app/controllers/decidim/consultations/questions_controller.rb +2 -2
  26. data/app/forms/decidim/consultations/admin/consultation_form.rb +1 -0
  27. data/app/models/decidim/consultation.rb +4 -3
  28. data/app/models/decidim/consultations/question.rb +22 -1
  29. data/app/permissions/decidim/consultations/admin/permissions.rb +108 -0
  30. data/app/permissions/decidim/consultations/permissions.rb +55 -0
  31. data/app/views/decidim/consultations/admin/consultations/edit.html.erb +4 -4
  32. data/app/views/decidim/consultations/admin/consultations/index.html.erb +5 -5
  33. data/app/views/decidim/consultations/admin/questions/edit.html.erb +2 -2
  34. data/app/views/decidim/consultations/admin/questions/index.html.erb +5 -5
  35. data/app/views/decidim/consultations/admin/responses/edit.html.erb +1 -1
  36. data/app/views/decidim/consultations/admin/responses/index.html.erb +3 -3
  37. data/app/views/decidim/consultations/consultation_widgets/show.html.erb +0 -2
  38. data/app/views/decidim/consultations/consultations/_consultations.html.erb +1 -1
  39. data/app/views/decidim/consultations/consultations/_regular_questions.html.erb +2 -2
  40. data/app/views/decidim/consultations/consultations/show.html.erb +0 -8
  41. data/app/views/decidim/consultations/question_votes/update_vote_button.js.erb +3 -0
  42. data/app/views/decidim/consultations/questions/_vote_button.html.erb +15 -28
  43. data/app/views/decidim/consultations/questions/_vote_modal.html.erb +1 -1
  44. data/app/views/decidim/consultations/questions/_vote_modal_confirm.html.erb +1 -1
  45. data/app/views/layouts/decidim/_question_components.html.erb +3 -2
  46. data/app/views/layouts/decidim/admin/consultation.html.erb +7 -4
  47. data/app/views/layouts/decidim/admin/consultations.html.erb +16 -10
  48. data/app/views/layouts/decidim/admin/question.html.erb +11 -8
  49. data/app/views/layouts/decidim/consultation.html.erb +0 -2
  50. data/app/views/layouts/decidim/consultation_choose.html.erb +0 -2
  51. data/app/views/layouts/decidim/question.html.erb +0 -1
  52. data/config/locales/ca.yml +33 -11
  53. data/config/locales/en.yml +33 -11
  54. data/config/locales/es.yml +33 -11
  55. data/config/locales/eu.yml +33 -11
  56. data/config/locales/fi.yml +33 -11
  57. data/config/locales/fr.yml +33 -11
  58. data/config/locales/gl.yml +33 -11
  59. data/config/locales/it.yml +33 -11
  60. data/config/locales/nl.yml +33 -11
  61. data/config/locales/pl.yml +41 -11
  62. data/config/locales/pt-BR.yml +33 -11
  63. data/config/locales/pt.yml +33 -11
  64. data/config/locales/ru.yml +1 -3
  65. data/config/locales/sv.yml +33 -11
  66. data/config/locales/uk.yml +41 -11
  67. data/lib/decidim/consultations/admin_engine.rb +1 -11
  68. data/lib/decidim/consultations/engine.rb +6 -11
  69. data/lib/decidim/consultations/participatory_space.rb +64 -105
  70. data/lib/decidim/consultations/version.rb +1 -1
  71. metadata +20 -19
  72. data/app/assets/config/decidim_consultations_manifest.scss +0 -3
  73. data/app/models/decidim/consultations/abilities/admin/consultation_admin_ability.rb +0 -34
  74. data/app/models/decidim/consultations/abilities/admin/question_admin_ability.rb +0 -30
  75. data/app/models/decidim/consultations/abilities/admin/response_admin_ability.rb +0 -26
  76. data/app/models/decidim/consultations/abilities/current_user_ability.rb +0 -45
  77. data/app/models/decidim/consultations/abilities/everyone_ability.rb +0 -23
  78. data/app/views/decidim/consultations/consultations/finished.html.erb +0 -15
@@ -4,22 +4,22 @@ module Decidim
4
4
  module Consultations
5
5
  module Admin
6
6
  # Controller that manages responses for a question
7
- class ResponsesController < Decidim::Admin::ApplicationController
7
+ class ResponsesController < Decidim::Consultations::Admin::ApplicationController
8
8
  include QuestionAdmin
9
9
 
10
10
  helper_method :current_response
11
11
 
12
12
  def index
13
- authorize! :index, Decidim::Consultations::Response
13
+ enforce_permission_to :read, :response
14
14
  end
15
15
 
16
16
  def new
17
- authorize! :create, Decidim::Consultations::Response
17
+ enforce_permission_to :create, :response
18
18
  @form = response_form.instance
19
19
  end
20
20
 
21
21
  def create
22
- authorize! :create, Decidim::Consultations::Response
22
+ enforce_permission_to :create, :response
23
23
  @form = response_form.from_params(params, current_question: current_question)
24
24
 
25
25
  CreateResponse.call(@form) do
@@ -36,12 +36,12 @@ module Decidim
36
36
  end
37
37
 
38
38
  def edit
39
- authorize! :update, current_response
39
+ enforce_permission_to :update, :response, response: current_response
40
40
  @form = response_form.from_model(current_response, current_question: current_question)
41
41
  end
42
42
 
43
43
  def update
44
- authorize! :update, current_response
44
+ enforce_permission_to :update, :response, response: current_response
45
45
 
46
46
  @form = response_form.from_params(params, current_question: current_question)
47
47
  UpdateResponse.call(current_response, @form) do
@@ -58,7 +58,7 @@ module Decidim
58
58
  end
59
59
 
60
60
  def destroy
61
- authorize! :destroy, current_response
61
+ enforce_permission_to :destroy, :response, response: current_response
62
62
 
63
63
  current_response.destroy
64
64
  if current_response.valid?
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Consultations
5
+ # A controller that holds the logic to show consultations in a
6
+ # public layout.
7
+ class ApplicationController < Decidim::ApplicationController
8
+ include NeedsPermission
9
+
10
+ private
11
+
12
+ def permission_class_chain
13
+ [
14
+ Decidim::Consultations::Permissions,
15
+ Decidim::Admin::Permissions,
16
+ Decidim::Permissions
17
+ ]
18
+ end
19
+
20
+ def permission_scope
21
+ :public
22
+ end
23
+ end
24
+ end
25
+ end
@@ -4,7 +4,7 @@ module Decidim
4
4
  module Consultations
5
5
  # A controller that holds the logic to show consultations in a
6
6
  # public layout.
7
- class ConsultationsController < Decidim::ApplicationController
7
+ class ConsultationsController < Decidim::Consultations::ApplicationController
8
8
  layout "layouts/decidim/consultation", only: :show
9
9
 
10
10
  include NeedsConsultation
@@ -22,29 +22,15 @@ module Decidim
22
22
  helper Decidim::WidgetUrlsHelper
23
23
 
24
24
  def index
25
- authorize! :read, Consultation
26
- redirect_to consultation_path(active_consultations.first) if active_consultations.count == 1
25
+ enforce_permission_to :read, :consultation_list
27
26
  end
28
27
 
29
28
  def show
30
- authorize! :read, current_consultation
31
- end
32
-
33
- def finished
34
- authorize! :read, Consultation
35
- render layout: "layouts/decidim/consultation_choose"
29
+ enforce_permission_to :read, :consultation, consultation: current_consultation
36
30
  end
37
31
 
38
32
  private
39
33
 
40
- def finished_consultations
41
- @finished_consultations ||= OrganizationConsultations.for(current_organization).finished.published
42
- end
43
-
44
- def active_consultations
45
- @active_consultations ||= OrganizationConsultations.for(current_organization).active.published
46
- end
47
-
48
34
  def consultations
49
35
  @consultations = search.results
50
36
  @consultations = reorder(@consultations)
@@ -2,14 +2,14 @@
2
2
 
3
3
  module Decidim
4
4
  module Consultations
5
- class QuestionVotesController < Decidim::ApplicationController
5
+ class QuestionVotesController < Decidim::Consultations::ApplicationController
6
6
  include NeedsQuestion
7
7
  include Decidim::FormFactory
8
8
 
9
9
  before_action :authenticate_user!
10
10
 
11
11
  def create
12
- authorize! :vote, current_question
12
+ enforce_permission_to :vote, :question, question: current_question
13
13
 
14
14
  vote_form = form(VoteForm).from_params(params, current_question: current_question)
15
15
  VoteQuestion.call(vote_form) do
@@ -27,7 +27,7 @@ module Decidim
27
27
  end
28
28
 
29
29
  def destroy
30
- authorize! :unvote, current_question
30
+ enforce_permission_to :unvote, :question, question: current_question
31
31
  UnvoteQuestion.call(current_question, current_user) do
32
32
  on(:ok) do
33
33
  current_question.reload
@@ -4,7 +4,7 @@ module Decidim
4
4
  module Consultations
5
5
  # A controller that holds the logic to show questions in a
6
6
  # public layout.
7
- class QuestionsController < Decidim::ApplicationController
7
+ class QuestionsController < Decidim::Consultations::ApplicationController
8
8
  layout "layouts/decidim/question"
9
9
 
10
10
  include NeedsQuestion
@@ -16,7 +16,7 @@ module Decidim
16
16
  helper Decidim::ResourceReferenceHelper
17
17
 
18
18
  def show
19
- authorize! :read, current_question
19
+ enforce_permission_to :read, :question, question: current_question
20
20
  end
21
21
  end
22
22
  end
@@ -17,6 +17,7 @@ module Decidim
17
17
  attribute :remove_banner_image
18
18
  attribute :introductory_video_url, String
19
19
  attribute :introductory_image, String
20
+ attribute :remove_introductory_image
20
21
  attribute :decidim_highlighted_scope_id, Integer
21
22
  attribute :start_voting_date, Date
22
23
  attribute :end_voting_date, Date
@@ -5,6 +5,7 @@ module Decidim
5
5
  class Consultation < ApplicationRecord
6
6
  include Decidim::Participable
7
7
  include Decidim::Publicable
8
+ include Decidim::Resourceable
8
9
  include Decidim::Consultations::PublicableResults
9
10
 
10
11
  belongs_to :organization,
@@ -56,8 +57,8 @@ module Decidim
56
57
  questions.published.where(decidim_scope_id: decidim_highlighted_scope_id)
57
58
  end
58
59
 
59
- def regular_questions
60
- questions.published.where.not(decidim_scope_id: decidim_highlighted_scope_id).group_by(&:scope)
60
+ def questions_by_scope
61
+ questions.published.group_by(&:scope)
61
62
  end
62
63
 
63
64
  # This method exists with the only purpose of getting rid of whats seems to be an issue in
@@ -72,7 +73,7 @@ module Decidim
72
73
  def self.order_randomly(seed)
73
74
  transaction do
74
75
  connection.execute("SELECT setseed(#{connection.quote(seed)})")
75
- select('"decidim_consultations".*, RANDOM()').order("RANDOM()").load
76
+ select('"decidim_consultations".*, RANDOM()').order(Arel.sql("RANDOM()")).load
76
77
  end
77
78
  end
78
79
  end
@@ -87,6 +87,27 @@ module Decidim
87
87
  votes.where(author: user).any?
88
88
  end
89
89
 
90
+ # Public: Checks whether the given user can unvote the question or note.
91
+ #
92
+ # Returns a Boolean.
93
+ def can_be_unvoted_by?(user)
94
+ consultation.active? &&
95
+ consultation.published? &&
96
+ published? &&
97
+ voted_by?(user)
98
+ end
99
+
100
+ # Public: Checks whether the given user can vote the question or note.
101
+ #
102
+ # Returns a Boolean.
103
+ def can_be_voted_by?(user)
104
+ organization.id == user.organization.id &&
105
+ consultation.active? &&
106
+ consultation.published? &&
107
+ published? &&
108
+ !voted_by?(user)
109
+ end
110
+
90
111
  def scopes_enabled?
91
112
  false
92
113
  end
@@ -119,7 +140,7 @@ module Decidim
119
140
  def self.order_randomly(seed)
120
141
  transaction do
121
142
  connection.execute("SELECT setseed(#{connection.quote(seed)})")
122
- select('"decidim_consultations_questions".*, RANDOM()').order("RANDOM()").load
143
+ select('"decidim_consultations_questions".*, RANDOM()').order(Arel.sql("RANDOM()")).load
123
144
  end
124
145
  end
125
146
  end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Consultations
5
+ module Admin
6
+ class Permissions < Decidim::DefaultPermissions
7
+ def permissions
8
+ return permission_action unless user
9
+ return permission_action unless permission_action.scope == :admin
10
+ return permission_action if consultation && !consultation.is_a?(Decidim::Consultation)
11
+
12
+ unless user.admin?
13
+ disallow!
14
+ return permission_action
15
+ end
16
+
17
+ user_can_enter_space_area?
18
+
19
+ if read_admin_dashboard_action?
20
+ allow!
21
+ return permission_action
22
+ end
23
+
24
+ allowed_read_participatory_space?
25
+ allowed_consultation_action?
26
+ allowed_question_action?
27
+ allowed_response_action?
28
+
29
+ permission_action
30
+ end
31
+
32
+ private
33
+
34
+ def question
35
+ @question ||= context.fetch(:question, nil)
36
+ end
37
+
38
+ def consultation
39
+ @consultation ||= context.fetch(:consultation, nil) || context.fetch(:participatory_space, nil)
40
+ end
41
+
42
+ def response
43
+ @response ||= context.fetch(:response, nil)
44
+ end
45
+
46
+ def allowed_consultation_action?
47
+ return unless permission_action.subject == :consultation
48
+
49
+ case permission_action.action
50
+ when :create, :read, :publish
51
+ allow!
52
+ when :update, :destroy, :preview
53
+ toggle_allow(consultation.present?)
54
+ when :publish_results
55
+ toggle_allow(consultation.finished? && !consultation.results_published?)
56
+ when :unpublish_results
57
+ toggle_allow(consultation.results_published?)
58
+ end
59
+ end
60
+
61
+ def allowed_question_action?
62
+ return unless permission_action.subject == :question
63
+
64
+ case permission_action.action
65
+ when :create, :read
66
+ allow!
67
+ when :update, :destroy, :preview
68
+ toggle_allow(question.present?)
69
+ when :publish
70
+ toggle_allow(question.external_voting || question.responses_count.positive?)
71
+ end
72
+ end
73
+
74
+ def allowed_response_action?
75
+ return unless permission_action.subject == :response
76
+
77
+ case permission_action.action
78
+ when :create, :read
79
+ allow!
80
+ when :update, :destroy
81
+ toggle_allow(response.present?)
82
+ end
83
+ end
84
+
85
+ # Only admin users can enter the consultations area.
86
+ def user_can_enter_space_area?
87
+ return unless permission_action.action == :enter &&
88
+ permission_action.subject == :space_area &&
89
+ context.fetch(:space_name, nil) == :consultations
90
+
91
+ allow!
92
+ end
93
+
94
+ def read_admin_dashboard_action?
95
+ permission_action.action == :read &&
96
+ permission_action.subject == :admin_dashboard
97
+ end
98
+
99
+ def allowed_read_participatory_space?
100
+ return unless permission_action.action == :read &&
101
+ permission_action.subject == :participatory_space
102
+
103
+ allow!
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Consultations
5
+ class Permissions < Decidim::DefaultPermissions
6
+ def permissions
7
+ allowed_public_anonymous_action?
8
+
9
+ permission_action unless user
10
+ allowed_public_action?
11
+
12
+ permission_action unless permission_action.scope == :admin
13
+ return Decidim::Consultations::Admin::Permissions.new(user, permission_action, context).permissions if permission_action.scope == :admin
14
+
15
+ permission_action
16
+ end
17
+
18
+ private
19
+
20
+ def question
21
+ @question ||= context.fetch(:question, nil)
22
+ end
23
+
24
+ def consultation
25
+ @consultation ||= context.fetch(:consultation, nil)
26
+ end
27
+
28
+ def allowed_public_anonymous_action?
29
+ return unless permission_action.action == :read
30
+ return unless permission_action.scope == :public
31
+
32
+ case permission_action.subject
33
+ when :consultation_list
34
+ allow!
35
+ when :consultation
36
+ toggle_allow(consultation.published? || user&.admin?)
37
+ when :question
38
+ toggle_allow(question.published? || user&.admin?)
39
+ end
40
+ end
41
+
42
+ def allowed_public_action?
43
+ return unless permission_action.scope == :public
44
+ return unless permission_action.subject == :question
45
+
46
+ case permission_action.action
47
+ when :vote
48
+ toggle_allow(question.can_be_voted_by?(user))
49
+ when :unvote
50
+ toggle_allow(question.can_be_unvoted_by?(user))
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -3,7 +3,7 @@
3
3
  <div class="button--double form-general-submit">
4
4
  <%= f.submit t("consultations.edit.update", scope: "decidim.admin"), class: "button" %>
5
5
 
6
- <% if can? :publish, current_consultation %>
6
+ <% if allowed_to? :publish, :consultation, consultation: current_consultation %>
7
7
  <% if current_consultation.published? %>
8
8
  <%= link_to t("actions.unpublish", scope: "decidim.admin"),
9
9
  consultation_publish_path(current_consultation),
@@ -17,21 +17,21 @@
17
17
  <% end %>
18
18
  <% end %>
19
19
 
20
- <% if can? :publish_results, current_consultation %>
20
+ <% if allowed_to? :publish_results, :consultation, consultation: current_consultation %>
21
21
  <%= link_to t("actions.publish_results", scope: "decidim.admin"),
22
22
  consultation_publish_results_path(current_consultation),
23
23
  method: :post,
24
24
  class: "button hollow" %>
25
25
  <% end %>
26
26
 
27
- <% if can? :unpublish_results, current_consultation %>
27
+ <% if allowed_to? :unpublish_results, :consultation, consultation: current_consultation %>
28
28
  <%= link_to t("actions.unpublish_results", scope: "decidim.admin"),
29
29
  consultation_publish_results_path(current_consultation),
30
30
  method: :delete,
31
31
  class: "button muted" %>
32
32
  <% end %>
33
33
 
34
- <% if can? :destroy, current_consultation %>
34
+ <% if allowed_to? :destroy, :consultation, consultation: current_consultation %>
35
35
  <%= link_to t("decidim.admin.actions.destroy"),
36
36
  current_consultation,
37
37
  method: :delete,
@@ -3,7 +3,7 @@
3
3
  <h2 class="card-title">
4
4
  <%= t "decidim.admin.titles.consultations" %>
5
5
  <%= link_to t("actions.new", scope: "decidim.admin", name: t("models.consultation.name", scope: "decidim.admin")),
6
- ["new", "consultation"], class: "button tiny button--title" if can? :create, Decidim::Consultation %>
6
+ ["new", "consultation"], class: "button tiny button--title" if allowed_to? :create, :consultation %>
7
7
  </h2>
8
8
  </div>
9
9
  <div class="card-section">
@@ -23,10 +23,10 @@
23
23
  <% @consultations.each do |consultation| %>
24
24
  <tr>
25
25
  <td>
26
- <% if can? :update, consultation %>
26
+ <% if allowed_to? :update, :consultation, consultation: consultation %>
27
27
  <%= link_to translated_attribute(consultation.title), edit_consultation_path(consultation) %>
28
28
  <br />
29
- <% elsif can? :preview, consultation %>
29
+ <% elsif allowed_to? :preview, :consultation, consultation: consultation %>
30
30
  <%= link_to translated_attribute(consultation.title),
31
31
  decidim_consultations.consultation_path(consultation),
32
32
  target: "_blank" %>
@@ -50,14 +50,14 @@
50
50
  <% end %>
51
51
  </td>
52
52
  <td class="table-list__actions">
53
- <% if can? :update, consultation %>
53
+ <% if allowed_to? :update, :consultation, consultation: consultation %>
54
54
  <%= icon_link_to "pencil",
55
55
  edit_consultation_path(consultation),
56
56
  t("actions.configure", scope: "decidim.admin"),
57
57
  class: "action-icon--edit" %>
58
58
  <% end %>
59
59
 
60
- <% if can? :preview, consultation %>
60
+ <% if allowed_to? :preview, :consultation, consultation: consultation %>
61
61
  <%= icon_link_to "eye",
62
62
  decidim_consultations.consultation_path(consultation),
63
63
  t("actions.preview", scope: "decidim.admin"),