decidim-core 0.17.2 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of decidim-core might be problematic. Click here for more details.

Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/decidim.js.es6 +1 -0
  3. data/app/assets/javascripts/decidim/core/bundle.js +1 -1
  4. data/app/assets/javascripts/decidim/core/bundle.js.map +1 -1
  5. data/app/assets/javascripts/decidim/diff_mode_dropdown.js.es6 +16 -0
  6. data/app/assets/javascripts/decidim/represent_user_group.js.es6 +18 -0
  7. data/app/assets/stylesheets/decidim/_variables.scss +4 -0
  8. data/app/assets/stylesheets/decidim/extras/_meeting-registrations.scss +9 -0
  9. data/app/assets/stylesheets/decidim/modules/_data-picker.scss +25 -0
  10. data/app/assets/stylesheets/decidim/modules/_modules.scss +1 -0
  11. data/app/assets/stylesheets/decidim/modules/_order-by.scss +2 -0
  12. data/app/assets/stylesheets/decidim/modules/_versions.scss +75 -0
  13. data/app/cells/decidim/amendable/amend_button_card_cell.rb +1 -1
  14. data/app/cells/decidim/amendable/amenders_list/show.erb +3 -9
  15. data/app/cells/decidim/amendable/amenders_list_cell.rb +23 -1
  16. data/app/cells/decidim/amendable/promote_button_card/show.erb +2 -1
  17. data/app/cells/decidim/amendable/promote_button_card_cell.rb +6 -2
  18. data/app/cells/decidim/card_m_cell.rb +5 -0
  19. data/app/cells/decidim/content_blocks/footer_sub_hero/show.erb +1 -1
  20. data/app/cells/decidim/diff/attribute.erb +17 -0
  21. data/app/cells/decidim/diff/diff_mode_dropdown.erb +29 -0
  22. data/app/cells/decidim/diff/diff_split.erb +11 -0
  23. data/app/cells/decidim/diff/diff_unified.erb +7 -0
  24. data/app/cells/decidim/diff/show.erb +5 -0
  25. data/app/cells/decidim/diff_cell.rb +79 -0
  26. data/app/cells/decidim/represent_user_group/show.erb +12 -0
  27. data/app/cells/decidim/represent_user_group_cell.rb +46 -0
  28. data/app/commands/decidim/amendable/accept.rb +10 -19
  29. data/app/commands/decidim/amendable/create.rb +15 -38
  30. data/app/commands/decidim/amendable/promote.rb +20 -22
  31. data/app/commands/decidim/amendable/reject.rb +3 -3
  32. data/app/controllers/concerns/decidim/amendments_controller.rb +4 -4
  33. data/app/controllers/concerns/decidim/devise_controllers.rb +6 -4
  34. data/app/controllers/concerns/decidim/filter_resource.rb +13 -4
  35. data/app/controllers/concerns/decidim/needs_permission.rb +1 -0
  36. data/app/controllers/concerns/decidim/needs_tos_accepted.rb +2 -1
  37. data/app/controllers/concerns/decidim/registers_permissions.rb +27 -0
  38. data/app/controllers/decidim/application_controller.rb +5 -4
  39. data/app/events/decidim/amendable/amendment_accepted_event.rb +1 -7
  40. data/app/events/decidim/amendable/amendment_base_event.rb +7 -2
  41. data/app/events/decidim/amendable/amendment_created_event.rb +2 -8
  42. data/app/events/decidim/amendable/amendment_rejected_event.rb +1 -7
  43. data/app/events/decidim/amendable/emendation_promoted_event.rb +1 -7
  44. data/app/forms/decidim/amendable/create_form.rb +16 -32
  45. data/app/forms/decidim/amendable/form.rb +40 -4
  46. data/app/forms/decidim/amendable/promote_form.rb +7 -11
  47. data/app/forms/decidim/amendable/reject_form.rb +1 -1
  48. data/app/forms/decidim/amendable/review_form.rb +4 -23
  49. data/app/forms/decidim/invite_user_form.rb +2 -2
  50. data/app/helpers/decidim/amendments_helper.rb +64 -72
  51. data/app/helpers/decidim/application_helper.rb +18 -0
  52. data/app/helpers/decidim/decidim_form_helper.rb +13 -1
  53. data/app/helpers/decidim/scopes_helper.rb +13 -3
  54. data/app/helpers/decidim/traceability_helper.rb +0 -61
  55. data/app/helpers/decidim/translations_helper.rb +20 -1
  56. data/app/jobs/decidim/email_notification_generator_job.rb +2 -0
  57. data/app/jobs/decidim/notification_generator_job.rb +2 -0
  58. data/app/mailers/decidim/application_mailer.rb +15 -0
  59. data/app/models/decidim/amendment.rb +4 -0
  60. data/app/models/decidim/area.rb +18 -0
  61. data/app/models/decidim/follow.rb +4 -0
  62. data/app/models/decidim/newsletter.rb +24 -0
  63. data/app/models/decidim/permission_action.rb +13 -0
  64. data/app/models/decidim/user.rb +12 -2
  65. data/app/queries/decidim/metric_measure.rb +1 -1
  66. data/app/services/decidim/participatory_space_search.rb +54 -0
  67. data/app/views/decidim/account/_password_fields.html.erb +1 -1
  68. data/app/views/decidim/amendments/_edit_form_fields.html.erb +21 -0
  69. data/app/views/decidim/amendments/new.html.erb +18 -4
  70. data/app/views/decidim/amendments/review.html.erb +11 -5
  71. data/app/views/decidim/application/_photos.html.erb +1 -1
  72. data/app/views/decidim/devise/passwords/edit.html.erb +1 -1
  73. data/app/views/decidim/devise/registrations/new.html.erb +1 -1
  74. data/app/views/decidim/notifications_settings/show.html.erb +6 -6
  75. data/app/views/decidim/scopes/_scopes_picker_input.html.erb +6 -1
  76. data/app/views/decidim/shared/participatory_space_filters/_filters.html.erb +13 -0
  77. data/app/views/decidim/shared/participatory_space_filters/_filters_small_view.html.erb +19 -0
  78. data/app/views/decidim/shared/participatory_space_filters/_show.html.erb +7 -0
  79. data/app/views/decidim/user_interests/_areas.html.erb +2 -2
  80. data/app/views/decidim/user_interests/_scopes.html.erb +2 -2
  81. data/app/views/decidim/user_interests/show.html.erb +3 -1
  82. data/config/locales/ar-SA.yml +24 -21
  83. data/config/locales/ar.yml +1282 -0
  84. data/config/locales/ca.yml +38 -22
  85. data/config/locales/cs.yml +25 -19
  86. data/config/locales/de.yml +24 -18
  87. data/config/locales/en.yml +39 -23
  88. data/config/locales/es-MX.yml +35 -19
  89. data/config/locales/es-PY.yml +35 -19
  90. data/config/locales/es.yml +38 -22
  91. data/config/locales/eu.yml +24 -18
  92. data/config/locales/fi-plain.yml +34 -18
  93. data/config/locales/fi.yml +39 -23
  94. data/config/locales/fr.yml +24 -18
  95. data/config/locales/gl.yml +24 -18
  96. data/config/locales/hu.yml +30 -21
  97. data/config/locales/id-ID.yml +25 -19
  98. data/config/locales/it.yml +37 -21
  99. data/config/locales/nl.yml +24 -18
  100. data/config/locales/pl.yml +25 -19
  101. data/config/locales/pt-BR.yml +25 -19
  102. data/config/locales/pt.yml +25 -19
  103. data/config/locales/sv.yml +37 -21
  104. data/config/locales/tr-TR.yml +35 -19
  105. data/db/migrate/20181219130325_add_smtp_settings_to_decidim_organizations.rb +7 -0
  106. data/db/migrate/20190325145349_add_extended_data_to_newsletters.rb +7 -0
  107. data/db/migrate/20190412105836_add_missing_indexes.rb +11 -0
  108. data/db/migrate/20190412131728_fix_user_names.rb +24 -0
  109. data/db/seeds.rb +7 -0
  110. data/lib/decidim/amendable.rb +41 -29
  111. data/lib/decidim/attribute_encryptor.rb +20 -0
  112. data/lib/decidim/component_manifest.rb +4 -0
  113. data/lib/decidim/core.rb +20 -1
  114. data/lib/decidim/core/engine.rb +1 -0
  115. data/lib/decidim/core/test/factories.rb +9 -0
  116. data/lib/decidim/core/test/shared_examples/amendable/amendment_accepted_event_examples.rb +1 -1
  117. data/lib/decidim/core/test/shared_examples/amendable/amendment_created_event_examples.rb +2 -2
  118. data/lib/decidim/core/test/shared_examples/amendable/amendment_form_examples.rb +1 -1
  119. data/lib/decidim/core/test/shared_examples/amendable/amendment_promoted_event_examples.rb +1 -1
  120. data/lib/decidim/core/test/shared_examples/amendable/amendment_rejected_event_examples.rb +1 -1
  121. data/lib/decidim/core/test/shared_examples/amendable/create_amendment_examples.rb +3 -21
  122. data/lib/decidim/core/test/shared_examples/comments_examples.rb +18 -0
  123. data/lib/decidim/core/test/shared_examples/has_attachments.rb +1 -1
  124. data/lib/decidim/core/test/shared_examples/space_cell_changes_button_text_cta.rb +31 -0
  125. data/lib/decidim/core/version.rb +1 -1
  126. data/lib/decidim/exporters/csv.rb +2 -2
  127. data/lib/decidim/filter_form_builder.rb +8 -1
  128. data/lib/decidim/form_builder.rb +40 -4
  129. data/lib/decidim/has_component.rb +7 -0
  130. data/lib/decidim/has_private_users.rb +25 -8
  131. data/lib/decidim/jsonb_attributes.rb +45 -0
  132. data/lib/decidim/newsletter_participant.rb +18 -0
  133. data/lib/decidim/participable.rb +9 -0
  134. data/lib/decidim/permissions_registry.rb +39 -0
  135. data/lib/tasks/decidim_metrics_tasks.rake +35 -0
  136. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.ar.js +16 -0
  137. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.es-MX.js +15 -0
  138. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.es-PY.js +15 -0
  139. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.fi-pl.js +14 -0
  140. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.id.js +13 -0
  141. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.pl.js +15 -0
  142. data/vendor/assets/javascripts/datepicker-locales/{foundation-datepicker.pt-br.js → foundation-datepicker.pt-BR.js} +0 -0
  143. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.tr.js +14 -0
  144. metadata +42 -10
  145. data/app/views/decidim/amendments/_form.html.erb +0 -30
  146. data/app/views/decidim/amendments/_review_form.html.erb +0 -19
