decidim-participatory_processes 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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -15
  3. data/app/commands/decidim/participatory_processes/admin/activate_participatory_process_step.rb +1 -1
  4. data/app/commands/decidim/participatory_processes/admin/update_participatory_process_step.rb +1 -1
  5. data/app/controllers/decidim/participatory_processes/admin/participatory_processes_controller.rb +0 -9
  6. data/app/controllers/decidim/participatory_processes/participatory_processes_controller.rb +14 -6
  7. data/app/events/decidim/participatory_process_step_activated_event.rb +23 -0
  8. data/app/events/decidim/participatory_process_step_changed_event.rb +23 -0
  9. data/app/models/decidim/participatory_process.rb +16 -4
  10. data/app/models/decidim/participatory_process_step.rb +2 -2
  11. data/app/permissions/decidim/participatory_processes/permissions.rb +7 -12
  12. data/app/presenters/decidim/participatory_processes/participatory_process_metric_charts_presenter.rb +83 -0
  13. data/app/queries/decidim/participatory_processes/metrics/participatory_process_followers_metric_measure.rb +31 -0
  14. data/app/queries/decidim/participatory_processes/visible_participatory_processes.rb +1 -0
  15. data/app/types/decidim/participatory_processes/participatory_process_type.rb +32 -0
  16. data/app/views/decidim/participatory_processes/admin/participatory_processes/edit.html.erb +0 -4
  17. data/app/views/decidim/participatory_processes/participatory_processes/_metrics.html.erb +10 -0
  18. data/app/views/decidim/participatory_processes/participatory_processes/_statistics.html.erb +1 -1
  19. data/app/views/decidim/participatory_processes/participatory_processes/index.html.erb +2 -3
  20. data/app/views/decidim/participatory_processes/participatory_processes/show.html.erb +4 -1
  21. data/app/views/decidim/participatory_processes/participatory_processes/statistics.html.erb +9 -0
  22. data/app/views/layouts/decidim/_process_header.html.erb +8 -45
  23. data/app/views/layouts/decidim/_process_header_steps.html.erb +18 -22
  24. data/app/views/layouts/decidim/_process_navigation.html.erb +20 -0
  25. data/app/views/layouts/decidim/participatory_process.html.erb +1 -1
  26. data/config/locales/ca.yml +9 -5
  27. data/config/locales/de.yml +9 -5
  28. data/config/locales/en.yml +9 -5
  29. data/config/locales/es-PY.yml +9 -5
  30. data/config/locales/es.yml +9 -5
  31. data/config/locales/eu.yml +9 -5
  32. data/config/locales/fi-pl.yml +9 -5
  33. data/config/locales/fi.yml +9 -5
  34. data/config/locales/fr.yml +9 -5
  35. data/config/locales/gl.yml +9 -5
  36. data/config/locales/hu.yml +9 -5
  37. data/config/locales/id-ID.yml +9 -5
  38. data/config/locales/it.yml +9 -5
  39. data/config/locales/nl.yml +9 -5
  40. data/config/locales/pl.yml +9 -5
  41. data/config/locales/pt-BR.yml +9 -5
  42. data/config/locales/pt.yml +9 -5
  43. data/config/locales/ru.yml +2 -5
  44. data/config/locales/sv.yml +9 -5
  45. data/config/locales/tr-TR.yml +9 -5
  46. data/config/locales/uk.yml +2 -5
  47. data/lib/decidim/participatory_processes/admin_engine.rb +1 -1
  48. data/lib/decidim/participatory_processes/engine.rb +18 -11
  49. data/lib/decidim/participatory_processes/test/factories.rb +11 -0
  50. data/lib/decidim/participatory_processes/version.rb +1 -1
  51. metadata +16 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a8db0c2f1ef72dc0bed95c83b5a6305de106ff0eee4cca89dca3a5f10d9cebe
4
- data.tar.gz: 4d092227cc5c8f230d992ac25245eefbb5453128b0316d85e4c4490917980c3e
3
+ metadata.gz: dcc7482dcc0d05dd5b2736b409fe3c21cac93daa281b3742e3aac4b84af0e8b7
4
+ data.tar.gz: 25445b48ad99ad7b91ad4dd96107c74435499f80ac0cdb9dada9d0b6cbe54e1c
5
5
  SHA512:
