decidim-core 0.11.2 → 0.12.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/decidim/notifications.js.es6 +8 -6
- data/app/assets/javascripts/decidim/user_registrations.js.es6 +25 -1
- data/app/assets/stylesheets/decidim/application.scss.erb +4 -0
- data/app/assets/stylesheets/decidim/layouts/_home.scss +79 -0
- data/app/assets/stylesheets/decidim/modules/_author-avatar.scss +2 -1
- data/app/assets/stylesheets/decidim/modules/_cards.scss +82 -38
- data/app/assets/stylesheets/decidim/modules/_collapsible-list.scss +16 -0
- data/app/assets/stylesheets/decidim/modules/_definition-data.scss +27 -0
- data/app/assets/stylesheets/decidim/modules/_fingerprint.scss +8 -0
- data/app/assets/stylesheets/decidim/modules/_horizontal-tabs.scss +51 -0
- data/app/assets/stylesheets/decidim/modules/_inline-filters.scss +5 -3
- data/app/assets/stylesheets/decidim/modules/_margins.scss +6 -4
- data/app/assets/stylesheets/decidim/modules/_modules.scss +3 -0
- data/app/assets/stylesheets/decidim/modules/_navbar.scss +113 -7
- data/app/assets/stylesheets/decidim/modules/_signup.scss +22 -5
- data/app/assets/stylesheets/decidim/modules/_toggle.scss +9 -0
- data/app/assets/stylesheets/decidim/modules/_typography.scss +5 -1
- data/app/assets/stylesheets/decidim/utils/_helpers.scss +42 -0
- data/app/assets/stylesheets/decidim/utils/_mixins.scss +6 -0
- data/app/assets/stylesheets/decidim/utils/_settings.scss +3 -2
- data/app/cells/decidim/announcement/show.erb +11 -0
- data/app/cells/decidim/announcement_cell.rb +32 -0
- data/app/cells/decidim/author/comments.erb +6 -0
- data/app/cells/decidim/author/contact.erb +3 -0
- data/app/cells/decidim/author/date.erb +5 -0
- data/app/cells/decidim/author/flag.erb +5 -0
- data/app/cells/decidim/author/profile.erb +9 -0
- data/app/cells/decidim/{profile → author}/profile_inline.erb +1 -1
- data/app/cells/decidim/author/show.erb +18 -0
- data/app/cells/decidim/author/withdraw.erb +6 -0
- data/app/cells/decidim/author_cell.rb +109 -0
- data/app/cells/decidim/card/show.erb +18 -16
- data/app/cells/decidim/card_cell.rb +17 -4
- data/app/cells/decidim/card_m/author.erb +3 -0
- data/app/cells/decidim/card_m/badge.erb +1 -0
- data/app/cells/decidim/card_m/comments_counter.erb +3 -0
- data/app/cells/decidim/card_m/data.erb +0 -0
- data/app/cells/decidim/card_m/footer.erb +0 -0
- data/app/cells/decidim/card_m/header.erb +17 -0
- data/app/cells/decidim/card_m/image.erb +5 -0
- data/app/cells/decidim/card_m/label.erb +3 -0
- data/app/cells/decidim/card_m/show.erb +24 -0
- data/app/cells/decidim/card_m/status.erb +9 -0
- data/app/cells/decidim/card_m/tags.erb +0 -0
- data/app/cells/decidim/card_m_cell.rb +136 -0
- data/app/cells/decidim/collapsible_list/show.erb +20 -0
- data/app/cells/decidim/collapsible_list_cell.rb +66 -0
- data/app/cells/decidim/fingerprint/show.erb +22 -0
- data/app/cells/decidim/fingerprint_cell.rb +17 -0
- data/app/cells/decidim/follow_button/show.erb +34 -0
- data/app/cells/decidim/follow_button_cell.rb +40 -0
- data/app/cells/decidim/followers/show.erb +9 -0
- data/app/cells/decidim/followers_cell.rb +18 -0
- data/app/cells/decidim/following/show.erb +9 -0
- data/app/cells/decidim/following_cell.rb +24 -0
- data/app/cells/decidim/notifications/show.erb +48 -0
- data/app/cells/decidim/notifications_cell.rb +21 -0
- data/app/cells/decidim/progress_bar/show.erb +17 -0
- data/app/cells/decidim/progress_bar_cell.rb +68 -0
- data/app/cells/decidim/tags/category.erb +1 -0
- data/app/cells/decidim/tags/scope.erb +1 -0
- data/app/cells/decidim/tags/show.erb +5 -0
- data/app/cells/decidim/tags_cell.rb +62 -0
- data/app/cells/decidim/tos_page/announcement.erb +2 -0
- data/app/cells/decidim/tos_page/refuse_btn_modal.erb +23 -0
- data/app/cells/decidim/tos_page/sticky_form.erb +29 -0
- data/app/cells/decidim/tos_page_cell.rb +39 -0
- data/app/cells/decidim/user_profile/footer.erb +5 -0
- data/app/cells/decidim/user_profile/header.erb +20 -0
- data/app/cells/decidim/user_profile_cell.rb +26 -0
- data/app/commands/decidim/create_omniauth_registration.rb +1 -1
- data/app/commands/decidim/create_registration.rb +2 -1
- data/app/commands/decidim/search.rb +45 -0
- data/app/controllers/concerns/decidim/devise_controllers.rb +15 -12
- data/app/controllers/concerns/decidim/http_caching_disabler.rb +21 -0
- data/app/controllers/concerns/decidim/impersonate_users.rb +1 -6
- data/app/controllers/concerns/decidim/locale_switcher.rb +1 -1
- data/app/controllers/concerns/decidim/needs_permission.rb +70 -0
- data/app/controllers/concerns/decidim/needs_tos_accepted.rb +42 -0
- data/app/controllers/concerns/decidim/participatory_space_context.rb +1 -7
- data/app/controllers/concerns/decidim/user_profile.rb +3 -1
- data/app/controllers/decidim/account_controller.rb +4 -4
- data/app/controllers/decidim/application_controller.rb +17 -8
- data/app/controllers/decidim/components/base_controller.rb +14 -9
- data/app/controllers/decidim/cookie_policy_controller.rb +0 -2
- data/app/controllers/decidim/devise/confirmations_controller.rb +13 -0
- data/app/controllers/decidim/devise/invitations_controller.rb +3 -1
- data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +9 -3
- data/app/controllers/decidim/devise/passwords_controller.rb +1 -1
- data/app/controllers/decidim/devise/registrations_controller.rb +1 -7
- data/app/controllers/decidim/doorkeeper/authorizations_controller.rb +0 -2
- data/app/controllers/decidim/doorkeeper/credentials_controller.rb +0 -1
- data/app/controllers/decidim/errors_controller.rb +0 -2
- data/app/controllers/decidim/follows_controller.rb +4 -2
- data/app/controllers/decidim/locales_controller.rb +1 -1
- data/app/controllers/decidim/messaging/conversations_controller.rb +5 -5
- data/app/controllers/decidim/newsletters_controller.rb +0 -2
- data/app/controllers/decidim/notifications_controller.rb +3 -19
- data/app/controllers/decidim/notifications_settings_controller.rb +2 -2
- data/app/controllers/decidim/pages_controller.rb +12 -10
- data/app/controllers/decidim/profiles_controller.rb +10 -4
- data/app/controllers/decidim/reports_controller.rb +14 -1
- data/app/controllers/decidim/scopes_controller.rb +3 -3
- data/app/controllers/decidim/searches_controller.rb +39 -0
- data/app/controllers/decidim/static_map_controller.rb +0 -2
- data/app/controllers/decidim/tos_controller.rb +20 -0
- data/app/controllers/decidim/widgets_controller.rb +0 -1
- data/app/forms/decidim/follow_form.rb +1 -0
- data/app/forms/decidim/registration_form.rb +2 -1
- data/app/helpers/decidim/card_helper.rb +2 -0
- data/app/helpers/decidim/cells_paginate_helper.rb +16 -0
- data/app/helpers/decidim/cta_button_helper.rb +1 -1
- data/app/helpers/decidim/decidim_form_helper.rb +4 -0
- data/app/helpers/decidim/icon_helper.rb +2 -0
- data/app/helpers/decidim/resource_helper.rb +1 -2
- data/app/helpers/decidim/scopes_helper.rb +17 -10
- data/app/helpers/decidim/searches_helper.rb +16 -0
- data/app/helpers/decidim/tooltip_helper.rb +12 -0
- data/app/models/decidim/organization.rb +10 -0
- data/app/models/decidim/permission_action.rb +40 -0
- data/app/models/decidim/searchable_resource.rb +37 -0
- data/app/models/decidim/static_page.rb +4 -0
- data/app/models/decidim/user.rb +39 -3
- data/app/permissions/decidim/default_permissions.rb +61 -0
- data/app/permissions/decidim/permissions.rb +106 -0
- data/app/permissions/decidim/user_manager_permissions.rb +24 -0
- data/app/presenters/decidim/admin_log/organization_presenter.rb +2 -1
- data/app/presenters/decidim/home_stats_presenter.rb +2 -8
- data/app/presenters/decidim/user_presenter.rb +8 -0
- data/app/services/decidim/traceability.rb +6 -9
- data/app/types/decidim/core/user_type.rb +1 -1
- data/app/views/decidim/devise/invitations/edit.html.erb +56 -10
- data/app/views/decidim/devise/registrations/new.html.erb +36 -14
- data/app/views/decidim/devise/shared/_newsletter_modal.html.erb +25 -0
- data/app/views/decidim/follows/update_button.js.erb +2 -2
- data/app/views/decidim/messaging/conversations/_message.html.erb +1 -1
- data/app/views/{pages → decidim/pages}/decidim_page.html.erb +5 -0
- data/app/views/decidim/pages/home.html.erb +17 -0
- data/app/views/{pages → decidim/pages}/home/_extended.html.erb +0 -0
- data/app/views/{pages → decidim/pages}/home/_footer_sub_hero.html.erb +0 -0
- data/app/views/{pages → decidim/pages}/home/_hero.html.erb +0 -0
- data/app/views/{pages → decidim/pages}/home/_highlighted_content_banner.html.erb +0 -0
- data/app/views/{pages → decidim/pages}/home/_highlighted_processes.html.erb +0 -0
- data/app/views/{pages → decidim/pages}/home/_statistics.html.erb +0 -0
- data/app/views/{pages → decidim/pages}/home/_sub_hero.html.erb +0 -0
- data/app/views/decidim/profiles/_followers.html.erb +5 -0
- data/app/views/decidim/profiles/_following.html.erb +5 -0
- data/app/views/decidim/profiles/_notifications.html.erb +0 -0
- data/app/views/decidim/profiles/_user.html.erb +59 -0
- data/app/views/decidim/profiles/_user_follow.erb +32 -0
- data/app/views/decidim/profiles/show.html.erb +32 -59
- data/app/views/decidim/searches/_count.html.erb +1 -0
- data/app/views/decidim/searches/_filters.html.erb +20 -0
- data/app/views/decidim/searches/_filters_small_view.html.erb +18 -0
- data/app/views/decidim/searches/_results.html.erb +5 -0
- data/app/views/decidim/searches/index.html.erb +20 -0
- data/app/views/decidim/searches/index.js.erb +5 -0
- data/app/views/decidim/shared/_address_details.html.erb +7 -9
- data/app/views/decidim/shared/_announcement.html.erb +1 -6
- data/app/views/decidim/shared/_author_reference.html.erb +1 -1
- data/app/views/decidim/shared/_follow_button.html.erb +1 -34
- data/app/views/decidim/shared/_static_map.html.erb +3 -1
- data/app/views/decidim/shared/_tags.html.erb +1 -11
- data/app/views/kaminari/decidim/_paginator.html.erb +16 -15
- data/app/views/layouts/decidim/_head.html.erb +1 -0
- data/app/views/layouts/decidim/_topbar_search.html.erb +8 -0
- data/app/views/layouts/decidim/_user_menu.html.erb +2 -2
- data/app/views/layouts/decidim/_wrapper.html.erb +3 -2
- data/config/initializers/devise.rb +1 -1
- data/config/initializers/rack_attack.rb +28 -0
- data/config/locales/ca.yml +136 -55
- data/config/locales/en.yml +135 -54
- data/config/locales/es.yml +136 -55
- data/config/locales/eu.yml +136 -54
- data/config/locales/fi.yml +135 -54
- data/config/locales/fr.yml +136 -54
- data/config/locales/gl.yml +136 -54
- data/config/locales/it.yml +136 -54
- data/config/locales/nl.yml +136 -54
- data/config/locales/pl.yml +144 -54
- data/config/locales/pt-BR.yml +136 -54
- data/config/locales/pt.yml +136 -54
- data/config/locales/ru.yml +150 -60
- data/config/locales/sv.yml +136 -54
- data/config/locales/uk.yml +146 -57
- data/config/routes.rb +11 -1
- data/db/migrate/20180209122819_create_decidim_searchable_resource.rb +21 -0
- data/db/migrate/20180508111640_add_tos_version_to_organization.rb +19 -0
- data/db/migrate/20180508111710_add_accepted_tos_version_field_to_users.rb +25 -0
- data/db/seeds.rb +33 -26
- data/lib/decidim/component_manifest.rb +35 -27
- data/lib/decidim/content_processor.rb +21 -3
- data/lib/decidim/core.rb +27 -16
- data/lib/decidim/core/engine.rb +8 -19
- data/lib/decidim/core/test.rb +2 -0
- data/lib/decidim/core/test/factories.rb +34 -4
- data/lib/decidim/core/test/shared_examples/fingerprint_examples.rb +15 -0
- data/lib/decidim/core/test/shared_examples/searchable_results_examples.rb +27 -0
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/events/base_event.rb +5 -1
- data/lib/decidim/fingerprint_calculator.rb +42 -0
- data/lib/decidim/fingerprintable.rb +63 -0
- data/lib/decidim/form_builder.rb +1 -0
- data/lib/decidim/manifest_registry.rb +4 -10
- data/lib/decidim/participable.rb +4 -0
- data/lib/decidim/participatory_space_manifest.rb +36 -0
- data/lib/decidim/participatory_space_resourceable.rb +11 -0
- data/lib/decidim/resource_manifest.rb +10 -11
- data/lib/decidim/resourceable.rb +3 -2
- data/lib/decidim/search_resource_fields_mapper.rb +93 -0
- data/lib/decidim/searchable.rb +85 -0
- data/lib/decidim/settings_manifest.rb +3 -2
- data/lib/decidim/traceable.rb +2 -0
- data/lib/decidim/view_model.rb +9 -0
- data/lib/tasks/decidim_tasks.rake +79 -1
- metadata +149 -76
- data/app/assets/stylesheets/decidim/extras/_register_form.scss +0 -9
- data/app/cells/decidim/author_box/show.erb +0 -10
- data/app/cells/decidim/author_box_cell.rb +0 -21
- data/app/cells/decidim/profile/show.erb +0 -13
- data/app/cells/decidim/profile_cell.rb +0 -17
- data/app/controllers/concerns/decidim/needs_authorization.rb +0 -46
- data/app/models/decidim/abilities/admin_ability.rb +0 -29
- data/app/models/decidim/abilities/base_ability.rb +0 -56
- data/app/models/decidim/abilities/everyone_ability.rb +0 -25
- data/app/models/decidim/abilities/participatory_process_admin_ability.rb +0 -28
- data/app/models/decidim/abilities/participatory_process_collaborator_ability.rb +0 -28
- data/app/models/decidim/abilities/participatory_process_moderator_ability.rb +0 -15
- data/app/models/decidim/abilities/user_manager_ability.rb +0 -35
- data/app/views/decidim/notifications/_notification.html.erb +0 -20
- data/app/views/decidim/notifications/index.html.erb +0 -36
- data/app/views/decidim/shared/_author.html.erb +0 -21
- data/app/views/pages/home.html.erb +0 -17
- data/db/migrate/20180613080638_rename_missing_features_to_components.rb +0 -15
- data/lib/decidim/abilities.rb +0 -7
- data/lib/decidim/abilities/participatory_process_role_ability.rb +0 -60
- data/lib/decidim/page_finder.rb +0 -49
data/lib/decidim/core/test.rb
CHANGED
@@ -21,3 +21,5 @@ require "decidim/core/test/shared_examples/user_localised_email_examples"
|
|
21
21
|
require "decidim/core/test/shared_examples/follows_examples"
|
22
22
|
require "decidim/core/test/shared_examples/simple_event"
|
23
23
|
require "decidim/core/test/shared_examples/component_type"
|
24
|
+
require "decidim/core/test/shared_examples/fingerprint_examples"
|
25
|
+
require "decidim/core/test/shared_examples/searchable_results_examples"
|
@@ -69,6 +69,14 @@ FactoryBot.define do
|
|
69
69
|
official_url { Faker::Internet.url }
|
70
70
|
highlighted_content_banner_enabled false
|
71
71
|
enable_omnipresent_banner false
|
72
|
+
tos_version { Time.current }
|
73
|
+
|
74
|
+
trait :with_tos do
|
75
|
+
after(:create) do |organization|
|
76
|
+
tos_page = Decidim::StaticPage.find_by(slug: "terms-and-conditions", organization: organization)
|
77
|
+
create(:static_page, :tos, organization: organization) if tos_page.nil?
|
78
|
+
end
|
79
|
+
end
|
72
80
|
end
|
73
81
|
|
74
82
|
factory :user, class: "Decidim::User" do
|
@@ -84,6 +92,13 @@ FactoryBot.define do
|
|
84
92
|
personal_url { Faker::Internet.url }
|
85
93
|
about { Faker::Lorem.paragraph(2) }
|
86
94
|
|
95
|
+
after(:create) do |user|
|
96
|
+
tos_page = Decidim::StaticPage.find_by(slug: "terms-and-conditions", organization: user.organization)
|
97
|
+
create(:static_page, :tos, organization: user.organization) if tos_page.nil?
|
98
|
+
user.accepted_tos_version = user.organization.tos_version
|
99
|
+
user.save
|
100
|
+
end
|
101
|
+
|
87
102
|
trait :confirmed do
|
88
103
|
confirmed_at { Time.current }
|
89
104
|
end
|
@@ -125,7 +140,7 @@ FactoryBot.define do
|
|
125
140
|
end
|
126
141
|
|
127
142
|
factory :user_group, class: "Decidim::UserGroup" do
|
128
|
-
name { Faker::Educator.course }
|
143
|
+
name { Faker::Educator.unique.course }
|
129
144
|
document_number { Faker::Number.number(8) + "X" }
|
130
145
|
phone { Faker::PhoneNumber.phone_number }
|
131
146
|
avatar { Decidim::Dev.test_file("avatar.jpg", "image/jpeg") }
|
@@ -189,6 +204,10 @@ FactoryBot.define do
|
|
189
204
|
trait :default do
|
190
205
|
slug { Decidim::StaticPage::DEFAULT_PAGES.sample }
|
191
206
|
end
|
207
|
+
|
208
|
+
trait :tos do
|
209
|
+
slug { "terms-and-conditions" }
|
210
|
+
end
|
192
211
|
end
|
193
212
|
|
194
213
|
factory :attachment_collection, class: "Decidim::AttachmentCollection" do
|
@@ -274,6 +293,7 @@ FactoryBot.define do
|
|
274
293
|
title { generate(:name) }
|
275
294
|
component { create(:component, manifest_name: "dummy") }
|
276
295
|
author { create(:user, :confirmed, organization: component.organization) }
|
296
|
+
scope { create(:scope, organization: component.organization) }
|
277
297
|
end
|
278
298
|
|
279
299
|
factory :resource_link, class: "Decidim::ResourceLink" do
|
@@ -286,10 +306,8 @@ FactoryBot.define do
|
|
286
306
|
author { build(:user, :confirmed, organization: organization) }
|
287
307
|
organization
|
288
308
|
|
289
|
-
# rubocop:disable RSpec/EmptyLineAfterSubject
|
290
|
-
# Bug in rubocop-rspec
|
291
309
|
subject { Decidim::Faker::Localized.sentence(3) }
|
292
|
-
|
310
|
+
|
293
311
|
body { Decidim::Faker::Localized.wrapped("<p>", "</p>") { Decidim::Faker::Localized.sentence(4) } }
|
294
312
|
|
295
313
|
trait :sent do
|
@@ -396,4 +414,16 @@ FactoryBot.define do
|
|
396
414
|
created_at { Time.zone.now }
|
397
415
|
scopes { "public" }
|
398
416
|
end
|
417
|
+
|
418
|
+
factory :searchable_resource, class: "Decidim::SearchableResource" do
|
419
|
+
resource { build(:dummy_resource) }
|
420
|
+
resource_id { resource.id }
|
421
|
+
resource_type { resource.class.name }
|
422
|
+
organization { resource.component.organization }
|
423
|
+
decidim_participatory_space { resource.component.participatory_space }
|
424
|
+
locale { I18n.locale }
|
425
|
+
scope { resource.scope }
|
426
|
+
content_a { Faker::Lorem.sentence }
|
427
|
+
datetime { DateTime.current }
|
428
|
+
end
|
399
429
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
shared_examples "fingerprint" do
|
4
|
+
include_context("with a component")
|
5
|
+
|
6
|
+
it "shows a fingerprint" do
|
7
|
+
visit(resource_locator(fingerprintable).path)
|
8
|
+
click_link("Check fingerprint")
|
9
|
+
|
10
|
+
within ".fingerprint-dialog" do
|
11
|
+
expect(page).to(have_content(fingerprintable.fingerprint.value))
|
12
|
+
expect(page).to(have_content(fingerprintable.fingerprint.source))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
shared_examples "searchable results" do
|
4
|
+
let(:organization) { create(:organization) }
|
5
|
+
|
6
|
+
before do
|
7
|
+
switch_to_host(organization.host)
|
8
|
+
visit decidim.root_path
|
9
|
+
end
|
10
|
+
|
11
|
+
context "when searching for indexed searchables" do
|
12
|
+
before do
|
13
|
+
expect(searchables).not_to be_empty
|
14
|
+
expect(term).not_to be_empty
|
15
|
+
|
16
|
+
fill_in "term", with: term
|
17
|
+
find("input#term").native.send_keys :enter
|
18
|
+
end
|
19
|
+
|
20
|
+
it "contains these searchables" do
|
21
|
+
expect(page).to have_current_path decidim.search_path, ignore_query: true
|
22
|
+
expect(page).to have_content(/results for the search: "#{term}"/i)
|
23
|
+
expect(page).to have_selector(".filters__section")
|
24
|
+
expect(page.find("#results-count").text.to_i).to be_positive
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/decidim/core/version.rb
CHANGED
@@ -6,6 +6,7 @@ module Decidim
|
|
6
6
|
# add more logic to a `Decidim::Notification` and are used to render them in the
|
7
7
|
# notifications dashboard and to generate other notifications (emails, for example).
|
8
8
|
class BaseEvent
|
9
|
+
extend ActiveModel::Translation
|
9
10
|
include Decidim::TranslatableAttributes
|
10
11
|
|
11
12
|
class_attribute :types
|
@@ -67,12 +68,15 @@ module Decidim
|
|
67
68
|
# event to decide based on the params.
|
68
69
|
#
|
69
70
|
# It returns false when the resource or any element in the chain is a
|
70
|
-
# `Decidim::Publicable` and it isn't published
|
71
|
+
# `Decidim::Publicable` and it isn't published or participatory_space
|
72
|
+
# is a `Decidim::Participable` and the user can't participate.
|
71
73
|
def notifiable?
|
72
74
|
return false if resource.is_a?(Decidim::Publicable) && !resource.published?
|
73
75
|
return false if participatory_space.is_a?(Decidim::Publicable) && !participatory_space&.published?
|
74
76
|
return false unless component&.published?
|
75
77
|
|
78
|
+
return false if participatory_space.is_a?(Decidim::Participable) && !participatory_space.can_participate?(user)
|
79
|
+
|
76
80
|
true
|
77
81
|
end
|
78
82
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "digest"
|
4
|
+
|
5
|
+
module Decidim
|
6
|
+
# This class will generate a unique fingerprint given an arbitrarily deep hash,
|
7
|
+
# ensuring that the same fingerprint will be generated regardless of ordering and
|
8
|
+
# whether keys are symbols or strings.
|
9
|
+
#
|
10
|
+
class FingerprintCalculator
|
11
|
+
# Public: Initializes the class with a source data to be fingerprinted.
|
12
|
+
def initialize(data)
|
13
|
+
@data = data
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: Generates a fingerprint hash.
|
17
|
+
#
|
18
|
+
# Returns a String with the fingerprint.
|
19
|
+
def value
|
20
|
+
@value ||= Digest::SHA256.hexdigest(source)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Public: Returns the fingerprint source *before* hashing, so that it can be
|
24
|
+
# inspected by the user.
|
25
|
+
#
|
26
|
+
# Returns a String with the JSON representation of the normalized data.
|
27
|
+
def source
|
28
|
+
@source ||= JSON.generate(sort_hash(@data))
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def sort_hash(hash)
|
34
|
+
return hash unless hash.is_a?(Hash)
|
35
|
+
|
36
|
+
Hash[
|
37
|
+
hash.map { |key, value| [key, sort_hash(value)] }
|
38
|
+
.sort_by { |key, _value| key }
|
39
|
+
]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module Decidim
|
6
|
+
# This module adds support functionality to be able to generate a unique fingerprint
|
7
|
+
# from a model, given some fields. Its goal is to provide a way to give an informal
|
8
|
+
# "receipt" to a user to they can detect tampering.
|
9
|
+
#
|
10
|
+
module Fingerprintable
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
class_methods do
|
14
|
+
attr_reader :fingerprint_options
|
15
|
+
|
16
|
+
# Public: Configures fingerprinting for this model.
|
17
|
+
#
|
18
|
+
# fields - An `Array` of `symbols` specifying the fields that will be part of
|
19
|
+
# the fingerprint generation.
|
20
|
+
# block - (optional) When provided, it's given an instance of the model as a
|
21
|
+
# parameter so the fingerprint can be generated in runtime.
|
22
|
+
#
|
23
|
+
# Returns nothing.
|
24
|
+
def fingerprint(fields: nil, &block)
|
25
|
+
@fingerprint_options = {}
|
26
|
+
|
27
|
+
if block_given?
|
28
|
+
@fingerprint_options[:block] = block
|
29
|
+
else
|
30
|
+
raise "You must provide a set of fields to generate the fingerprint." unless fields
|
31
|
+
@fingerprint_options[:fields] = fields
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Public: Returns an instance of `FingerprintCalculator` containing the fingerprint.
|
37
|
+
#
|
38
|
+
# Example:
|
39
|
+
#
|
40
|
+
# model.fingerprint.value # Returns the fingerprint as a String
|
41
|
+
# model.fingerprint.source # Returns the source String (usually a json) from which
|
42
|
+
# # the fingerprint is generated.
|
43
|
+
def fingerprint
|
44
|
+
@fingerprint ||= FingerprintCalculator.new(fingerprint_data)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def fingerprint_data
|
50
|
+
options = self.class.fingerprint_options
|
51
|
+
|
52
|
+
if options[:block]
|
53
|
+
options[:block].call(self)
|
54
|
+
elsif options[:fields]
|
55
|
+
options[:fields].each_with_object({}) do |field, result|
|
56
|
+
result[field] = send(field)
|
57
|
+
end
|
58
|
+
else
|
59
|
+
raise "Fingerprinting needs to be set up via the `fingerprint` class method."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/decidim/form_builder.rb
CHANGED
@@ -229,6 +229,7 @@ module Decidim
|
|
229
229
|
picker_options[:class] += " is-invalid-input" if error?(attribute)
|
230
230
|
|
231
231
|
items = object.send(attribute).collect { |item| [item, yield(item)] }
|
232
|
+
|
232
233
|
template = ""
|
233
234
|
template += label(attribute, label_for(attribute) + required_for_attribute(attribute)) unless options[:label] == false
|
234
235
|
template += @template.render("decidim/widgets/data_picker", picker_options: picker_options, prompt_params: prompt_params, items: items)
|
@@ -21,16 +21,10 @@ module Decidim
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def find(name)
|
24
|
-
manifests.find
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@resource_manifests ||= manifests.flat_map(&:resource_manifests)
|
29
|
-
end
|
30
|
-
|
31
|
-
def find_resource_manifest(resource_name_or_klass)
|
32
|
-
resource_manifests.find do |manifest|
|
33
|
-
manifest.model_class == resource_name_or_klass || manifest.name.to_s == resource_name_or_klass.to_s
|
24
|
+
manifests.find do |manifest|
|
25
|
+
manifest.try(:model_class_name) == name.to_s ||
|
26
|
+
manifest.name.to_s == name.to_s ||
|
27
|
+
manifest.name.to_s.pluralize == name.to_s
|
34
28
|
end
|
35
29
|
end
|
36
30
|
|
data/lib/decidim/participable.rb
CHANGED
@@ -28,6 +28,18 @@ module Decidim
|
|
28
28
|
# engine's assets path.
|
29
29
|
attribute :icon, String
|
30
30
|
|
31
|
+
# The name of the class that handles the permissions for this space. It will
|
32
|
+
# probably have the form of `Decidim::<MySpace>::Permissions`.
|
33
|
+
attribute :permissions_class_name, String, default: "Decidim::DefaultPermissions"
|
34
|
+
|
35
|
+
# The cell path to use to render the card of a resource.
|
36
|
+
attribute :card, String
|
37
|
+
|
38
|
+
# A path with the `scss` stylesheet this engine provides. It is used to
|
39
|
+
# mix this engine's stylesheets with the main app's stylesheets so it can
|
40
|
+
# use the scss variables and mixins provided by Decidim::Core.
|
41
|
+
attribute :stylesheet, String, default: nil
|
42
|
+
|
31
43
|
validates :name, presence: true
|
32
44
|
|
33
45
|
# A context used to set the layout and behavior of a participatory space. Full documentation can
|
@@ -67,6 +79,7 @@ module Decidim
|
|
67
79
|
#
|
68
80
|
# Returns nothing.
|
69
81
|
def seed!
|
82
|
+
print "Creating seeds for the #{name} space...\n" unless Rails.env.test?
|
70
83
|
@seeds&.call
|
71
84
|
end
|
72
85
|
|
@@ -85,5 +98,28 @@ module Decidim
|
|
85
98
|
def participatory_spaces(&block)
|
86
99
|
@participatory_spaces ||= block
|
87
100
|
end
|
101
|
+
|
102
|
+
# Public: Finds the permission class from its name, using the
|
103
|
+
# `permissions_class_name` attribute. If the class does not exist,
|
104
|
+
# it raises an exception. If the class name is not set, it returns nil.
|
105
|
+
#
|
106
|
+
# Returns a Class.
|
107
|
+
def permissions_class
|
108
|
+
permissions_class_name&.constantize
|
109
|
+
end
|
110
|
+
|
111
|
+
# Public: Registers a resource. Exposes a DSL defined by
|
112
|
+
# `Decidim::ResourceManifest`.
|
113
|
+
#
|
114
|
+
# Resource manifests are a way to expose a resource from one engine to
|
115
|
+
# the whole system. This way resources can be linked between them.
|
116
|
+
#
|
117
|
+
# name - A name for that resource. Should be singular (ie not plural).
|
118
|
+
# block - A Block that will be called to set the Resource attributes.
|
119
|
+
#
|
120
|
+
# Returns nothing.
|
121
|
+
def register_resource(name, &block)
|
122
|
+
Decidim.register_resource(name, &block)
|
123
|
+
end
|
88
124
|
end
|
89
125
|
end
|
@@ -26,6 +26,8 @@ module Decidim
|
|
26
26
|
# An association with all the links that are originated from this model.
|
27
27
|
has_many :participatory_space_resource_links_from, as: :from, class_name: "Decidim::ParticipatorySpaceLink"
|
28
28
|
|
29
|
+
delegate :resource_manifest, to: :class
|
30
|
+
|
29
31
|
# Finds all the linked resources to or from this model for a given resource
|
30
32
|
# name and link name.
|
31
33
|
#
|
@@ -76,5 +78,14 @@ module Decidim
|
|
76
78
|
end
|
77
79
|
end
|
78
80
|
end
|
81
|
+
|
82
|
+
class_methods do
|
83
|
+
# Finds the resource manifest for the model.
|
84
|
+
#
|
85
|
+
# Returns a Decidim::ResourceManifest
|
86
|
+
def resource_manifest
|
87
|
+
Decidim.find_resource_manifest(self)
|
88
|
+
end
|
89
|
+
end
|
79
90
|
end
|
80
91
|
end
|
@@ -8,7 +8,7 @@ module Decidim
|
|
8
8
|
# used directly, you should use `register_resource` inside a component.
|
9
9
|
#
|
10
10
|
# Example:
|
11
|
-
# component.register_resource do |resource|
|
11
|
+
# component.register_resource(:my_model) do |resource|
|
12
12
|
# resource.model_class = Decidim::MyEngine::MyModel
|
13
13
|
# resource.template = "decidim/myengine/myengine/linked_models"
|
14
14
|
# end
|
@@ -30,19 +30,25 @@ module Decidim
|
|
30
30
|
# When not explicitly set, it will use the model name.
|
31
31
|
attribute :route_name, String
|
32
32
|
|
33
|
-
# The template to use to render the collection of
|
33
|
+
# The template to use to render the collection of the resource.
|
34
34
|
attribute :template, String
|
35
35
|
|
36
|
-
|
36
|
+
# The main card to render an instance of the resource.
|
37
|
+
attribute :card, String
|
38
|
+
|
39
|
+
validates :model_class_name, :route_name, :name, presence: true
|
37
40
|
|
38
41
|
# Finds an ActiveRecord::Relation of the resource `model_class`, scoped to the
|
39
42
|
# given component. This way you can find resources from another engine without
|
40
|
-
# actually coupling both engines.
|
43
|
+
# actually coupling both engines. If no `component_manifest` is set for this
|
44
|
+
# manifest, it returns an empty collection.
|
41
45
|
#
|
42
46
|
# component - a Decidim::Component
|
43
47
|
#
|
44
48
|
# Returns an ActiveRecord::Relation.
|
45
49
|
def resource_scope(component)
|
50
|
+
return model_class.none unless component_manifest
|
51
|
+
|
46
52
|
component_ids = Decidim::Component.where(participatory_space: component.participatory_space, manifest_name: component_manifest.name).pluck(:id)
|
47
53
|
return model_class.none if component_ids.empty?
|
48
54
|
|
@@ -57,13 +63,6 @@ module Decidim
|
|
57
63
|
model_class_name.constantize
|
58
64
|
end
|
59
65
|
|
60
|
-
# The name of the resource we are exposing.
|
61
|
-
#
|
62
|
-
# Returns a String.
|
63
|
-
def name
|
64
|
-
super || model_class_name.demodulize.underscore.pluralize.to_sym
|
65
|
-
end
|
66
|
-
|
67
66
|
# The name of the named Rails route to create the url to the resource.
|
68
67
|
#
|
69
68
|
# Returns a String.
|