@@ -37,7 +37,7 @@ shared_examples "amendment accepted event" do
37
37
  describe "notification_title" do
38
38
  it "is generated correctly" do
39
39
  expect(subject.notification_title)
40
- .to include("The <a href=\"#{emendation_path}\">amendment</a> created by <a href=\"#{emendation_author_path}\">#{emendation_author_nickname}</a> has been accepted for <a href=\"#{amendable_path}\">#{amendable_title}</a> #{amendable_type}.") # rubocop:disable Metrics/LineLength
40
+ .to eq("The <a href=\"#{emendation_path}\">amendment</a> created by <a href=\"#{emendation_author_path}\">#{emendation_author_nickname}</a> has been accepted for <a href=\"#{amendable_path}\">#{amendable_title}</a>.") # rubocop:disable Metrics/LineLength
41
41
  end
42
42
  end
43
43
  end
@@ -21,7 +21,7 @@ shared_examples "amendment created event" do
21
21
 
22
22
  describe "email_subject" do
23
23
  it "is generated correctly" do
24
- expect(subject.email_subject).to eq("New amendment for #{amendable_title} from #{emendation_author_nickname}")
24
+ expect(subject.email_subject).to eq("New amendment for #{amendable_title}")
25
25
  end
26
26
  end
27
27
 