6
- metadata.gz: 843e3216dff264fe2cf9439d3573de4407e0a3259fb3c5aaa4c6422542380fe8fdfa39a24e3831f64b74bcea8c866d450e4a401e2e4d330b662840ae01aa8d02
7
- data.tar.gz: 0451b42520e1216e11c9a111cff97b7d4b4c3757ff17f15c4a339b658b546831ebaedc364934b7fa8a49941060cb34d83c80ed026656248420c226ce146fb14c
6
+ metadata.gz: 1a2f754d7e05d3ad0c1daca4681d5e927cf4620661be5e6b57c7cfe695b37d402876a8ab39719fe270365030c107d6dff5057295db977b9e4b0ad940ccfe5a01
7
+ data.tar.gz: f4770fbfa28e7f8598bef52e10cb6685b8aaeddfc8037f1e28b929f16a039e62a907a4e573af87832254e748a85c2f536dbe0debde4a9803c440fa0086482edc
data/README.md CHANGED
@@ -2,11 +2,18 @@
2
2
 
3
3
  Participatory processes are the standard Decidim's participatory space.
4
4
 
5
- A participatory process can define its own steps, and attach different components
6
- (such as meetings or proposals) with different configurations to each of them.
7
-
8
- A participatory process can have attachments, be associated to custom
9
- categories, and are fully manageable via an administration UI.
5
+ A participatory process:
6
+
7
+ * can define its own steps
8
+ * can define helper text
9
+ * can attach different components (such as meetings or proposals) with different configurations to each of them.
10
+ * can have attachments
11
+ * can be associated to custom categories
12
+ * can be promoted
13
+ * can be a private process, and only users with permissions can see the process
14
+ * special content can be added to the process or superprocess home
15
+ * can show statistics on process home.
16
+ * are fully manageable via an administration UI.
10
17
 
11
18
  ## Usage
12
19
 
@@ -14,22 +21,21 @@ This module provides:
14
21
 
15
22
  * A CRUD engine to manage participatory processes.
16
23
 
17
- * Public views for participatory process via a high level section in the main
18
- menu.
24
+ * Public views for participatory process via a high level section in the main menu.
19
25
 
20
26
  ## Installation
21
27
 
22
- Add this line to your application's Gemfile:
28
+ This is on the default Decidim installation so you shouldn't change anything to use this participatory space.
29
+
30
+ ## Screenshots
31
+
32
+ ![Public View](docs/screenshot01.png)
23
33
 
24
- ```ruby
25
- gem 'decidim-participatory_processes'
26
- ```
34
+ ![Admin View](docs/screenshot02.png)
27
35
 
28
- And then execute:
36
+ ## Documentation
29
37
 
30
- ```bash
31
- bundle
32
- ```
38
+ Read more about this Space on [Admin Manual](https://docs.decidim.org/admin-manual/en/processess/).
33
39
 
34
40
  ## Contributing
35
41
 
@@ -60,7 +60,7 @@ module Decidim
60
60
  event: "decidim.events.participatory_process.step_activated",
61
61
  event_class: Decidim::ParticipatoryProcessStepActivatedEvent,
62
62
  resource: step,
63
- recipient_ids: step.participatory_process.followers.pluck(:id)
63
+ followers: step.participatory_process.followers
64
64
  )
65
65
  end
66
66
 
@@ -60,7 +60,7 @@ module Decidim
60
60
  event: "decidim.events.participatory_process.step_changed",
61
61
  event_class: Decidim::ParticipatoryProcessStepChangedEvent,
62
62
  resource: step,
63
- recipient_ids: step.participatory_process.followers.pluck(:id)
63
+ followers: step.participatory_process.followers
64
64
  )
65
65
  end
66
66
  end
@@ -68,15 +68,6 @@ module Decidim
68
68
  end
69
69
  end
70
70
 
71
- def destroy
72
- enforce_permission_to :destroy, :process, process: current_participatory_process
73
- current_participatory_process.destroy!
74
-
75
- flash[:notice] = I18n.t("participatory_processes.destroy.success", scope: "decidim.admin")
76
-
77
- redirect_to participatory_processes_path
78
- end
79
-
80
71
  def copy
81
72
  enforce_permission_to :create, Decidim::ParticipatoryProcess
82
73
  end
@@ -6,7 +6,7 @@ module Decidim
6
6
  # public layout.
7
7
  class ParticipatoryProcessesController < Decidim::ParticipatoryProcesses::ApplicationController
