decidim-initiatives 0.20.1 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/decidim/initiatives/admin/filterable.rb +37 -0
  3. data/app/controllers/decidim/initiatives/admin/initiatives_controller.rb +6 -12
  4. data/app/models/decidim/initiative.rb +18 -1
  5. data/app/permissions/decidim/initiatives/admin/permissions.rb +10 -6
  6. data/app/queries/decidim/initiatives/admin/manageable_initiatives.rb +7 -39
  7. data/app/types/decidim/initiatives/initiative_api_type.rb +26 -0
  8. data/app/types/decidim/initiatives/initiative_committee_member_type.rb +18 -0
  9. data/app/types/decidim/initiatives/initiative_type.rb +42 -0
  10. data/app/views/decidim/initiatives/admin/initiatives/index.html.erb +3 -43
  11. data/config/locales/ar.yml +12 -10
  12. data/config/locales/ca.yml +12 -10
  13. data/config/locales/cs.yml +14 -12
  14. data/config/locales/de.yml +10 -10
  15. data/config/locales/el.yml +1 -0
  16. data/config/locales/en.yml +12 -10
  17. data/config/locales/es-MX.yml +12 -10
  18. data/config/locales/es-PY.yml +12 -10
  19. data/config/locales/es.yml +12 -10
  20. data/config/locales/eu.yml +10 -10
  21. data/config/locales/fi-plain.yml +12 -10
  22. data/config/locales/fi.yml +12 -10
  23. data/config/locales/fr.yml +10 -10
  24. data/config/locales/gl.yml +10 -10
  25. data/config/locales/hu.yml +12 -10
  26. data/config/locales/id-ID.yml +10 -10
  27. data/config/locales/is-IS.yml +10 -10
  28. data/config/locales/it.yml +12 -10
  29. data/config/locales/nl.yml +10 -10
  30. data/config/locales/no.yml +12 -10
  31. data/config/locales/pl.yml +10 -10
  32. data/config/locales/pt-BR.yml +10 -10
  33. data/config/locales/pt.yml +10 -10
  34. data/config/locales/ru.yml +10 -10
  35. data/config/locales/sv.yml +10 -10
  36. data/config/locales/tr-TR.yml +10 -10
  37. data/config/locales/uk.yml +10 -10
  38. data/lib/decidim/api/initiative_type_interface.rb +13 -0
  39. data/lib/decidim/initiatives/api.rb +7 -0
  40. data/lib/decidim/initiatives/engine.rb +8 -0
  41. data/lib/decidim/initiatives/participatory_space.rb +2 -0
  42. data/lib/decidim/initiatives/query_extensions.rb +40 -0
  43. data/lib/decidim/initiatives/version.rb +1 -1
  44. metadata +20 -13
  45. data/app/views/decidim/initiatives/initiative_widgets/show.html.erb +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f700127f2cd4317eebf36ebc437cd3bf9f8db1b887afcf7c42e18d7735f71c1
4
- data.tar.gz: aa39b6b6f75f465c331be6578b36d57a80dc486ed515d809889454ddcf2ad641
3
+ metadata.gz: bb3ddfb0265d59d3529b4855a3b5d195ae04616050f26d2baf9c621bfa165eb6
4
+ data.tar.gz: 4d16e5c1ae4cffa02b3077074bfc8f90ecf31b6a0a1dc6efac25549042dcc919
5
5
  SHA512:
6
- metadata.gz: 5b4bb552d1c3d8aa05eab47f94905f45adf32864d98e7ffbd725b75702fbce0eed8876cc3f9adc8096cb08d66c23d45c58aa8918d63b0ef032f11d67cbcf02ca
7
- data.tar.gz: 5d1c86ec5c714bd81a7186663756d501741fbfe88d54ff454aa11a44510d9f0ccb5f23dcaa0ac18f06d2ae5fcf6d4b14d070f11e47535d9b8c7a485dcfbc19ab
6
+ metadata.gz: 684b21bc414dec69621ae6291c9bb07012495a45c24bc035a0348c08b3478eb70fe587a9cb5f4c68c04c91d24e483850a324ef292d8c2303f10e0f0bb4558075
7
+ data.tar.gz: 7fb407da4a8752b56720500ba69f8d9c691d99821b0a13bfe273d2dda935ad6c68d44cee9439251743dde22b9ba940428dd62564aa086830d7d6d05030b240c6
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ module Initiatives
7
+ module Admin
8
+ module Filterable
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ include Decidim::Admin::Filterable
13
+
14
+ private
15
+
16
+ def base_query
17
+ collection
18
+ end
19
+
20
+ def search_field_predicate
21
+ :title_or_description_cont
22
+ end
23
+
24
+ def filters
25
+ [:state_eq]
26
+ end
27
+
28
+ def filters_with_values
29
+ {
30
+ state_eq: Initiative.states.keys
31
+ }
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -9,6 +9,7 @@ module Decidim
9
9
  class InitiativesController < Decidim::Initiatives::Admin::ApplicationController