@@ -42,7 +42,7 @@ shared_examples "amendment created event" do
42
42
  describe "notification_title" do
43
43
  it "is generated correctly" do
44
44
  expect(subject.notification_title)
45
- .to include("A <a href=\"#{emendation_path}\">new amendment</a> has been created by <a href=\"#{emendation_author_path}\">#{emendation_author_nickname}</a> for <a href=\"#{amendable_path}\">#{amendable_title}</a> #{amendable_type}.") # rubocop:disable Metrics/LineLength
45
+ .to eq("A new amendment has been created for <a href=\"#{amendable_path}\">#{amendable_title}</a>.")
46
46
  end
47
47
  end
48
48
  end
@@ -3,7 +3,7 @@
3
3
  shared_examples "an amendment form" do
4
4
  let(:title) { "More sidewalks and less roads!" }
5
5
  let(:body) { "Everything would be better" }
6
- let(:emendation_fields) do
6
+ let(:emendation_params) do
7
7
  {
8
8
  title: title,
9
9
  body: body
@@ -37,7 +37,7 @@ shared_examples "amendment promoted event" do
37
37
  describe "notification_title" do
38
38
  it "is generated correctly" do
39
39
  expect(subject.notification_title)
40
- .to include("A <a href=\"#{emendation_path}\">rejected amendment</a> for <a href=\"#{amendable_path}\">#{amendable_title}</a> #{amendable_type} has been published as a new proposal by <a href=\"#{emendation_author_path}\">#{emendation_author_nickname}</a>.") # rubocop:disable Metrics/LineLength
40
+ .to eq("A <a href=\"#{emendation_path}\">rejected amendment</a> for <a href=\"#{amendable_path}\">#{amendable_title}</a> has been published as a new #{amendable_type} by <a href=\"#{emendation_author_path}\">#{emendation_author_nickname}</a>.") # rubocop:disable Metrics/LineLength
41
41
  end
42
42
  end
43
43
  end
@@ -37,7 +37,7 @@ shared_examples "amendment rejected event" do
37
37
  describe "notification_title" do
38
38
  it "is generated correctly" do
39
39
  expect(subject.notification_title)
40
- .to include("The <a href=\"#{emendation_path}\">amendment</a> created by <a href=\"#{emendation_author_path}\">#{emendation_author_nickname}</a> has been rejected for <a href=\"#{amendable_path}\">#{amendable_title}</a> #{amendable_type}.") # rubocop:disable Metrics/LineLength
40
+ .to eq("The <a href=\"#{emendation_path}\">amendment</a> created by <a href=\"#{emendation_author_path}\">#{emendation_author_nickname}</a> has been rejected for <a href=\"#{amendable_path}\">#{amendable_title}</a>.") # rubocop:disable Metrics/LineLength
41
41
  end
42
42
  end
43
43
  end
@@ -19,7 +19,7 @@ shared_examples "create amendment" do
19
19
  .to receive(:perform_action!)
20
20
  .with(
21
21
  "publish",
22
- form.amendable_type.constantize,
22
+ form.amendable.amendable_type.constantize,
23
23
  form.current_user,
24
24
  kind_of(Hash)
25
25
  ).and_call_original
@@ -34,9 +34,8 @@ shared_examples "create amendment" do
34
34
  event: "decidim.events.amendments.amendment_created",
35
35
  event_class: Decidim::Amendable::AmendmentCreatedEvent,
36
36
  resource: amendable,
37
- followers: kind_of(Array),
38
- affected_users: kind_of(Array),
39
- extra: kind_of(Hash)
37
+ affected_users: [amendable.creator_author],
38
+ followers: []
40
39
  )
