decidim-core 0.0.8.1 → 0.1.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/decidim_core_manifest.js +0 -1
  3. data/app/assets/javascripts/decidim/form_filter.component.js.es6 +12 -2
  4. data/app/assets/stylesheets/decidim/_decidim.scss +1 -2
  5. data/app/assets/stylesheets/decidim/extras/_embed.scss +21 -0
  6. data/app/assets/stylesheets/decidim/modules/_cards.scss +1 -1
  7. data/app/assets/stylesheets/decidim/modules/_icons.scss +1 -1
  8. data/app/commands/decidim/create_registration.rb +1 -1
  9. data/app/commands/decidim/invite_user.rb +7 -8
  10. data/app/controllers/concerns/decidim/filter_resource.rb +2 -3
  11. data/app/controllers/concerns/decidim/payload_info.rb +1 -1
  12. data/app/controllers/decidim/authorizations_controller.rb +0 -4
  13. data/app/controllers/decidim/pages_controller.rb +8 -11
  14. data/app/controllers/decidim/participatory_process_groups_controller.rb +1 -1
  15. data/app/controllers/decidim/participatory_process_widgets_controller.rb +4 -0
  16. data/app/controllers/decidim/widgets_controller.rb +7 -3
  17. data/app/forms/decidim/registration_form.rb +4 -4
  18. data/app/helpers/decidim/layout_helper.rb +1 -1
  19. data/app/helpers/decidim/map_helper.rb +21 -21
  20. data/app/helpers/decidim/resource_helper.rb +4 -4
  21. data/app/helpers/decidim/widget_urls_helper.rb +2 -2
  22. data/app/mailers/decidim/export_mailer.rb +29 -0
  23. data/app/middleware/decidim/current_organization.rb +1 -1
  24. data/app/models/decidim/feature.rb +5 -0
  25. data/app/models/decidim/organization.rb +1 -1
  26. data/app/models/decidim/participatory_process.rb +1 -1
  27. data/app/models/decidim/user.rb +1 -1
  28. data/app/presenters/decidim/home_stats_presenter.rb +74 -0
  29. data/app/queries/decidim/stats_users_count.rb +24 -0
  30. data/app/services/decidim/public_processes.rb +4 -2
  31. data/app/services/decidim/resource_search.rb +1 -1
  32. data/app/services/decidim/static_map_generator.rb +1 -3
  33. data/app/uploaders/decidim/image_uploader.rb +1 -1
  34. data/app/views/decidim/export_mailer/export.html.erb +1 -0
  35. data/app/views/decidim/participatory_process_widgets/show.html.erb +16 -27
  36. data/app/views/decidim/participatory_processes/show.html.erb +7 -7
  37. data/app/views/decidim/widgets/show.js.erb +27 -17
  38. data/app/views/layouts/decidim/widget.html.erb +55 -3
  39. data/app/views/pages/home/_statistics.html.erb +2 -10
  40. data/config/i18n-tasks.yml +1 -0
  41. data/config/initializers/devise.rb +11 -4
  42. data/config/locales/ca.yml +14 -3
  43. data/config/locales/en.yml +14 -3
  44. data/config/locales/es.yml +13 -2
  45. data/config/locales/eu.yml +0 -2
  46. data/config/locales/fi.yml +0 -2
  47. data/config/locales/fr.yml +386 -1
  48. data/config/locales/nl.yml +1 -3
  49. data/db/seeds.rb +1 -1
  50. data/lib/decidim/core.rb +10 -2
  51. data/lib/decidim/core/api/decidim_type.rb +4 -0
  52. data/lib/decidim/core/api/translated_field_type.rb +2 -2
  53. data/lib/decidim/core/engine.rb +13 -0
  54. data/lib/decidim/core/test/shared_examples/comments_examples.rb +16 -18
  55. data/lib/decidim/core/test/shared_examples/manage_moderations_examples.rb +2 -2
  56. data/lib/decidim/core/test/shared_examples/reports_examples.rb +9 -9
  57. data/lib/decidim/core/version.rb +1 -1
  58. data/lib/decidim/exporters.rb +9 -0
  59. data/lib/decidim/exporters/csv.rb +54 -0
  60. data/lib/decidim/exporters/export_data.rb +22 -0
  61. data/lib/decidim/exporters/exporter.rb +28 -0
  62. data/lib/decidim/exporters/json.rb +22 -0
  63. data/lib/decidim/feature_manifest.rb +18 -0
  64. data/lib/decidim/file_zipper.rb +28 -0
  65. data/lib/decidim/form_builder.rb +27 -14
  66. data/lib/decidim/has_reference.rb +1 -1
  67. data/lib/decidim/i18n_exceptions.rb +3 -2
  68. data/lib/decidim/query_extensions.rb +1 -1
  69. data/lib/decidim/reportable.rb +1 -1
  70. data/lib/decidim/resource_manifest.rb +0 -7
  71. data/lib/decidim/stats_registry.rb +110 -0
  72. data/vendor/assets/javascripts/form_datepicker.js.es6 +3 -1
  73. metadata +53 -29
  74. data/app/assets/stylesheets/decidim/widget.scss.erb +0 -25
