decidim-core 0.0.8.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/config/decidim_core_manifest.js +0 -1
- data/app/assets/javascripts/decidim/form_filter.component.js.es6 +12 -2
- data/app/assets/stylesheets/decidim/_decidim.scss +1 -2
- data/app/assets/stylesheets/decidim/extras/_embed.scss +21 -0
- data/app/assets/stylesheets/decidim/modules/_cards.scss +1 -1
- data/app/assets/stylesheets/decidim/modules/_icons.scss +1 -1
- data/app/commands/decidim/create_registration.rb +1 -1
- data/app/commands/decidim/invite_user.rb +7 -8
- data/app/controllers/concerns/decidim/filter_resource.rb +2 -3
- data/app/controllers/concerns/decidim/payload_info.rb +1 -1
- data/app/controllers/decidim/authorizations_controller.rb +0 -4
- data/app/controllers/decidim/pages_controller.rb +8 -11
- data/app/controllers/decidim/participatory_process_groups_controller.rb +1 -1
- data/app/controllers/decidim/participatory_process_widgets_controller.rb +4 -0
- data/app/controllers/decidim/widgets_controller.rb +7 -3
- data/app/forms/decidim/registration_form.rb +4 -4
- data/app/helpers/decidim/layout_helper.rb +1 -1
- data/app/helpers/decidim/map_helper.rb +21 -21
- data/app/helpers/decidim/resource_helper.rb +4 -4
- data/app/helpers/decidim/widget_urls_helper.rb +2 -2
- data/app/mailers/decidim/export_mailer.rb +29 -0
- data/app/middleware/decidim/current_organization.rb +1 -1
- data/app/models/decidim/feature.rb +5 -0
- data/app/models/decidim/organization.rb +1 -1
- data/app/models/decidim/participatory_process.rb +1 -1
- data/app/models/decidim/user.rb +1 -1
- data/app/presenters/decidim/home_stats_presenter.rb +74 -0
- data/app/queries/decidim/stats_users_count.rb +24 -0
- data/app/services/decidim/public_processes.rb +4 -2
- data/app/services/decidim/resource_search.rb +1 -1
- data/app/services/decidim/static_map_generator.rb +1 -3
- data/app/uploaders/decidim/image_uploader.rb +1 -1
- data/app/views/decidim/export_mailer/export.html.erb +1 -0
- data/app/views/decidim/participatory_process_widgets/show.html.erb +16 -27
- data/app/views/decidim/participatory_processes/show.html.erb +7 -7
- data/app/views/decidim/widgets/show.js.erb +27 -17
- data/app/views/layouts/decidim/widget.html.erb +55 -3
- data/app/views/pages/home/_statistics.html.erb +2 -10
- data/config/i18n-tasks.yml +1 -0
- data/config/initializers/devise.rb +11 -4
- data/config/locales/ca.yml +14 -3
- data/config/locales/en.yml +14 -3
- data/config/locales/es.yml +13 -2
- data/config/locales/eu.yml +0 -2
- data/config/locales/fi.yml +0 -2
- data/config/locales/fr.yml +386 -1
- data/config/locales/nl.yml +1 -3
- data/db/seeds.rb +1 -1
- data/lib/decidim/core.rb +10 -2
- data/lib/decidim/core/api/decidim_type.rb +4 -0
- data/lib/decidim/core/api/translated_field_type.rb +2 -2
- data/lib/decidim/core/engine.rb +13 -0
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +16 -18
- data/lib/decidim/core/test/shared_examples/manage_moderations_examples.rb +2 -2
- data/lib/decidim/core/test/shared_examples/reports_examples.rb +9 -9
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/exporters.rb +9 -0
- data/lib/decidim/exporters/csv.rb +54 -0
- data/lib/decidim/exporters/export_data.rb +22 -0
- data/lib/decidim/exporters/exporter.rb +28 -0
- data/lib/decidim/exporters/json.rb +22 -0
- data/lib/decidim/feature_manifest.rb +18 -0
- data/lib/decidim/file_zipper.rb +28 -0
- data/lib/decidim/form_builder.rb +27 -14
- data/lib/decidim/has_reference.rb +1 -1
- data/lib/decidim/i18n_exceptions.rb +3 -2
- data/lib/decidim/query_extensions.rb +1 -1
- data/lib/decidim/reportable.rb +1 -1
- data/lib/decidim/resource_manifest.rb +0 -7
- data/lib/decidim/stats_registry.rb +110 -0
- data/vendor/assets/javascripts/form_datepicker.js.es6 +3 -1
- metadata +53 -29
- data/app/assets/stylesheets/decidim/widget.scss.erb +0 -25
data/config/locales/nl.yml
CHANGED
@@ -308,7 +308,7 @@ nl:
|
|
308
308
|
title: Gebruikersinstellingen
|
309
309
|
user_groups: Organisaties
|
310
310
|
locale:
|
311
|
-
name:
|
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:
|
data/db/seeds.rb
CHANGED
data/lib/decidim/core.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
36
|
+
resolve lambda { |obj, args, _ctx|
|
37
37
|
translations = obj.stringify_keys
|
38
38
|
translations[args["locale"]]
|
39
39
|
}
|
data/lib/decidim/core/engine.rb
CHANGED
@@ -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
|
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(
|
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(
|
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
|
-
|
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(
|
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
|
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(
|
199
|
-
page.find(
|
200
|
-
expect(page).to have_selector(
|
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(
|
209
|
-
page.find(
|
210
|
-
expect(page).to have_selector(
|
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
|
-
|
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
|
-
|
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(
|
8
|
+
expect(page).to have_selector(".author-data__extra")
|
9
9
|
|
10
10
|
within ".author-data__extra", match: :first do
|
11
|
-
page.find(
|
11
|
+
page.find("button").click
|
12
12
|
end
|
13
13
|
|
14
|
-
expect(page).to have_css(
|
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(
|
27
|
+
expect(page).to have_selector(".author-data__extra")
|
28
28
|
|
29
29
|
within ".author-data__extra", match: :first do
|
30
|
-
page.find(
|
30
|
+
page.find("button").click
|
31
31
|
end
|
32
32
|
|
33
|
-
expect(page).to have_css(
|
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(
|
52
|
+
expect(page).to have_selector(".author-data__extra")
|
53
53
|
|
54
54
|
within ".author-data__extra", match: :first do
|
55
|
-
page.find(
|
55
|
+
page.find("button").click
|
56
56
|
end
|
57
57
|
|
58
|
-
expect(page).to have_css(
|
58
|
+
expect(page).to have_css(".flag-modal", visible: true)
|
59
59
|
|
60
60
|
expect(page).to have_content "already reported"
|
61
61
|
end
|
data/lib/decidim/core/version.rb
CHANGED
@@ -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
|