41
40
 
42
41
  command.call
@@ -58,21 +57,4 @@ shared_examples "create amendment" do
58
57
  .by(0)
59
58
  end
60
59
  end
61
-
62
- context "when the emendation doens't change the amendable" do
63
- let(:title) { amendable.title }
64
- let(:body) { amendable.body }
65
-
66
- it "broadcasts invalid" do
67
- expect { command.call }.to broadcast(:invalid)
68
- end
69
-
70
- it "doesn't create an amendment and the emendation" do
71
- expect { command.call }
72
- .to change(Decidim::Amendment, :count)
73
- .by(0)
74
- .and change(amendable.resource_manifest.model_class_name.constantize, :count)
75
- .by(0)
76
- end
77
- end
78
60
  end
@@ -98,6 +98,7 @@ shared_examples "comments" do
98
98
  visit resource_path
99
99
 
100
100
  expect(page).to have_selector(".comment__reply")
101
+ expect(page).not_to have_selector(".comment__additionalreply")
101
102
 
102
103
  within "#comments #comment_#{comment.id}" do
103
104
  click_button "Reply"
@@ -110,10 +111,27 @@ shared_examples "comments" do
110
111
  end
111
112
 
112
113
  expect(page).to have_selector(".comment-thread .comment--nested")
114
+ expect(page).to have_selector(".comment__additionalreply")
113
115
  expect(page).to have_reply_to(comment, "This is a reply")