@@ -308,7 +308,7 @@ nl:
308
308
  title: Gebruikersinstellingen
309
309
  user_groups: Organisaties
310
310
  locale:
311
- name: Engels
311
+ name: Nederlands
312
312
  pages:
313
313
  '404':
314
314
  back_home: Terug naar huis
@@ -340,8 +340,6 @@ nl:
340
340
  see_all_processes: Toon alle processen
341
341
  statistics:
342
342
  headline: Huidige stand van %{organization}
343
- processes: Processen
344
- users: Gebruikers
345
343
  sub_hero:
346
344
  register: Registeren
347
345
  social_share_button:
@@ -20,7 +20,7 @@ if !Rails.env.production? || ENV["SEED"]
20
20
  reference_prefix: Faker::Name.suffix
21
21
  )
22
22
 
23
- 3.times.each do |index|
23
+ 3.times.each do
24
24
  Decidim::Scope.create!(
25
25
  name: Faker::Address.unique.state,
26
26
  organization: organization
@@ -24,6 +24,9 @@ module Decidim
24
24
  autoload :HasCategory, "decidim/has_category"
25
25
  autoload :HasReference, "decidim/has_reference"
26
26
  autoload :Attributes, "decidim/attributes"
27
+ autoload :StatsRegistry, "decidim/stats_registry"
28
+ autoload :Exporters, "decidim/exporters"
29
+ autoload :FileZipper, "decidim/file_zipper"
27
30
 
28
31
  include ActiveSupport::Configurable
29
32
 
@@ -79,13 +82,13 @@ module Decidim
79
82
 
80
83
  # Exposes a configuration option: The application name String.
81
84
  config_accessor :available_locales do
82
- %w(en ca es eu fi)
85
+ %w(en ca es eu fi fr nl)
83
86
  end
84
87
 
85
88
  # Exposes a configuration option: an object to configure geocoder
86
89
  config_accessor :geocoder
87
90
 
88
- # Exposes a configuration option: the currency unit
91
+ # Exposes a configuration option: the currency unit
89
92
  config_accessor :currency_unit { "€" }
90
93
 
91
94
  # Exposes a configuration option: The maximum file size of an attachment.
@@ -155,4 +158,9 @@ module Decidim
155
158
  def self.resource_manifests
156
159
  @resource_manifests ||= feature_manifests.flat_map(&:resource_manifests)
157
160
  end
161
+
162
+ # Public: Stores an instance of StatsRegistry
163
+ def self.stats
164
+ @stats ||= StatsRegistry.new
165
+ end
158
166
  end
@@ -8,5 +8,9 @@ module Decidim
8
8
  field :version, !types.String, "The current decidim's version of this deployment." do
9
9
  resolve ->(obj, _args, _ctx) { obj.version }
10
10
  end
11
+
12
+ field :application_name, !types.String, "The current installation's name." do
13
+ resolve ->(obj, _args, _ctx) { obj.application_name }
14
+ end
11
15
  end
12
16
  end
@@ -20,7 +20,7 @@ module Decidim
20
20
  description "A list of locales to scope the translations to."
21
21
  end
22
22
 
23
- resolve ->(obj, args, _ctx) {
23
+ resolve lambda { |obj, args, _ctx|
24
24
  translations = obj.stringify_keys
25
25
  translations = translations.slice(*args["locales"]) if args["locales"]
26
26
 
@@ -33,7 +33,7 @@ module Decidim
33
33
  description "Returns a single translation given a locale."
34
34
  argument :locale, !types.String, "A locale to search for"
35
35
 
36
- resolve ->(obj, args, _ctx) {
36
+ resolve lambda { |obj, args, _ctx|
37
37
  translations = obj.stringify_keys
38
38
  translations[args["locale"]]
39
39
  }
@@ -119,6 +119,19 @@ module Decidim
119
119
  )
120
120
  end
121
121
  end
122
+
123
+ initializer "decidim.stats" do
124
+ Decidim.stats.register :users_count, priority: StatsRegistry::HIGH_PRIORITY do |organization, start_at, end_at|
125
+ StatsUsersCount.for(organization, start_at, end_at)
126
+ end
127
+
128
+ Decidim.stats.register :processes_count, priority: StatsRegistry::HIGH_PRIORITY do |organization, start_at, end_at|
129
+ processes = (OrganizationParticipatoryProcesses.new(organization) | PublicParticipatoryProcesses.new)
130
+ processes = processes.where("created_at >= ?", start_at) if start_at.present?
131
+ processes = processes.where("created_at <= ?", end_at) if end_at.present?
132
+ processes.count
133
+ end
134
+ end
122
135
  end
123
136
  end
124
137
  end
@@ -3,17 +3,15 @@
3
3
  RSpec.shared_examples "comments" do
4
4
  let!(:organization) { create(:organization) }
5
5
  let!(:user) { create(:user, :confirmed, organization: organization) }
6
- let!(:comments) {
7
- 3.times.map do
6
+ let!(:comments) do
7
+ Array.new(3) do
8
8
  create(:comment, commentable: commentable)
9
9
  end
10
- }
10
+ end
11
11
  let(:authenticated) { false }
12
12
 
13
13
  def visit_commentable_path
14
- if authenticated
15
- login_as user, scope: :user
16
- end
14
+ login_as user, scope: :user if authenticated
17
15
  visit resource_path
18
16
  end
19
17
 
@@ -42,13 +40,13 @@ RSpec.shared_examples "comments" do
42
40
  visit_commentable_path
43
41
 
44
42
  within ".order-by" do
45
- page.find('.dropdown.menu .is-dropdown-submenu-parent').hover
43
+ page.find(".dropdown.menu .is-dropdown-submenu-parent").hover
46
44
  end
47
45
 
48
46
  click_link "Best rated"
49
47
 
50
48
  within "#comments" do
51
- expect(page.find('.comment', match: :first)).to have_content "Most Rated Comment"
49
+ expect(page.find(".comment", match: :first)).to have_content "Most Rated Comment"
52
50
  end
53
51
  end
54
52
 
@@ -98,9 +96,9 @@ RSpec.shared_examples "comments" do
98
96
  expect(page).to have_content "This is a new comment"
99
97
  end
100
98
  else
101
- expect {
99
+ expect do
102
100
  wait_for_email subject: "new comment"
103
- }.to raise_error StandardError
101
+ end.to raise_error StandardError
104
102
  end
105
103
  end
106
104
  end
@@ -173,7 +171,7 @@ RSpec.shared_examples "comments" do
173
171
 
174
172
  expect(page).to have_selector(".add-comment form")
175
173
 
176
- page.find('.opinion-toggle--ok').click
174
+ page.find(".opinion-toggle--ok").click
177
175
 
178
176
  within ".add-comment form" do
179
177
  fill_in "add-comment-#{commentable.commentable_type}-#{commentable.id}", with: "I am in favor about this!"
@@ -181,7 +179,7 @@ RSpec.shared_examples "comments" do
181
179
  end
182
180
 
183
181
  within "#comments" do
184
- expect(page).to have_selector 'span.success.label', text: "In favor"
182
+ expect(page).to have_selector "span.success.label", text: "In favor"
185
183
  end
186
184
  end
187
185
  end
@@ -195,9 +193,9 @@ RSpec.shared_examples "comments" do
195
193
  visit_commentable_path
196
194
 
197
195
  within "#comment_#{comments[0].id}" do
198
- expect(page).to have_selector('.comment__votes--up', text: /0/)
199
- page.find('.comment__votes--up').click
200
- expect(page).to have_selector('.comment__votes--up', text: /1/)
196
+ expect(page).to have_selector(".comment__votes--up", text: /0/)
197
+ page.find(".comment__votes--up").click
198
+ expect(page).to have_selector(".comment__votes--up", text: /1/)
201
199
  end
202
200
  end
203
201
 
@@ -205,9 +203,9 @@ RSpec.shared_examples "comments" do
205
203
  visit_commentable_path
206
204
 
207
205
  within "#comment_#{comments[0].id}" do
208
- expect(page).to have_selector('.comment__votes--down', text: /0/)
209
- page.find('.comment__votes--down').click
210
- expect(page).to have_selector('.comment__votes--down', text: /1/)
206
+ expect(page).to have_selector(".comment__votes--down", text: /0/)
207
+ page.find(".comment__votes--down").click
208
+ expect(page).to have_selector(".comment__votes--down", text: /1/)
211
209
  end
212
210
  end
213
211
  end
@@ -38,7 +38,7 @@ RSpec.shared_examples "manage moderations" do
38
38
  click_link "Moderations"
39
39
 
40
40
  within "tr[data-id=\"#{moderation.id}\"]" do
41
- click_link "Unreport"
41
+ find("a.action-icon--unreport").click
42
42
  end
43
43
 
44
44
  within ".callout-wrapper" do
@@ -50,7 +50,7 @@ RSpec.shared_examples "manage moderations" do
50
50
  click_link "Moderations"
51
51
 
52
52
  within "tr[data-id=\"#{moderation.id}\"]" do
53
- click_link "Hide"
53
+ find("a.action-icon--hide").click
54
54
  end
55
55
 
56
56
  within ".callout-wrapper" do
@@ -5,13 +5,13 @@ RSpec.shared_examples "reports" do
5
5
  it "should be given the option to sign in" do
6
6
  visit reportable_path
7
7
 
8
- expect(page).to have_selector('.author-data__extra')
8
+ expect(page).to have_selector(".author-data__extra")
9
9
 
10
10
  within ".author-data__extra", match: :first do
11
- page.find('button').click
11
+ page.find("button").click
12
12
  end
13
13
 
14
- expect(page).to have_css('#loginModal', visible: true)
14
+ expect(page).to have_css("#loginModal", visible: true)
15
15
  end
16
16
  end
17
17
 
@@ -24,13 +24,13 @@ RSpec.shared_examples "reports" do
24
24
  it "reports the resource" do
25
25
  visit reportable_path
26
26
 
27
- expect(page).to have_selector('.author-data__extra')
27
+ expect(page).to have_selector(".author-data__extra")
28
28
 
29
29
  within ".author-data__extra", match: :first do
30
- page.find('button').click
30
+ page.find("button").click
31
31
  end
32
32
 
33
- expect(page).to have_css('.flag-modal', visible: true)
33
+ expect(page).to have_css(".flag-modal", visible: true)
34
34
 
35
35
  within ".flag-modal" do
36
36
  click_button "Report"
@@ -49,13 +49,13 @@ RSpec.shared_examples "reports" do
49
49
  it "cannot report it twice" do
50
50
  visit reportable_path
51
51
 
52
- expect(page).to have_selector('.author-data__extra')
52
+ expect(page).to have_selector(".author-data__extra")
53
53
 
54
54
  within ".author-data__extra", match: :first do
55
- page.find('button').click
55
+ page.find("button").click
56
56
  end
57
57
 
58
- expect(page).to have_css('.flag-modal', visible: true)
58
+ expect(page).to have_css(".flag-modal", visible: true)
59
59
 
60
60
  expect(page).to have_content "already reported"
61
61
  end
@@ -2,7 +2,7 @@
2
2
  # This holds Decidim's version and the Rails version on which it depends.
3
3
  module Decidim
4
4
  def self.version
5
- "0.0.8.1"
5
+ "0.1.0"
6
6
  end
7
7
 
8
8
  def self.rails_version
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Exporters
4
+ autoload :Exporter, "decidim/exporters/exporter"
5
+ autoload :JSON, "decidim/exporters/json"
6
+ autoload :CSV, "decidim/exporters/csv"
7
+ autoload :ExportData, "decidim/exporters/export_data"
8
+ end
9
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ require "csv"
3
+
4
+ module Decidim
5
+ module Exporters
6
+ # Exports any serialized object (Hash) into a readable CSV. It transforms
7
+ # the columns using slashes in a way that can be afterwards reconstructed
8
+ # into the original nested hash.
9
+ #
10
+ # For example, `{ name: { ca: "Hola", en: "Hello" } }` would result into
11
+ # the columns: `name/ca` and `name/es`.
12
+ class CSV < Exporter
13
+ # Public: Exports a CSV serialized version of the collection using the
14
+ # provided serializer and following the previously described strategy.
15
+ #
16
+ # Returns an ExportData instance.
17
+ def export
18
+ data = ::CSV.generate(headers: headers, write_headers: true, col_sep: ";") do |csv|
19
+ processed_collection.each do |resource|
20
+ csv << headers.map { |header| resource[header] }
21
+ end
22
+ end
23
+
24
+ ExportData.new(data, "csv")
25
+ end
26
+
27
+ private
28
+
29
+ def headers
30
+ return [] if processed_collection.empty?
31
+ processed_collection.first.keys
32
+ end
33
+
34
+ def processed_collection
35
+ @processed_collection ||= collection.map do |resource|
36
+ flatten(@serializer.new(resource).serialize)
37
+ end
38
+ end
39
+
40
+ def flatten(object, key = nil)
41
+ if object.is_a? Hash
42
+ object.inject({}) do |result, (subkey, value)|
43
+ new_key = key ? "#{key}/#{subkey}" : subkey.to_s
44
+ result.merge(flatten(value, new_key))
45
+ end
46
+ elsif object.is_a?(Array)
47
+ { key.to_s => object.map(&:to_s).join(", ") }
48
+ else
49
+ { key.to_s => object }
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Exporters
4
+ # Holds the result of an export.
5
+ class ExportData
6
+ attr_reader :extension
7
+
8
+ # Initializes an `ExportData` with the RAW data and the extension.
9
+ def initialize(data, extension)
10
+ @data = data
11
+ @extension = extension
12
+ end
13
+
14
+ # Gives back the raw data of the export.
15
+ #
16
+ # Returns a String with the result of the export.
17
+ def read
18
+ @data
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ module Decidim
3
+ module Exporters
4
+ # Abstract class providing the interface and partial implementation
5
+ # of an exporter. See `Decidim::Exporters::JSON` and `Decidim::Exporters::CSV`
6
+ # for a reference implementation.
7
+ class Exporter
8
+ # Public: Initializes an Exporter.
9
+ #
10
+ # collection - An Array with the collection to be exported.
11
+ # serializer - A Serializer to be used during the export.
12
+ def initialize(collection, serializer)
13
+ @collection = collection
14
+ @serializer = serializer
15
+ end
16
+
17
+ # Public: Should generate an `ExportData` with the result of the export.
18
+ # Responsibility of the subclass.
19
+ def export
20
+ raise NotImplementedError
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :collection, :serializer
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ require "json"
3
+
4
+ module Decidim
5
+ module Exporters
6
+ # Exports a JSON version of a provided hash, given a collection and a
7
+ # Serializer.
8
+ class JSON < Exporter
9
+ # Public: Generates a JSON representation of a collection and a
10
+ # Serializer.
11
+ #
12
+ # Returns an ExportData with the export.
13
+ def export
14
+ data = ::JSON.pretty_generate(@collection.map do |resource|
15
+ @serializer.new(resource).serialize
16
+ end)
17
+
18
+ ExportData.new(data, "json")
19
+ end
20
+ end
21
+ end
22
+ end
@@ -135,5 +135,23 @@ module Decidim
135
135
  def resource_manifests
136
136
  @resource_manifests ||= []
137
137
  end
138
+
139
+ # Public: Stores an instance of StatsRegistry
140
+ def stats
141
+ @stats ||= StatsRegistry.new
142
+ end
143
+
144
+ # Public: Registers a stat inside a feature manifest.
145
+ #
146
+ # name - The name of the stat
147
+ # options - A hash of options
148
+ # * primary: Wether the stat is primary or not.
149
+ # * priority: The priority of the stat used for render issues.
150
+ # block - A block that receive the features to filter out the stat.
151
+ #
152
+ # Returns nothing.
153
+ def register_stat(name, options = {}, &block)
154
+ stats.register(name, options, &block)
155
+ end
138
156
  end
139
157
  end