10
10
  include Decidim::Initiatives::NeedsInitiative
11
11
  include Decidim::Initiatives::TypeSelectorOptions
12
+ include Decidim::Initiatives::Admin::Filterable
12
13
 
13
14
  helper Decidim::Initiatives::InitiativeHelper
14
15
  helper Decidim::Initiatives::CreateInitiativeHelper
@@ -16,18 +17,7 @@ module Decidim
16
17
  # GET /admin/initiatives
17
18
  def index
18
19
  enforce_permission_to :list, :initiative
19
-
20
- @query = params[:q]
21
- @state = params[:state]
22
- @initiatives = ManageableInitiatives
23
- .for(
24
- current_organization,
25
- current_user,
26
- @query,
27
- @state
28
- )
29
- .page(params[:page])
30
- .per(15)
20
+ @initiatives = filtered_collection
31
21
  end
32
22
 
33
23
  # GET /admin/initiatives/:id
@@ -165,6 +155,10 @@ module Decidim
165
155
 
166
156
  private
167
157
 
158
+ def collection
159
+ @collection ||= ManageableInitiatives.for(current_user)
160
+ end
161
+
168
162
  def pdf_signature_service
169
163
  @pdf_signature_service ||= Decidim.pdf_signature_service.to_s.safe_constantize
170
164
  end
@@ -68,7 +68,7 @@ module Decidim
68
68
 
69
69
  scope :open, lambda {
70
70
  published
71
- .where.not(state: [:discarded, :rejected, :accepted])
71
+ .where.not(state: [:discarded, :rejected, :accepted, :created])
72
72
  .where("signature_start_date <= ?", Date.current)
73
73
  .where("signature_end_date >= ?", Date.current)
74
74
  }
@@ -332,6 +332,13 @@ module Decidim
332
332
  organization.available_authorizations.include?("sms") && type.validate_sms_code_on_votes?
333
333
  end
334
334
 
335
+ # Public: Returns an empty object. This method should be implemented by
336
+ # `ParticipatorySpaceResourceable`, but for some reason this model does not
337
+ # implement this interface.
338
+ def user_role_config_for(_user, _role_name)
339
+ Decidim::ParticipatorySpaceRoleConfig::Base.new(:empty_role_name)
340
+ end
341
+
335
342
  private
336
343
 
337
344
  def signature_type_allowed
@@ -351,5 +358,15 @@ module Decidim
351
358
  notifier = Decidim::Initiatives::StatusChangeNotifier.new(initiative: self)
352
359
  notifier.notify
353
360
  end
361
+
362
+ # Allow ransacker to search for a key in a hstore column (`title`.`en`)
363
+ [:title, :description].each do |column|
364
+ ransacker column do |parent|
365
+ Arel::Nodes::InfixOperation.new("->>", parent.table[column], Arel::Nodes.build_quoted(I18n.locale.to_s))
366
+ end
367
+ end
368
+
369
+ # Allow ransacker to search on an Enum Field
370
+ ransacker :state, formatter: proc { |int| states[int] }
354
371
  end
355
372
  end
@@ -151,6 +151,8 @@ module Decidim
151
151
  initiative.signature_end_date < Date.current &&
152
152
  initiative.percentage < 100
153
153
  toggle_allow(allowed)
154
+ when :send_to_technical_validation
155
+ toggle_allow(allowed_to_send_to_technical_validation?)
154
156
  else
155
157
  allow!
156
158
  end
@@ -180,18 +182,20 @@ module Decidim
180
182
  when :update
181
183
  toggle_allow(initiative.created?)
182
184
  when :send_to_technical_validation
183
- allowed = initiative.created? && (
184
- !initiative.created_by_individual? ||
185
- initiative.enough_committee_members?
186
- )
187
-
188
- toggle_allow(allowed)
185
+ toggle_allow(allowed_to_send_to_technical_validation?)
189
186
  when :manage_membership