114
116
  end
115
117
  end
116
118
 
119
+ context "when a comment has been moderated" do
120
+ let!(:parent) { create(:comment, commentable: commentable) }
121
+ let!(:reply) { create(:comment, commentable: parent, root_commentable: commentable) }
122
+
123
+ it "doesn't show additional reply" do
124
+ Decidim::Moderation.create!(reportable: reply, participatory_space: reply.participatory_space, hidden_at: 1.day.ago)
125
+
126
+ visit current_path
127
+
128
+ within "#comments #comment_#{parent.id}" do
129
+ expect(page).to have_selector(".comment__reply")
130
+ expect(page).not_to have_selector(".comment__additionalreply")
131
+ end
132
+ end
133
+ end
134
+
117
135
  describe "arguable option" do
118
136
  context "when commenting with alignment" do
119
137
  before do
@@ -39,7 +39,7 @@ shared_examples_for "has attachments" do
39
39
  end
40
40
 
41
41
  within "div.wrapper .images" do
42
- expect(strip_tags(translated(fist_image.description, locale: :en))).to appear_before(strip_tags(translated(last_image.description, locale: :en)))
42
+ expect(strip_tags(translated(fist_image.title, locale: :en))).to appear_before(strip_tags(translated(last_image.title, locale: :en)))
43
43
  end
44
44
  end
45
45
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples_for "space cell changes button text CTA" do
6
+ describe "within the card footer" do
7
+ context "when it has no components" do
8
+ it "renders 'More info' in the CTA button text" do
9
+ expect(subject).to have_selector(".card__footer--spaces .card__button", text: "More info")
10
+ end
11
+ end
12
+
13
+ context "when it has a component" do
14
+ context "and it is not published" do
15
+ let!(:component) { create(:component, :unpublished, manifest_name: "dummy", participatory_space: model) }
16
+
17
+ it "renders 'More info' in the CTA button text" do
18
+ expect(subject).to have_selector(".card__footer--spaces .card__button", text: "More info")
19
+ end
20
+ end
21
+
22
+ context "and it is published" do
23
+ let!(:component) { create(:component, :published, manifest_name: "dummy", participatory_space: model) }
24
+
25
+ it "renders 'Take part' in the CTA button text" do
26
+ expect(subject).to have_selector(".card__footer--spaces .card__button", text: "Take part")
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-core version.
5
5
  module Core
6
6
  def self.version
7
- "0.17.2"
7
+ "0.18.0"
8
8
  end
9
9
  end
10
10
  end
@@ -15,8 +15,8 @@ module Decidim
15
15
  # provided serializer and following the previously described strategy.
16
16
  #
17
17
  # Returns an ExportData instance.
18
- def export
19
- data = ::CSV.generate(headers: headers, write_headers: true, col_sep: ";") do |csv|
18
+ def export(col_sep = Decidim.default_csv_col_sep)
19
+ data = ::CSV.generate(headers: headers, write_headers: true, col_sep: col_sep) do |csv|
20
20
  processed_collection.each do |resource|
21
21
  csv << headers.map { |header| resource[header] }
22
22
  end
@@ -40,8 +40,15 @@ module Decidim
40
40
  end
41
41
  end
42
42
 
43
+ # Wrap the areas select in a custom fieldset.
44
+ def areas_select(method, collection, options = {})
45
+ fieldset_wrapper options[:legend_title] do
46
+ super(method, collection, options)
47
+ end
48
+ end
49
+
43
50
  # Wrap the scopes picker in a custom fieldset.
44
- def scopes_picker(method, options = {})
51
+ def scopes_picker(method, options = { checkboxes_on_top: true })
45
52
  fieldset_wrapper options[:legend_title] do
46
53
  super(method, options)
47
54
  end
@@ -202,12 +202,44 @@ module Decidim
202
202
  select(name, @template.options_for_select(categories, selected: selected, disabled: disabled), options, html_options)
203
203
  end
204
204
 