8
8
  include ParticipatorySpaceContext
9
- participatory_space_layout only: :show
9
+ participatory_space_layout only: [:show, :statistics]
10
10
 
11
11
  helper Decidim::AttachmentsHelper
12
12
  helper Decidim::IconHelper
@@ -16,7 +16,7 @@ module Decidim
16
16
 
17
17
  helper ParticipatoryProcessHelper
18
18
 
19
- helper_method :collection, :promoted_participatory_processes, :participatory_processes, :stats, :filter
19
+ helper_method :collection, :promoted_participatory_processes, :participatory_processes, :stats, :metrics, :filter
20
20
  helper_method :process_count_by_filter
21
21
 
22
22
  def index
@@ -27,7 +27,11 @@ module Decidim
27
27
  end
28
28
 
29
29
  def show
30
- check_current_user_can_visit_space
30
+ enforce_permission_to :read, :process, process: current_participatory_space
31
+ end
32
+
33
+ def statistics
34
+ enforce_permission_to :read, :process, process: current_participatory_space
31
35
  end
32
36
 
33
37
  private
@@ -57,11 +61,11 @@ module Decidim
57
61
  end
58
62
 
59
63
  def participatory_processes
60
- @participatory_processes ||= filtered_participatory_processes(filter)
64
+ @participatory_processes ||= filtered_participatory_processes(filter).query.where(decidim_participatory_process_group_id: nil)
61
65
  end
62
66
 
63
67
  def promoted_participatory_processes
64
- @promoted_participatory_processes ||= filtered_participatory_processes | PromotedParticipatoryProcesses.new
68
+ @promoted_participatory_processes ||= filtered_participatory_processes("all") | PromotedParticipatoryProcesses.new
65
69
  end
66
70
 
67
71
  def filtered_participatory_process_groups(filter_name = filter)
@@ -76,6 +80,10 @@ module Decidim
76
80
  @stats ||= ParticipatoryProcessStatsPresenter.new(participatory_process: current_participatory_space)
77
81
  end
78
82
 
83
+ def metrics
84
+ @metrics ||= ParticipatoryProcessMetricChartsPresenter.new(participatory_process: current_participatory_space)
85
+ end
86
+
79
87
  def filter
80
88
  @filter = params[:filter] || default_filter
81
89
  end
@@ -91,7 +99,7 @@ module Decidim
91
99
  return @process_count_by_filter if @process_count_by_filter
92
100
 
93
101
  @process_count_by_filter = %w(active upcoming past).inject({}) do |collection_by_filter, filter_name|
94
- processes = filtered_participatory_processes(filter_name)
102
+ processes = filtered_participatory_processes(filter_name).query.where(decidim_participatory_process_group_id: nil)
95
103
  groups = filtered_participatory_process_groups(filter_name)
96
104
  collection_by_filter.merge(filter_name.to_s => processes.count + groups.count)
97
105
  end
@@ -0,0 +1,23 @@
1
+ # frozen-string_literal: true
2
+
3
+ module Decidim
4
+ class ParticipatoryProcessStepActivatedEvent < Decidim::Events::SimpleEvent
5
+ include Rails.application.routes.mounted_helpers
6
+
7
+ def resource_path
8
+ @resource_path ||= decidim_participatory_processes.participatory_process_participatory_process_steps_path(participatory_process_slug: participatory_space.slug)
9
+ end
10
+
11
+ def resource_url
12
+ @resource_url ||= decidim_participatory_processes
13
+ .participatory_process_participatory_process_steps_url(
14
+ participatory_process_slug: participatory_space.slug,
15
+ host: participatory_space.organization.host
16
+ )
17
+ end
18
+
19
+ def participatory_space
20
+ resource.participatory_process
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen-string_literal: true
2
+
3
+ module Decidim
4
+ class ParticipatoryProcessStepChangedEvent < Decidim::Events::SimpleEvent
5
+ include Rails.application.routes.mounted_helpers
6
+
7
+ def resource_path
8
+ @resource_path ||= decidim_participatory_processes.participatory_process_participatory_process_steps_path(participatory_process_slug: participatory_space.slug)
9
+ end
10
+
11
+ def resource_url
12
+ @resource_url ||= decidim_participatory_processes
13
+ .participatory_process_participatory_process_steps_url(
14
+ participatory_process_slug: participatory_space.slug,
15
+ host: participatory_space.organization.host
16
+ )
17
+ end
18
+
19
+ def participatory_space
20
+ resource.participatory_process
21
+ end
22
+ end
23
+ end
@@ -66,6 +66,22 @@ module Decidim
66
66
  where(promoted: true)
67
67
  end
68
68
 
69
+ def self.private_processes
70
+ where(private_space: true)
71
+ end
72
+
73
+ def self.active_spaces
74
+ active
75
+ end
76
+
77
+ def self.future_spaces
78
+ upcoming
79
+ end
80
+
81
+ def self.past_spaces
82
+ past
83
+ end
84
+
69
85
  def self.log_presenter_class_for(_log)
70
86
  Decidim::ParticipatoryProcesses::AdminLog::ParticipatoryProcessPresenter
71
87
  end
@@ -83,10 +99,6 @@ module Decidim
83
99
  slug
84
100
  end
85
101
 
86
- def self.private_processes
87
- where(private_space: true)
88
- end
89
-
90
102
  def can_participate?(user)
91
103
  return true unless private_space?
92
104
  return true if private_space? && users.include?(user)
@@ -21,7 +21,7 @@ module Decidim
21
21
  validates :position, numericality: { greater_than_or_equal_to: 0, only_integer: true }, allow_blank: true
22
22
  validates :position, uniqueness: { scope: :decidim_participatory_process_id }
23
23
 
24
- before_create :set_position
24
+ before_validation :set_position, on: :create
25
25
 
26
26
  def self.log_presenter_class_for(_log)
27
27
  Decidim::ParticipatoryProcesses::AdminLog::StepPresenter
@@ -42,7 +42,7 @@ module Decidim
42
42
  return if position.present?
43
43
  return self.position = 0 if participatory_process.steps.select(&:persisted?).empty?
44
44
 
45
- self.position = participatory_process.steps.pluck(:position).last + 1
45
+ self.position = participatory_process.steps.maximum(:position) + 1
46
46
  end
47
47
  end
48
48
  end
@@ -35,7 +35,6 @@ module Decidim
35
35
  user_can_read_process_list?
36
36
  user_can_read_current_process?
37
37
  user_can_create_process?
38
- user_can_destroy_process?
39
38
 
40
39
  # org admins and space admins can do everything in the admin section
41
40
  org_admin_action?
@@ -102,11 +101,17 @@ module Decidim
102
101
  [:process, :participatory_space].include?(permission_action.subject) &&
103
102
  process
104
103
 
104
+ return disallow! if cannot_view_private_space
105
105
  return allow! if user&.admin?
106
106
  return allow! if process.published?
107
107
  toggle_allow(can_manage_process?)
108
108
  end
109
109
 
110
+ def cannot_view_private_space
111
+ return unless process.private_space
112
+ !user || !user.admin && !process.users.include?(user)
113
+ end
114
+
110
115
  def public_report_content_action?
111
116
  return unless permission_action.action == :create &&
112
117
  permission_action.subject == :moderation
@@ -164,14 +169,6 @@ module Decidim
164
169
  toggle_allow(user.admin?)
165
170
  end
166
171
 
167
- # Only organization admins can destroy a process
168
- def user_can_destroy_process?
169
- return unless permission_action.action == :destroy &&
170
- permission_action.subject == :process
171
-
172
- toggle_allow(user.admin?)
173
- end
174
-
175
172
  # Everyone can read the process list
176
173
  def user_can_read_process_list?
177
174
  return unless read_process_list_permission_action?
@@ -201,14 +198,12 @@ module Decidim
201
198
 
202
199
  # Process admins can eprform everything *inside* that process. They cannot
203
200
  # create a process or perform actions on process groups or other
204
- # processes. They cannot destroy their process either.
201
+ # processes.
205
202
  def process_admin_action?
206
203
  return unless can_manage_process?(role: :admin)
207
204
  return if user.admin?
208
205
  return disallow! if permission_action.action == :create &&
209
206
  permission_action.subject == :process
210
- return disallow! if permission_action.action == :destroy &&
211
- permission_action.subject == :process
212
207
 
213
208
  is_allowed = [
214
209
  :attachment,
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ParticipatoryProcesses
5
+ # A presenter to render metrics in ParticipatoryProcesses statistics page
6
+ class ParticipatoryProcessMetricChartsPresenter < Decidim::MetricChartsPresenter
7
+ attribute :participatory_process, Decidim::ParticipatoryProcess
8
+
9
+ def params
10
+ capture do
11
+ concat(content_tag(:input, nil, type: :hidden, id: :"metrics-space_type", value: participatory_process.class))
12
+ concat(content_tag(:input, nil, type: :hidden, id: :"metrics-space_id", value: participatory_process.id))
13
+ end
14
+ end
15
+
16
+ def highlighted
17
+ render_highlighted(Decidim.metrics_registry.filtered(highlight: true, scope: "participatory_process"))
18
+ end
19
+
20
+ def not_highlighted
21
+ render_not_highlighted(Decidim.metrics_registry.filtered(highlight: false, scope: "participatory_process"))
22
+ end
23
+
24
+ def big_stats
25
+ safe_join(
26
+ Decidim.metrics_registry.filtered(scope: "participatory_process", block: "big", sort: true).map do |metric_manifest|
27
+ content_tag :div, class: "row" do
28
+ render_metrics_descriptive(metric_manifest.metric_name,
29
+ klass: "column",
30
+ graph_klass: "small",
31
+ title: I18n.t("decidim.metrics.#{metric_manifest.metric_name}.title"),
32
+ description: I18n.t("decidim.metrics.#{metric_manifest.metric_name}.description"),
33
+ download: true,
34
+ data: { ratio: "11:4", axis: true })
35
+ end
36
+ end
37
+ )
38
+ end
39
+
40
+ def medium_stats
41
+ safe_join(
42
+ Decidim.metrics_registry.filtered(scope: "participatory_process", block: "medium", sort: true).in_groups_of(2).map do |metrics_group|
43
+ content_tag :div, class: "row" do
44
+ safe_join(
45
+ metrics_group.map do |metric_manifest|
46
+ next "" if metric_manifest.blank?
47
+ render_metrics_descriptive(metric_manifest.metric_name,
48
+ klass: "column medium-6",
49
+ graph_klass: "small",
50
+ title: I18n.t("decidim.metrics.#{metric_manifest.metric_name}.title"),
51
+ description: I18n.t("decidim.metrics.#{metric_manifest.metric_name}.description"),
52
+ download: true,
53
+ data: { ratio: "16:9", axis: true })
54
+ end
55
+ )
56
+ end
57
+ end
58
+ )
59
+ end
60
+
61
+ def small_stats
62
+ safe_join(
63
+ Decidim.metrics_registry.filtered(scope: "participatory_process", block: "small", sort: true).in_groups_of(3).map do |metrics_group|
64
+ content_tag :div, class: "row" do
65
+ safe_join(
66
+ metrics_group.map do |metric_manifest|
67
+ next "" if metric_manifest.blank?
68
+ render_metrics_data(metric_manifest.metric_name,
69
+ klass: "column medium-4",
70
+ ratio: "16:9",
71
+ margin: "margin-top: 30px",
72
+ graph_klass: "small",
73
+ download: true,
74
+ data: { ratio: "16:9" })
75
+ end
76
+ )
77
+ end
78
+ end
79
+ )
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ParticipatoryProcesses
5
+ module Metrics
6
+ # Searches for unique Users following the next objects
7
+ # - ParticipatoryProcesses
8
+ class ParticipatoryProcessFollowersMetricMeasure < Decidim::MetricMeasure
9
+ def valid?
10
+ super && @resource.is_a?(Decidim::Participable)
11
+ end
12
+
13
+ def calculate
14
+ participatory_process = @resource
15
+
16
+ process_followers = Decidim::Follow.where(followable: participatory_process).joins(:user)
17
+ .where("decidim_follows.created_at <= ?", end_time)
18
+ cumulative_users = process_followers.pluck(:decidim_user_id)
19
+
20
+ process_followers = process_followers.where("decidim_follows.created_at >= ?", start_time)
21
+ quantity_users = process_followers.pluck(:decidim_user_id)
22
+
23
+ {
24
+ cumulative_users: cumulative_users.uniq,
25
+ quantity_users: quantity_users.uniq
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -12,6 +12,7 @@ module Decidim
12
12
  processes = Decidim::ParticipatoryProcess.all
13
13
 
14
14
  if @current_user
15
+ return processes if @current_user.admin
15
16
  processes.visible_for(@current_user.id)
16
17
  else
17
18
  processes.public_spaces