190
187
  toggle_allow(initiative.promoting_committee_enabled?)
191
188
  else
192
189
  disallow!
193
190
  end
194
191
  end
192
+
193
+ def allowed_to_send_to_technical_validation?
194
+ initiative.created? && (
195
+ !initiative.created_by_individual? ||
196
+ initiative.enough_committee_members?
197
+ )
198
+ end
195
199
  end
196
200
  end
197
201
  end
@@ -7,57 +7,25 @@ module Decidim
7
7
  # Regular users will get only their initiatives. Administrators will
8
8
  # retrieve all initiatives.
9
9
  class ManageableInitiatives < Rectify::Query
10
- attr_reader :organization, :user, :q, :state
11
-
12
10
  # Syntactic sugar to initialize the class and return the queried objects
13
11
  #
14
- # organization - Decidim::Organization
15
- # user - Decidim::User
16
- # query - String
17
- # state - String
18
- def self.for(organization, user, query, state)
19
- new(organization, user, query, state).query
12
+ # user - Decidim::User
13
+ def self.for(user)
14
+ new(user).query
20
15
  end
21
16
 
22
17
  # Initializes the class.
23
18
  #
24
- # organization - Decidim::Organization
25
- # user - Decidim::User
26
- # query - String
27
- # state - String
28
- def initialize(organization, user, query, state)
29
- @organization = organization
19
+ # user - Decidim::User
20
+ def initialize(user)
30
21
  @user = user
31
- @q = query
32
- @state = state
33
22
  end
34
23
 
35
24
  # Retrieves all initiatives / Initiatives created by the user.
36
25
  def query
37
- if user.admin?
38
- base = Initiative
39
- .where(organization: organization)
40
- .with_state(state)
41
- else
42
- ids = InitiativesCreated.by(user).with_state(state).pluck(:id)
43
- ids += InitiativesPromoted.by(user).with_state(state).pluck(:id)
44
- base = Initiative.where(id: ids)
45
- end
46
-
47
- return base if q.blank?
48
-
49
- organization.available_locales.each_with_index do |loc, index|
50
- base = if index.zero?
51
- base.where("title->>? ilike ?", loc, "%#{q}%")
52
- .or(Initiative.where("description->>? ilike ?", loc, "%#{q}%"))
53
- else
54
- base
55
- .or(Initiative.where("title->>? ilike ?", loc, "%#{q}%"))
56
- .or(Initiative.where("description->>? ilike ?", loc, "%#{q}%"))
57
- end
58
- end
26
+ return Initiative.where(organization: @user.organization) if @user.admin?
59
27
 
60
- base
28
+ Initiative.where(id: InitiativesCreated.by(@user) + InitiativesPromoted.by(@user))
61
29
  end
62
30
  end
