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.
- 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
|