205
+ # Public: Generates a select field for areas.
206
+ #
207
+ # name - The name of the field (usually area_id)
208
+ # collection - A collection of areas or area_types.
209
+ # If it's areas, we sort the selectable options alphabetically.
210
+ #
211
+ # Returns a String.
212
+ def areas_select(name, collection, options = {})
213
+ selectables = if collection.first.is_a?(Decidim::Area)
214
+ assemblies = collection
215
+ .map { |a| [a.name[I18n.locale.to_s], a.id] }
216
+ .sort_by { |arr| arr[0] }
217
+
218
+ @template.options_for_select(
219
+ assemblies,
220
+ selected: options[:selected]
221
+ )
222
+ else
223
+ @template.option_groups_from_collection_for_select(
224
+ collection,
225
+ :areas,
226
+ :translated_name,
227
+ :id,
228
+ :translated_name,
229
+ selected: options[:selected]
230
+ )
231
+ end
232
+
233
+ select(name, selectables, options)
234
+ end
235
+
205
236
  # Public: Generates a picker field for scope selection.
206
237
  #
207
238
  # attribute - The name of the field (usually scope_id)
208
239
  # options - An optional Hash with options:
209
240
  # - multiple - Multiple mode, to allow multiple scopes selection.
210
241
  # - label - Show label?
242
+ # - checkboxes_on_top - Show checked picker values on top (default) or below the picker prompt
211
243
  #
212
244
  # Also it should receive a block that returns a Hash with :url and :text for each selected scope (and for null scope for prompt)
213
245
  #
@@ -225,7 +257,11 @@ module Decidim
225
257
  scopes = selected_scopes(attribute).map { |scope| [scope, yield(scope)] }
226
258
  template = ""
227
259
  template += label(attribute, label_for(attribute) + required_for_attribute(attribute)) unless options[:label] == false
228
- template += @template.render("decidim/scopes/scopes_picker_input", picker_options: picker_options, prompt_params: prompt_params, scopes: scopes)
260
+ template += @template.render("decidim/scopes/scopes_picker_input",
261
+ picker_options: picker_options,
262
+ prompt_params: prompt_params,
263
+ scopes: scopes,
264
+ checkboxes_on_top: options[:checkboxes_on_top])
229
265
  template += error_and_help_text(attribute, options)
230
266
  template.html_safe
231
267
  end
@@ -366,11 +402,11 @@ module Decidim
366
402
  end
367
403
  end
368
404
 
369
- def form_field_for(attribute)
405
+ def form_field_for(attribute, options = {})
370
406
  if attribute == :body
371
- text_area attribute, rows: 10
407
+ text_area(attribute, options.merge(rows: 10))
372
408
  else
373
- text_field attribute
409
+ text_field(attribute, options)
374
410
  end
375
411
  end
376
412
 
@@ -12,6 +12,13 @@ module Decidim
12
12
  belongs_to :component, foreign_key: "decidim_component_id", class_name: "Decidim::Component", touch: true
13
13
  delegate :organization, to: :component, allow_nil: true
14
14
  delegate :participatory_space, to: :component, allow_nil: true
15
+
16
+ def can_participate_in_space?(user)
17
+ return true unless participatory_space.try(:private_space?)
18
+ return false unless user
19
+
20
+ participatory_space.users.include?(user)
21
+ end
15
22
  end
16
23
 
17
24
  class_methods do
@@ -9,17 +9,34 @@ module Decidim
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  included do
12
- has_many :participatory_space_private_users, class_name: "Decidim::ParticipatorySpacePrivateUser", as: :privatable_to, dependent: :destroy
13
- has_many :users, through: :participatory_space_private_users, class_name: "Decidim::User", foreign_key: "private_user_to_id"
12
+ has_many :participatory_space_private_users,
13
+ class_name: "Decidim::ParticipatorySpacePrivateUser",
14
+ as: :privatable_to,
15
+ dependent: :destroy
16
+ has_many :users,
17
+ through: :participatory_space_private_users,
18
+ class_name: "Decidim::User",
19
+ foreign_key: "private_user_to_id"
14
20
 
15
- scope :visible_for, lambda { |user|
16
- joins("LEFT JOIN decidim_participatory_space_private_users ON
17
- decidim_participatory_space_private_users.privatable_to_id = #{table_name}.id")
18
- .where("(private_space = ? and decidim_participatory_space_private_users.decidim_user_id = ?) or private_space = ? ", true, user, false).distinct
19
- }
21
+ def self.visible_for(user)
22
+ if user
23
+ return all if user.admin?
24
+
25
+ left_outer_joins(:participatory_space_private_users).where(
26
+ %(private_space = false OR
27
+ decidim_participatory_space_private_users.decidim_user_id = ?), user.id
28
+ )
29
+ else
30
+ public_spaces
31
+ end
32
+ end
20
33
 
21
34
  def self.public_spaces
22
- super.where(private_space: false)
35
+ where(private_space: false)
36
+ end
37
+
38
+ def self.private_spaces
39
+ where(private_space: true)
23
40
  end
24
41
  end
25
42
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ # A set of convenient methods to generate dynamic jsonb objects in a way is
7
+ # compatilbe with Virtus and ActiveModel thus making it easy to integrate
8
+ # into Rails forms and similar workflows.
9
+ module JsonbAttributes
10
+ extend ActiveSupport::Concern
11
+
12
+ class_methods do
13
+ # Public: Mirrors Virtus `attribute` interface to define attributes in
14
+ # custom jsonb objects.
15
+ #
16
+ # name - Attribute's name
17
+ # fields - The attribute's child fields
18
+ #
19
+ # Example:
20
+ # jsonb_attribute(:settings, [[:custom_setting, String], [:another_setting, Boolean])
21
+ # # This will generate `custom_setting`, `custom_setting=` and
22
+ # # `another_setting`, `another_setting=` and will keep them
23
+ # # syncronized with a hash in `settings`:
24
+ # # settings = { "custom_setting" => "demo", "another_setting" => "demo"}
25
+ #
26
+ # Returns nothing.
27
+ def jsonb_attribute(name, fields, *options)
28
+ attribute name, Hash, default: {}
29
+
30
+ fields.each do |f, type|
31
+ attribute f, type, *options
32
+ define_method f do
33
+ field = public_send(name) || {}
34
+ field[f.to_s] || field[f.to_sym]
35
+ end
36
+
37
+ define_method "#{f}=" do |value|
38
+ field = public_send(name) || {}
39
+ public_send("#{name}=", field.merge(f => super(value)))
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ # This concern contains the logic related to newsletter participants
7
+ module NewsletterParticipant
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ # Returns a User collection Participants
12
+ # This is the default, if you want, you can overwrite in each Class to be export.
13
+ def self.newsletter_participant_ids(_component)
14
+ nil
15
+ end
16
+ end
17
+ end
18
+ end
@@ -75,6 +75,15 @@ module Decidim
75
75
  def can_participate?(_user)
76
76
  true
77
77
  end
78
+
79
+ def empty_published_component?
80
+ components.published.empty?
81
+ end
82
+
83
+ def cta_button_text_key
84
+ return :more_info if empty_published_component?
85
+ :take_part
86
+ end
78
87
  end
79
88
 
80
89
  class_methods do
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ #
5
+ # Takes care of holding and accessing permissions classes for each artifact.
6
+ #
7
+ class PermissionsRegistry
8
+ def initialize
9
+ @registry = {}
10
+ end
11
+
12
+ # Syntactic sugar for the `chain_for` instance method.
13
+ def self.chain_for(artifact)
14
+ ::Decidim.permissions_registry.chain_for(artifact)
15
+ end
16
+
17
+ # Returns the registered array of permissions for the given `artifact`.
18
+ #
19
+ # +artifact+ is expected to be the class or module that declares `NeedsPermission.permission_class_chain`.
20
+ def chain_for(artifact)
21
+ @registry[artifact_to_key(artifact)]
22
+ end
23
+
24
+ # Registers the of `Permissions` for the given `artifact`.
25
+ #
26
+ # +artifact+ is expected to be the class or module that declares `NeedsPermission.permission_class_chain`.
27
+ # +permission_classes+ are subclasses of `DefaultPermissions`.
28
+ def register_permissions(artifact, *permission_classes)
29
+ @registry[artifact_to_key(artifact)] = permission_classes.dup
30
+ end
31
+
32
+ # Registry accepts the class or the class name of the artifact,
33
+ # but the registry only indexes by the name.
34
+ # Artifact name normalization is done here.
35
+ def artifact_to_key(artifact)
36
+ artifact.respond_to?(:name) ? artifact.name : artifact
37
+ end
38
+ end
39
+ end