decidim-core 0.9.3 → 0.10.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/javascripts/decidim/append_redirect_url_to_modals.js.es6 +1 -1
- data/app/assets/javascripts/decidim/data_picker.js.es6 +32 -28
- data/app/assets/javascripts/decidim/form_filter.component.js.es6 +2 -2
- data/app/assets/javascripts/decidim/foundation.js.es6 +1 -2
- data/app/assets/stylesheets/decidim/_decidim.scss +6 -1
- data/app/assets/stylesheets/decidim/modules/_address.scss +4 -0
- data/app/assets/stylesheets/decidim/modules/_block-banner.scss +39 -0
- data/app/assets/stylesheets/decidim/modules/_buttons.scss +76 -1
- data/app/assets/stylesheets/decidim/modules/_callout.scss +4 -0
- data/app/assets/stylesheets/decidim/modules/_cards.scss +117 -16
- data/app/assets/stylesheets/decidim/modules/_collapsible-list.scss +19 -0
- data/app/assets/stylesheets/decidim/modules/_data-picker.scss +0 -1
- data/app/assets/stylesheets/decidim/modules/_docs-manager.scss +16 -0
- data/app/assets/stylesheets/decidim/modules/_icons.scss +13 -4
- data/app/assets/stylesheets/decidim/modules/_margins.scss +39 -0
- data/app/assets/stylesheets/decidim/modules/_modules.scss +4 -0
- data/app/assets/stylesheets/decidim/modules/_navbar.scss +26 -0
- data/app/assets/stylesheets/decidim/modules/_process-phase.scss +49 -0
- data/app/assets/stylesheets/decidim/modules/_reveal.scss +39 -0
- data/app/assets/stylesheets/decidim/modules/_typography.scss +45 -0
- data/app/assets/stylesheets/decidim/modules/_wizard-steps.scss +45 -0
- data/app/assets/stylesheets/decidim/utils/_helpers.scss +14 -0
- data/app/assets/stylesheets/decidim/utils/_mixins.scss +34 -0
- data/app/assets/stylesheets/decidim/utils/_settings.scss +6 -3
- data/app/commands/decidim/create_report.rb +2 -2
- data/app/controllers/decidim/devise/invitations_controller.rb +1 -1
- data/app/controllers/decidim/features/base_controller.rb +1 -1
- data/app/controllers/decidim/locales_controller.rb +1 -1
- data/app/forms/decidim/registration_form.rb +1 -1
- data/app/helpers/decidim/decidim_form_helper.rb +26 -1
- data/app/helpers/decidim/meta_tags_helper.rb +2 -0
- data/app/helpers/decidim/resource_reference_helper.rb +24 -0
- data/app/helpers/decidim/scopes_helper.rb +22 -4
- data/app/helpers/decidim/view_hooks_helper.rb +6 -3
- data/app/mailers/decidim/messaging/conversation_mailer.rb +2 -0
- data/app/models/decidim/abilities/base_ability.rb +1 -1
- data/app/models/decidim/action_log.rb +57 -0
- data/app/models/decidim/area.rb +25 -0
- data/app/models/decidim/area_type.rb +20 -0
- data/app/models/decidim/attachment.rb +3 -0
- data/app/models/decidim/attachment_collection.rb +16 -0
- data/app/models/decidim/authorization.rb +1 -0
- data/app/models/decidim/categorization.rb +2 -0
- data/app/models/decidim/category.rb +8 -0
- data/app/models/decidim/feature.rb +6 -1
- data/app/models/decidim/moderation.rb +7 -0
- data/app/models/decidim/newsletter.rb +7 -0
- data/app/models/decidim/organization.rb +9 -0
- data/app/models/decidim/participatory_process_user_role.rb +9 -0
- data/app/models/decidim/resource_link.rb +8 -1
- data/app/models/decidim/scope.rb +7 -0
- data/app/models/decidim/static_page.rb +7 -0
- data/app/models/decidim/user.rb +5 -1
- data/app/models/decidim/user_group.rb +7 -0
- data/app/presenters/decidim/admin_log/feature_presenter.rb +43 -0
- data/app/presenters/decidim/admin_log/moderation_presenter.rb +48 -0
- data/app/presenters/decidim/admin_log/newsletter_presenter.rb +47 -0
- data/app/presenters/decidim/admin_log/newsletter_resource_presenter.rb +18 -0
- data/app/presenters/decidim/admin_log/organization_presenter.rb +84 -0
- data/app/presenters/decidim/admin_log/scope_presenter.rb +54 -0
- data/app/presenters/decidim/admin_log/static_page_presenter.rb +48 -0
- data/app/presenters/decidim/admin_log/static_page_resource_presenter.rb +18 -0
- data/app/presenters/decidim/admin_log/user_group_presenter.rb +31 -0
- data/app/presenters/decidim/admin_log/user_presenter.rb +59 -0
- data/app/presenters/decidim/area_presenter.rb +14 -0
- data/app/presenters/decidim/area_type_presenter.rb +14 -0
- data/app/presenters/decidim/category_presenter.rb +14 -0
- data/app/presenters/decidim/log/base_presenter.rb +253 -0
- data/app/presenters/decidim/log/diff_presenter.rb +120 -0
- data/app/presenters/decidim/log/resource_presenter.rb +71 -0
- data/app/presenters/decidim/log/space_presenter.rb +63 -0
- data/app/presenters/decidim/log/user_presenter.rb +85 -0
- data/app/presenters/decidim/log/value_types/area_presenter.rb +28 -0
- data/app/presenters/decidim/log/value_types/date_presenter.rb +20 -0
- data/app/presenters/decidim/log/value_types/default_presenter.rb +43 -0
- data/app/presenters/decidim/log/value_types/locale_presenter.rb +20 -0
- data/app/presenters/decidim/log/value_types/percentage_presenter.rb +21 -0
- data/app/presenters/decidim/log/value_types/scope_presenter.rb +28 -0
- data/app/presenters/decidim/log/value_types/scope_type_presenter.rb +28 -0
- data/app/presenters/decidim/user_presenter.rb +1 -1
- data/app/services/decidim/action_authorizer.rb +1 -1
- data/app/services/decidim/action_logger.rb +108 -0
- data/app/services/decidim/events_manager.rb +1 -1
- data/app/services/decidim/log/diff_changeset_calculator.rb +135 -0
- data/app/services/decidim/resource_search.rb +2 -8
- data/app/services/decidim/settings_change.rb +31 -0
- data/app/services/decidim/traceability.rb +57 -11
- data/app/types/decidim/core/component_type.rb +12 -0
- data/app/types/decidim/core/date_time_type.rb +12 -0
- data/app/types/decidim/core/date_type.rb +13 -0
- data/app/types/decidim/core/decidim_type.rb +23 -0
- data/app/types/decidim/core/localized_string_type.rb +14 -0
- data/app/types/decidim/core/organization_type.rb +20 -0
- data/app/types/decidim/core/participatory_space_type.rb +12 -0
- data/app/types/decidim/core/session_type.rb +19 -0
- data/app/types/decidim/core/statistic_type.rb +22 -0
- data/app/types/decidim/core/translated_field_type.rb +45 -0
- data/app/types/decidim/core/user_group_type.rb +39 -0
- data/app/types/decidim/core/user_type.rb +41 -0
- data/app/validators/etiquette_validator.rb +1 -1
- data/app/views/decidim/application/_attachments.html.erb +4 -0
- data/app/views/decidim/application/_collection.html.erb +14 -0
- data/app/views/decidim/application/_document.html.erb +19 -0
- data/app/views/decidim/application/_documents.html.erb +8 -23
- data/app/views/decidim/shared/_announcement.html.erb +3 -2
- data/app/views/decidim/shared/_tags.html.erb +1 -0
- data/app/views/decidim/widgets/_data_picker.html.erb +6 -0
- data/app/views/layouts/decidim/mailer.html.erb +2 -2
- data/config/initializers/devise.rb +3 -3
- data/config/locales/ca.yml +65 -11
- data/config/locales/en.yml +64 -10
- data/config/locales/es.yml +66 -12
- data/config/locales/eu.yml +61 -10
- data/config/locales/fi.yml +64 -10
- data/config/locales/fr.yml +64 -10
- data/config/locales/gl.yml +64 -10
- data/config/locales/it.yml +64 -10
- data/config/locales/nl.yml +64 -10
- data/config/locales/pl.yml +60 -10
- data/config/locales/pt-BR.yml +64 -10
- data/config/locales/pt.yml +64 -10
- data/config/locales/sv.yml +64 -10
- data/config/locales/uk.yml +72 -0
- data/db/migrate/20170215115407_add_organization_custom_reference.rb +1 -1
- data/db/migrate/20170313095436_add_available_authorizations_to_organization.rb +1 -1
- data/db/migrate/20171207182729_create_decidim_attachment_collections.rb +12 -0
- data/db/migrate/20180130093153_add_action_log.rb +18 -0
- data/db/migrate/20180206143340_fix_reference_for_all_resources.rb +13 -0
- data/db/migrate/20180215104821_create_decidim_area_types.rb +11 -0
- data/db/migrate/20180215104945_create_decidim_areas.rb +12 -0
- data/db/migrate/20180221101934_fix_nickname_index.rb +1 -1
- data/db/migrate/20180226140756_add_version_to_action_logs.rb +19 -0
- data/db/migrate/20180314085339_rename_maximum_votes_per_proposal_to_threshold_per_proposal.rb +27 -0
- data/db/migrate/20180326075746_change_event_name_and_class_to_rename_to_publish_proposal_event.rb +17 -0
- data/db/seeds.rb +28 -0
- data/lib/decidim/abilities/participatory_process_role_ability.rb +2 -2
- data/lib/decidim/api/author_interface.rb +25 -0
- data/lib/decidim/api/component_interface.rb +16 -0
- data/lib/decidim/api/participatory_space_interface.rb +38 -0
- data/lib/decidim/authorable.rb +8 -0
- data/lib/decidim/core.rb +27 -9
- data/lib/decidim/core/engine.rb +3 -4
- data/lib/decidim/core/test.rb +2 -0
- data/lib/decidim/core/test/factories.rb +62 -6
- data/lib/decidim/core/test/shared_examples/announcements_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +47 -5
- data/lib/decidim/core/test/shared_examples/component_type.rb +7 -0
- data/lib/decidim/core/test/shared_examples/has_attachment_collections.rb +63 -0
- data/lib/decidim/core/test/shared_examples/has_attachments.rb +21 -0
- data/lib/decidim/core/test/shared_examples/has_reference.rb +1 -1
- data/lib/decidim/core/test/shared_examples/simple_event.rb +27 -1
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/events/author_event.rb +1 -1
- data/lib/decidim/events/base_event.rb +1 -1
- data/lib/decidim/events/simple_event.rb +21 -0
- data/lib/decidim/exporters/excel.rb +1 -1
- data/lib/decidim/feature_manifest.rb +2 -0
- data/lib/decidim/form_builder.rb +37 -3
- data/lib/decidim/has_attachment_collections.rb +18 -0
- data/lib/decidim/has_attachments.rb +14 -0
- data/lib/decidim/has_category.rb +5 -0
- data/lib/decidim/has_reference.rb +4 -4
- data/lib/decidim/loggable.rb +32 -0
- data/lib/decidim/participable.rb +0 -2
- data/lib/decidim/participatory_space_manifest.rb +2 -0
- data/lib/decidim/publicable.rb +2 -2
- data/lib/decidim/query_extensions.rb +46 -14
- data/lib/decidim/resourceable.rb +15 -6
- data/lib/decidim/scopable.rb +35 -1
- data/lib/decidim/scopable_feature.rb +16 -0
- data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.ca.js +0 -0
- data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.es.js +0 -0
- data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.eu.js +0 -0
- data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.fi.js +0 -0
- data/vendor/assets/javascripts/leaflet.markercluster.js +0 -0
- metadata +91 -38
- data/app/commands/decidim/remove_admin.rb +0 -25
- data/app/helpers/decidim/feature_reference_helper.rb +0 -25
- data/lib/decidim/core/api.rb +0 -13
- data/lib/decidim/core/api/author_interface.rb +0 -18
- data/lib/decidim/core/api/decidim_type.rb +0 -17
- data/lib/decidim/core/api/localized_string_type.rb +0 -12
- data/lib/decidim/core/api/process_step_type.rb +0 -19
- data/lib/decidim/core/api/process_type.rb +0 -17
- data/lib/decidim/core/api/session_type.rb +0 -17
- data/lib/decidim/core/api/translated_field_type.rb +0 -43
- data/lib/decidim/core/api/user_group_type.rb +0 -37
- data/lib/decidim/core/api/user_type.rb +0 -39
- data/lib/decidim/devise_failure_app.rb +0 -36
- data/lib/decidim/has_scope.rb +0 -25
- data/lib/decidim/i18n_exceptions.rb +0 -15
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Log
|
5
|
+
module ValueTypes
|
6
|
+
# This class presents the given value as a percentage. Check
|
7
|
+
# the `DefaultPresenter` for more info on how value
|
8
|
+
# presenters work.
|
9
|
+
class PercentagePresenter < DefaultPresenter
|
10
|
+
# Public: Presents the value as a percentage. For clarity,
|
11
|
+
# it strips the insignificant zeros.
|
12
|
+
#
|
13
|
+
# Returns an HTML-safe String.
|
14
|
+
def present
|
15
|
+
return unless value
|
16
|
+
h.number_to_percentage(value, strip_insignificant_zeros: true)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Log
|
5
|
+
module ValueTypes
|
6
|
+
# This class presents the given value as a Decidim::Scope. Check
|
7
|
+
# the `DefaultPresenter` for more info on how value
|
8
|
+
# presenters work.
|
9
|
+
class ScopePresenter < DefaultPresenter
|
10
|
+
# Public: Presents the value as a Decidim::Scope. If the scope can
|
11
|
+
# be found, it shows its title. Otherwise it shows its ID.
|
12
|
+
#
|
13
|
+
# Returns an HTML-safe String.
|
14
|
+
def present
|
15
|
+
return unless value
|
16
|
+
return h.translated_attribute(scope.name) if scope
|
17
|
+
I18n.t("not_found", id: value, scope: "decidim.log.value_types.scope_presenter")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def scope
|
23
|
+
@scope ||= Decidim::Scope.where(id: value).first
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Log
|
5
|
+
module ValueTypes
|
6
|
+
# This class presents the given value as a Decidim::ScopeType. Check
|
7
|
+
# the `DefaultPresenter` for more info on how value
|
8
|
+
# presenters work.
|
9
|
+
class ScopeTypePresenter < DefaultPresenter
|
10
|
+
# Public: Presents the value as a Percentage. If the scope can
|
11
|
+
# be found, it shows its title. Otherwise it shows its ID.
|
12
|
+
#
|
13
|
+
# Returns an HTML-safe String.
|
14
|
+
def present
|
15
|
+
return unless value
|
16
|
+
return h.translated_attribute(scope_type.name) if scope_type
|
17
|
+
I18n.t("not_found", id: value, scope: "decidim.log.value_types.scope_type_presenter")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def scope_type
|
23
|
+
@scope_type ||= Decidim::ScopeType.where(id: value).first
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -43,7 +43,7 @@ module Decidim
|
|
43
43
|
def authorization
|
44
44
|
return nil unless user && authorization_handler_name
|
45
45
|
|
46
|
-
@authorization ||= Verifications::Authorizations.new(user: user, name: authorization_handler_name).first
|
46
|
+
@authorization ||= Verifications::Authorizations.new(organization: user.organization, user: user, name: authorization_handler_name).first
|
47
47
|
end
|
48
48
|
|
49
49
|
def authorization_handler
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
# Use this class to log actions by any user. You probably shouldn't
|
5
|
+
# use this class dfirectly, but rather use `Decidim.traceability` instead.
|
6
|
+
# Check the docs on `Decidim::Traceability` for more info.
|
7
|
+
#
|
8
|
+
# Usage:
|
9
|
+
#
|
10
|
+
# ActionLogger.log(:create, user, new_proposal, extra_data)
|
11
|
+
class ActionLogger
|
12
|
+
# Public: Logs the given `action` by the given `user` on the given `resource`.
|
13
|
+
# Delegates the work to the instance method.
|
14
|
+
#
|
15
|
+
# action - a String representing the name of the action
|
16
|
+
# user - the Decidim::User that performed the action
|
17
|
+
# resource - the resource onn which the action was performed
|
18
|
+
# version_id - the ID of the `PaperTrail::Version` that was created on that action
|
19
|
+
# resource_extra - a Hash with resource_extra info to be recorded
|
20
|
+
#
|
21
|
+
# Returns the newly created `Decidim::ActionLog` resource.
|
22
|
+
def self.log(action, user, resource, version_id, resource_extra = {})
|
23
|
+
new(action, user, resource, version_id, resource_extra).log!
|
24
|
+
end
|
25
|
+
|
26
|
+
# Public: Initializes the instance.
|
27
|
+
#
|
28
|
+
# action - a String representing the name of the action
|
29
|
+
# user - the Decidim::User that performed the action
|
30
|
+
# resource - the resource onn which the action was performed
|
31
|
+
# version_id - the ID of the `PaperTrail::Version` that was created on that action
|
32
|
+
# resource_extra - a Hash with resource_extra info to be recorded
|
33
|
+
def initialize(action, user, resource, version_id = nil, resource_extra = {})
|
34
|
+
@action = action
|
35
|
+
@user = user
|
36
|
+
@resource = resource
|
37
|
+
@version_id = version_id
|
38
|
+
@resource_extra = resource_extra
|
39
|
+
end
|
40
|
+
|
41
|
+
# Public: Logs the given `action` by the given `user` on the given
|
42
|
+
# `resource`.
|
43
|
+
#
|
44
|
+
# Returns the newly created `Decidim::ActionLog` resource.
|
45
|
+
def log!
|
46
|
+
Decidim::ActionLog.create!(
|
47
|
+
user: user,
|
48
|
+
organization: organization,
|
49
|
+
action: action,
|
50
|
+
resource: resource,
|
51
|
+
participatory_space: participatory_space,
|
52
|
+
feature: feature,
|
53
|
+
version_id: version_id,
|
54
|
+
extra: extra_data
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
attr_reader :action, :user, :resource, :resource_extra, :version_id
|
61
|
+
|
62
|
+
def organization
|
63
|
+
user.organization
|
64
|
+
end
|
65
|
+
|
66
|
+
def feature
|
67
|
+
resource.feature if resource.respond_to?(:feature)
|
68
|
+
end
|
69
|
+
|
70
|
+
def participatory_space
|
71
|
+
return feature.participatory_space if feature.respond_to?(:participatory_space)
|
72
|
+
resource.participatory_space if resource.respond_to?(:participatory_space)
|
73
|
+
end
|
74
|
+
|
75
|
+
def title_for(resource)
|
76
|
+
resource.try(:title) || resource.try(:name) || resource.try(:subject)
|
77
|
+
end
|
78
|
+
|
79
|
+
def participatory_space_manifest_name
|
80
|
+
participatory_space.try(:class).try(:participatory_space_manifest).try(:name)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Private: Defines some extra data that will be saved in the action log `extra`
|
84
|
+
# field.
|
85
|
+
#
|
86
|
+
# Returns a Hash.
|
87
|
+
def extra_data
|
88
|
+
{
|
89
|
+
feature: {
|
90
|
+
manifest_name: feature.try(:manifest_name),
|
91
|
+
title: title_for(feature)
|
92
|
+
}.compact,
|
93
|
+
participatory_space: {
|
94
|
+
manifest_name: participatory_space_manifest_name,
|
95
|
+
title: title_for(participatory_space)
|
96
|
+
}.compact,
|
97
|
+
resource: {
|
98
|
+
title: title_for(resource)
|
99
|
+
}.compact,
|
100
|
+
user: {
|
101
|
+
ip: user.current_sign_in_ip,
|
102
|
+
name: user.name,
|
103
|
+
nickname: user.nickname
|
104
|
+
}.compact
|
105
|
+
}.deep_merge(resource_extra)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Log
|
5
|
+
# This class takes a changeset from a `PaperTrail::Version` and
|
6
|
+
# a field mapping and cleans the changeset so it can be easily
|
7
|
+
# rendered in the log section. It is intended to be used by the
|
8
|
+
# `Decidim::Log::BasePresenter` class, which handles most of the
|
9
|
+
# work to render a log.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# version = resource.versions.last
|
14
|
+
# fields_mapping = { updated_at: :date, title: :string }
|
15
|
+
# i18n_labels_scope = "activemodel.attributes.my_resource"
|
16
|
+
#
|
17
|
+
# DiffChangesetCalculator
|
18
|
+
# .new(version.changeset, fields_mapping, i18n_labels_scope)
|
19
|
+
# .changeset
|
20
|
+
class DiffChangesetCalculator
|
21
|
+
# original_changeset - a `changeset` from a PaperTrail::Version instance
|
22
|
+
# fields_mapping - a Hash mapping attribute names and a type to render them
|
23
|
+
# i18n_labels_scope - a String representing the I18n scope where the attribtue
|
24
|
+
# labels can be found
|
25
|
+
def initialize(original_changeset, fields_mapping, i18n_labels_scope)
|
26
|
+
@original_changeset = original_changeset
|
27
|
+
@fields_mapping = fields_mapping
|
28
|
+
@i18n_labels_scope = i18n_labels_scope
|
29
|
+
end
|
30
|
+
|
31
|
+
# Calculates the changeset that should be rendered, from the
|
32
|
+
# `original_changeset` and the `fields_mapping` values.
|
33
|
+
#
|
34
|
+
# Returns an Array of Hashes.
|
35
|
+
def changeset
|
36
|
+
original_changeset.inject([]) do |diff, (attribute, values)|
|
37
|
+
attribute = attribute.to_sym
|
38
|
+
|
39
|
+
type = :default
|
40
|
+
type = fields_mapping[attribute] unless fields_mapping.nil?
|
41
|
+
|
42
|
+
if type.blank? || values[0] == values[1]
|
43
|
+
diff
|
44
|
+
else
|
45
|
+
diff.concat(calculate_changeset(attribute, values, type))
|
46
|
+
end
|
47
|
+
end.compact
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
attr_reader :fields_mapping, :original_changeset, :i18n_labels_scope
|
53
|
+
|
54
|
+
# Private: Generates the data structure for the changeset attribute,
|
55
|
+
# needed so that the attribute can be rendered in the diff.
|
56
|
+
#
|
57
|
+
# attribute - the name of the attribute
|
58
|
+
# values - an Array of the attribute values: [old_value, new_value]
|
59
|
+
# type - a symbol or a String representing the value type presenter
|
60
|
+
#
|
61
|
+
# Returns an array of hashes.
|
62
|
+
def calculate_changeset(attribute, values, type)
|
63
|
+
return generate_i18n_changeset(attribute, values, type) if type == :i18n
|
64
|
+
|
65
|
+
generate_changeset(attribute, values, type)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Private: Generates the data structure for an i18n attribute,
|
69
|
+
# needed so that the attribute can be rendered in the diff.
|
70
|
+
# Sets the label for the given attribute as: `AttributeName (locale)`.
|
71
|
+
#
|
72
|
+
# attribute - the name of the attribute
|
73
|
+
# values - an Array of the attribute values: [old_value, new_value]
|
74
|
+
# type - a symbol or a String representing the value type presenter
|
75
|
+
#
|
76
|
+
# Returns an array of hashes.
|
77
|
+
def generate_i18n_changeset(attribute, values, type)
|
78
|
+
values.map! { |value| value.is_a?(String) ? JSON.parse(value) : value }
|
79
|
+
|
80
|
+
locales = values[0].to_h.keys | values[1].to_h.keys
|
81
|
+
locales.flat_map do |locale|
|
82
|
+
previous_value = values.first.try(:[], locale)
|
83
|
+
new_value = values.last.try(:[], locale)
|
84
|
+
if previous_value == new_value
|
85
|
+
nil
|
86
|
+
else
|
87
|
+
label = generate_label(attribute, locale)
|
88
|
+
generate_changeset(attribute, [previous_value, new_value], type, label)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Private: Generates the structure needed for the given attribute,
|
94
|
+
# values, type and label.
|
95
|
+
#
|
96
|
+
# attribute - the name of the attribute
|
97
|
+
# values - an Array of the attribute values: [old_value, new_value]
|
98
|
+
# type - a symbol or a String representing the value type presenter
|
99
|
+
# label - the label for the current attribute
|
100
|
+
#
|
101
|
+
# Returns an array of Hashes.
|
102
|
+
def generate_changeset(attribute, values, type, label = nil)
|
103
|
+
[
|
104
|
+
{
|
105
|
+
attribute_name: attribute,
|
106
|
+
label: label || generate_label(attribute),
|
107
|
+
new_value: values[1],
|
108
|
+
previous_value: values[0],
|
109
|
+
type: type
|
110
|
+
}
|
111
|
+
]
|
112
|
+
end
|
113
|
+
|
114
|
+
# Generates the label for the given attribute. If the `locale` is set,
|
115
|
+
# it appends the locale at the end: `AttributeName (LocaleName)`.
|
116
|
+
#
|
117
|
+
# attribute - A Symbol representing the attribute name. It will retrive
|
118
|
+
# this key from the I18n scope set at `i18n_labels_scope`.
|
119
|
+
# locale - a String representing the name of the locale.
|
120
|
+
#
|
121
|
+
# Returns a String.
|
122
|
+
def generate_label(attribute, locale = nil)
|
123
|
+
label = if i18n_labels_scope
|
124
|
+
I18n.t(attribute, scope: i18n_labels_scope, default: attribute.to_s.humanize)
|
125
|
+
else
|
126
|
+
attribute.to_s.humanize
|
127
|
+
end
|
128
|
+
return label unless locale
|
129
|
+
|
130
|
+
locale_name = I18n.t("locale.name", locale: locale)
|
131
|
+
"#{label} (#{locale_name})"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -47,15 +47,9 @@ module Decidim
|
|
47
47
|
|
48
48
|
conditions = []
|
49
49
|
conditions << "decidim_scope_id IS NULL" if clean_scope_ids.delete("global")
|
50
|
+
conditions.concat(["? = ANY(decidim_scopes.part_of)"] * clean_scope_ids.count) if clean_scope_ids.any?
|
50
51
|
|
51
|
-
clean_scope_ids.map
|
52
|
-
|
53
|
-
if clean_scope_ids.any?
|
54
|
-
conditions.concat(["? = ANY(decidim_scopes.part_of)"] * clean_scope_ids.count)
|
55
|
-
conditions << "decidim_scopes.id IN (?)"
|
56
|
-
end
|
57
|
-
|
58
|
-
query.includes(:scope).references(:decidim_scopes).where(conditions.join(" OR "), *clean_scope_ids, clean_scope_ids)
|
52
|
+
query.includes(:scope).references(:decidim_scopes).where(conditions.join(" OR "), *clean_scope_ids.map(&:to_i))
|
59
53
|
end
|
60
54
|
|
61
55
|
private
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
# This is a helper class in order to publish feature and settings changes
|
5
|
+
# so that components can react to these changes and send notifications to users.
|
6
|
+
class SettingsChange
|
7
|
+
# Publishes a change to ActiveSupport::Notifications.
|
8
|
+
#
|
9
|
+
# feature - The Decidim::Feature where the changes have been applied.
|
10
|
+
# previous_settings - A Hash or a Decidim::SettingsManifest schema with the settings before changing them.
|
11
|
+
# current_settings - A Hash or a Decidim::SettingsManifest schema with the current settings.
|
12
|
+
def self.publish(feature, previous_settings, current_settings)
|
13
|
+
ActiveSupport::Notifications.publish(
|
14
|
+
"decidim.settings_change.#{feature.manifest_name}",
|
15
|
+
feature_id: feature.id,
|
16
|
+
previous_settings: previous_settings.to_h.deep_symbolize_keys,
|
17
|
+
current_settings: current_settings.to_h.deep_symbolize_keys
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Creates a subscription to setting changes.
|
22
|
+
#
|
23
|
+
# scope - The String manifest name of the component so it only receives relevant changes.
|
24
|
+
# block - The block to be executed when an event is received.
|
25
|
+
def self.subscribe(scope, &block)
|
26
|
+
ActiveSupport::Notifications.subscribe(/^decidim\.settings_change\.#{scope}/) do |_event_name, data|
|
27
|
+
block.call(data)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -24,11 +24,12 @@ module Decidim
|
|
24
24
|
#
|
25
25
|
# klass - An ActiveRecord class that implements `Decidim::Traceable`
|
26
26
|
# author - An object that implements `to_gid` or a String
|
27
|
-
# params - a Hash
|
27
|
+
# params - a Hash with the attributes of the new resource
|
28
|
+
# extra_log_info - a Hash with extra info that will be saved to the log
|
28
29
|
#
|
29
30
|
# Returns an instance of `klass`.
|
30
|
-
def create(klass, author, params)
|
31
|
-
|
31
|
+
def create(klass, author, params, extra_log_info = {})
|
32
|
+
perform_action!(:create, klass, author, extra_log_info) do
|
32
33
|
klass.create(params)
|
33
34
|
end
|
34
35
|
end
|
@@ -37,25 +38,51 @@ module Decidim
|
|
37
38
|
#
|
38
39
|
# klass - An ActiveRecord class that implements `Decidim::Traceable`
|
39
40
|
# author - An object that implements `to_gid` or a String
|
40
|
-
# params - a Hash
|
41
|
+
# params - a Hash with the attributes of the new resource
|
42
|
+
# extra_log_info - a Hash with extra info that will be saved to the log
|
41
43
|
#
|
42
44
|
# Returns an instance of `klass`.
|
43
|
-
def create!(klass, author, params)
|
44
|
-
|
45
|
+
def create!(klass, author, params, extra_log_info = {})
|
46
|
+
perform_action!(:create, klass, author, extra_log_info) do
|
45
47
|
klass.create!(params)
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
49
|
-
#
|
51
|
+
# Performs the given block and sets the author of the action.
|
52
|
+
# It also logs the action with the given `action` parameter.
|
53
|
+
# The action and the logging are run inside a transaction.
|
50
54
|
#
|
55
|
+
# action - a String or Symbol representing the action performed
|
51
56
|
# resource - An ActiveRecord instance that implements `Decidim::Traceable`
|
52
57
|
# author - An object that implements `to_gid` or a String
|
53
|
-
#
|
58
|
+
# extra_log_info - a Hash with extra info that will be saved to the log
|
54
59
|
#
|
55
|
-
# Returns the
|
56
|
-
def
|
60
|
+
# Returns whatever the given block returns.
|
61
|
+
def perform_action!(action, resource, author, extra_log_info = {})
|
57
62
|
PaperTrail.whodunnit(gid(author)) do
|
58
|
-
resource.
|
63
|
+
klass = resource.is_a?(Class) ? resource : resource.class
|
64
|
+
klass.transaction do
|
65
|
+
Decidim::ApplicationRecord.transaction do
|
66
|
+
result = block_given? ? yield : nil
|
67
|
+
loggable_resource = resource.is_a?(Class) ? result : resource
|
68
|
+
log(action, author, loggable_resource, extra_log_info)
|
69
|
+
result
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Updates the `resource` with `update!` and sets the author of the version.
|
76
|
+
#
|
77
|
+
# resource - An ActiveRecord instance that implements `Decidim::Traceable`
|
78
|
+
# author - An object that implements `to_gid` or a String
|
79
|
+
# params - a Hash with the attributes to update to the resource
|
80
|
+
# extra_log_info - a Hash with extra info that will be saved to the log
|
81
|
+
#
|
82
|
+
# Returns the updated `resource`.
|
83
|
+
def update!(resource, author, params, extra_log_info = {})
|
84
|
+
perform_action!(:update, resource, author, extra_log_info) do
|
85
|
+
resource.update!(params)
|
59
86
|
resource
|
60
87
|
end
|
61
88
|
end
|
@@ -87,5 +114,24 @@ module Decidim
|
|
87
114
|
return author.to_gid if author.respond_to?(:to_gid)
|
88
115
|
author
|
89
116
|
end
|
117
|
+
|
118
|
+
def log(action, user, resource, extra_log_info = {})
|
119
|
+
return unless user.is_a?(Decidim::User)
|
120
|
+
|
121
|
+
Decidim::ActionLogger.log(
|
122
|
+
action,
|
123
|
+
user,
|
124
|
+
resource,
|
125
|
+
version_id(resource),
|
126
|
+
extra_log_info
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
def version_id(resource)
|
131
|
+
return nil unless resource.is_a?(Decidim::Traceable)
|
132
|
+
return nil if resource.versions.blank?
|
133
|
+
|
134
|
+
resource.versions.last.id
|
135
|
+
end
|
90
136
|
end
|
91
137
|
end
|