63
31
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Initiatives
5
+ InitiativeApiType = GraphQL::ObjectType.define do
6
+ name "InitiativeType"
7
+ description "An initiative type"
8
+
9
+ field :id, !types.ID, "The internal ID for this initiative type"
10
+ field :title, Decidim::Core::TranslatedFieldType, "Initiative type name"
11
+ field :description, Decidim::Core::TranslatedFieldType, "This is the initiative type description"
12
+ field :createdAt, Decidim::Core::DateTimeType, "The date this initiative type was created", property: :created_at
13
+ field :updatedAt, Decidim::Core::DateTimeType, "The date this initiative type was updated", property: :updated_at
14
+ field :bannerImage, types.String, "Banner image", property: :banner_image
15
+ field :collectUserExtraFields, types.Boolean, "Collect participant personal data on signature", property: :collect_user_extra_fields
16
+ field :extraFieldsLegalInformation, types.String, "Legal information about the collection of personal data", property: :extra_fields_legal_information
17
+ field :minimumCommitteeMembers, types.Int, "Minimum of committee members", property: :minimum_committee_members
18
+ field :validateSmsCodeOnVotes, types.Boolean, "Add SMS code validation step to signature process", property: :validate_sms_code_on_votes
19
+ field :undoOnlineSignaturesEnabled, types.Boolean, "Enable participants to undo their online signatures", property: :undo_online_signatures_enabled
20
+ field :promotingComitteeEnabled, types.Boolean, "If promoting committee is enabled", property: :promoting_committee_enabled
21
+ field :signatureType, types.String, "Signature type of the initiative", property: :signature_type
22
+
23
+ field :initiatives, !types[Decidim::Initiatives::InitiativeType], "The initiatives that have this type"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Initiatives
5
+ # This type represents a initiative committee member.
6
+ InitiativeCommitteeMemberType = GraphQL::ObjectType.define do
7
+ name "InitiativeCommitteeMemberType"
8
+ description "A initiative committee member"
9
+
10
+ field :id, !types.ID, "Internal ID for this member of the committee"
11
+ field :user, Decidim::Core::UserType, "The decidim user for this initiative committee member"
12
+
13
+ field :state, types.Int, "Type of the committee member"
14
+ field :createdAt, Decidim::Core::DateTimeType, "The date this initiative committee member was created", property: :created_at
15
+ field :updatedAt, Decidim::Core::DateTimeType, "The date this initiative committee member was updated", property: :updated_at
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Initiatives
5
+ # This type represents a Initiative.
6
+ InitiativeType = GraphQL::ObjectType.define do
7
+ interfaces [
8
+ -> { Decidim::Core::ParticipatorySpaceInterface },
9
+ -> { Decidim::Core::ScopableInterface },
10
+ -> { Decidim::Core::AttachableInterface },
11
+ -> { Decidim::Core::AuthorInterface },
12
+ -> { Decidim::Initiatives::InitiativeTypeInterface }
13
+ ]
14
+
15
+ name "Initiative"
16
+ description "A initiative"
17
+
18
+ field :description, Decidim::Core::TranslatedFieldType, "The description of this initiative."
19
+ field :slug, !types.String
20
+ field :hashtag, types.String, "The hashtag for this initiative"
21
+ field :createdAt, !Decidim::Core::DateTimeType, "The time this initiative was created", property: :created_at
22
+ field :updatedAt, !Decidim::Core::DateTimeType, "The time this initiative was updated", property: :updated_at
23
+ field :publishedAt, !Decidim::Core::DateTimeType, "The time this initiative was published", property: :published_at
24
+ field :reference, !types.String, "Reference prefix for this initiative"
25
+ field :state, types.String, "Current status of the initiative"
26
+ field :signatureType, types.String, "Signature type of the initiative", property: :signature_type
27
+ field :signatureStartDate, !Decidim::Core::DateType, "The signature start date", property: :signature_start_date
28
+ field :signatureEndDate, !Decidim::Core::DateType, "The signature end date", property: :signature_end_date
29
+ field :offlineVotes, types.Int, "The number of offline votes in this initiative", property: :offline_votes
30
+ field :initiativeVotesCount, types.Int, "The number of votes in this initiative", property: :initiative_votes_count
31
+ field :initiativeSupportsCount, types.Int, "The number of supports in this initiative", property: :initiative_supports_count
32
+
33
+ field :author, !Decidim::Core::AuthorInterface, "The initiative author" do
34
+ resolve lambda { |obj, _args, _ctx|
35
+ obj.user_group || obj.author
36
+ }
37
+ end
38
+
39
+ field :committeeMembers, types[Decidim::Initiatives::InitiativeCommitteeMemberType], property: :committee_members
40
+ end
41
+ end
42
+ end
@@ -1,50 +1,10 @@
1
- <div class="filters row">
2
- <div class="column medium-3">
3
- <span class="dropdown-menu-inverted_label"><%= t(".filter_by") %> :</span>
4
- <ul class="dropdown menu dropdown-inverted" data-dropdown-menu data-close-on-click-inside="false">
5
- <li class="is-dropdown-submenu-parent">
6
- <a href="#">
7
- <% if @state.present? %>
8
- <%= t(".filter.#{@state}") %>
9
- <% else %>
10
- <%= t(".filter.all") %>
11
- <% end %>
12
- </a>
13
- <ul class="menu is-dropdown-submenu">
14
- <li><%= link_to t(".filter.created"), url_for(state: "created", q: @query) %></li>
15
- <li><%= link_to t(".filter.validating"), url_for(state: "validating", q: @query) %></li>
16
- <li><%= link_to t(".filter.discarded"), url_for(state: "discarded", q: @query) %></li>
17
- <li><%= link_to t(".filter.published"), url_for(state: "published", q: @query) %></li>
18
- <li><%= link_to t(".filter.rejected"), url_for(state: "rejected", q: @query) %></li>
19
- <li><%= link_to t(".filter.accepted"), url_for(state: "accepted", q: @query) %></li>
20
- <li><%= link_to t(".filter.all"), url_for(q: @query) %></li>
21
- </ul>
22
- </li>
23
- </ul>
24
- </div>
25
- <div class="column medium-4">
26
- <%= form_tag "", method: :get do %>
27
- <div class="filters__search">
28
- <div class="input-group">
29
- <%= search_field_tag :q, @query,label: false, class: "input-group-field", placeholder: t(".search") %>
30
- <%= hidden_field_tag :state, @state %>
31
- <div class="input-group-button">
32
- <button type="submit" class="button button--muted">
33
- <%= icon "magnifying-glass", aria_label: t(".search") %>
34
- </button>
35
- </div>
36
- </div>
37
- </div>
38
- <% end %>
39
- </div>
40
- </div>
41
-
42
- <div class="card" id="initiatives">
1
+ <div class="card with-overflow" id="initiatives">
43
2
  <div class="card-divider">
44
3
  <h2 class="card-title">
45
4
  <%= t "decidim.admin.titles.initiatives" %>
46
5
  </h2>
47
6
  </div>
7
+ <%= admin_filter_selector %>
48
8
  <div class="card-section">
49
9
  <div class="table-scroll">
50
10
  <table class="table-list">
@@ -54,7 +14,7 @@
54
14
  <th><%= t("models.initiatives.fields.title", scope: "decidim.admin") %></th>
55
15
  <th><%= t("models.initiatives.fields.state", scope: "decidim.admin") %></th>
56
16
  <th><%= t("models.initiatives.fields.supports_count", scope: "decidim.admin") %></th>
57
- <th><%= t("models.initiatives.fields.created_at", scope: "decidim.admin") %></th>
17
+ <th><%= sort_link(query, :created_at, t("models.initiatives.fields.created_at", scope: "decidim.admin"), default_order: :desc) %></th>
58
18
  <th class="actions"><%= t ".actions_title" %></th>
59
19
  </tr>
60
20
  </thead>
@@ -73,6 +73,18 @@ ar:
73
73
  admin:
74
74
  actions:
75
75
  new_initiative_type: نوع المبادرة الجديدة
76
+ filters:
77
+ search_placeholder:
78
+ title_or_description_cont: البحث عن %{collection} بحسب العنوان أو الوصف.
79
+ state_eq:
80
+ label: الحالة
81
+ values:
82
+ accepted: وافقت
83
+ created: تمّ إنشاؤه
84
+ discarded: التخلص منها
85
+ published: نشرت
86
+ rejected: مرفوض
87
+ validating: المصادقة الفنية
76
88
  menu:
77
89
  initiatives: المبادرات
78
90
  initiatives_types: أنواع المبادرة
@@ -188,18 +200,8 @@ ar:
188
200
  title: معلومات عامة
189
201
  index:
190
202
  actions_title: عمل
191
- filter:
192
- accepted: وافقت
193
- all: الكل
194
- created: تمّ إنشاؤه
195
- discarded: التخلص منها
196
- published: نشرت
197
- rejected: مرفوض
198
- validating: المصادقة الفنية
199
- filter_by: مصنف بواسطة
200
203
  preview: معاينة
201
204
  print: طباعة
202
- search: بحث
203
205
  show:
204
206
  print: طباعة
205
207
  update:
@@ -61,6 +61,18 @@ ca:
61
61
  admin:
62
62
  actions:
63
63
  new_initiative_type: Nou tipus d'iniciativa
64
+ filters:
65
+ search_placeholder:
66
+ title_or_description_cont: Cerca %{collection} per títol o descripció.
67
+ state_eq:
68
+ label: Estat
69
+ values:
70
+ accepted: Acceptada
71
+ created: Creada
72
+ discarded: Rebutjada
73
+ published: Publicada
74
+ rejected: Rebutjada
75
+ validating: Validació tècnica
64
76
  menu:
65
77
  initiatives: Iniciatives
66
78
  initiatives_types: Tipus d'iniciatives
@@ -176,18 +188,8 @@ ca:
176
188
  title: Informació general
177
189
  index:
178
190
  actions_title: Acció
179
- filter:
180
- accepted: Acceptada
181
- all: Totes
182
- created: Creada
183
- discarded: Rebutjada
184
- published: Publicada
185
- rejected: Rebutjada
186
- validating: Validació tècnica
187
- filter_by: Filtra per
188
191
  preview: Vista prèvia
189
192
  print: Imprimir
190
- search: Cerca
191
193
  show:
192
194
  print: Imprimir
193
195
  update: