decidim-core 0.10.1 → 0.11.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -11
- data/app/assets/images/decidim/icons.svg +25 -6
- data/app/assets/javascripts/decidim/account_form.js.es6 +8 -8
- data/app/assets/javascripts/decidim/append_elements.js.es6 +1 -1
- data/app/assets/javascripts/decidim/append_redirect_url_to_modals.js.es6 +5 -5
- data/app/assets/javascripts/decidim/data_picker.js.es6 +10 -10
- data/app/assets/javascripts/decidim/editor.js.es6 +37 -22
- data/app/assets/javascripts/decidim/filters.js.es6 +1 -1
- data/app/assets/javascripts/decidim/form_filter.component.js.es6 +15 -15
- data/app/assets/javascripts/decidim/form_filter.component.test.js +29 -29
- data/app/assets/javascripts/decidim/impersonation.js.es6 +3 -3
- data/app/assets/javascripts/decidim/input_mentions.js.es6 +100 -0
- data/app/assets/javascripts/decidim/input_tags.js.es6 +12 -0
- data/app/assets/javascripts/decidim/{map.js.es6.erb → map.js.es6} +9 -9
- data/app/assets/javascripts/decidim/notifications.js.es6 +10 -10
- data/app/assets/javascripts/decidim/orders.js.es6 +5 -5
- data/app/assets/javascripts/decidim/user_registrations.js.es6 +4 -4
- data/app/assets/javascripts/decidim/widget.js.es6 +1 -1
- data/app/assets/javascripts/decidim.js.es6 +10 -0
- data/app/assets/stylesheets/decidim/application.scss.erb +1 -1
- data/app/assets/stylesheets/decidim/modules/_author-avatar.scss +39 -0
- data/app/assets/stylesheets/decidim/modules/_cards.scss +158 -3
- data/app/assets/stylesheets/decidim/modules/_definition-data.scss +6 -0
- data/app/assets/stylesheets/decidim/modules/_extra.scss +1 -3
- data/app/assets/stylesheets/decidim/modules/_icons.scss +14 -6
- data/app/assets/stylesheets/decidim/modules/_inline-filters.scss +61 -0
- data/app/assets/stylesheets/decidim/modules/_input-mentions.scss +124 -0
- data/app/assets/stylesheets/decidim/modules/_input-tags.scss +55 -0
- data/app/assets/stylesheets/decidim/modules/_modules.scss +3 -0
- data/app/assets/stylesheets/decidim/modules/_status-labels.scss +4 -0
- data/app/assets/stylesheets/decidim/modules/_typography.scss +16 -0
- data/app/assets/stylesheets/decidim/utils/_helpers.scss +29 -0
- data/app/assets/stylesheets/decidim/utils/_mixins.scss +6 -0
- data/app/cells/decidim/author_box/show.erb +10 -0
- data/app/cells/decidim/author_box_cell.rb +21 -0
- data/app/cells/decidim/card/show.erb +17 -0
- data/app/cells/decidim/card_cell.rb +29 -0
- data/app/cells/decidim/profile/profile_inline.erb +21 -0
- data/app/cells/decidim/profile/show.erb +13 -0
- data/app/cells/decidim/profile_cell.rb +17 -0
- data/app/commands/decidim/create_omniauth_registration.rb +3 -2
- data/app/commands/decidim/create_report.rb +1 -1
- data/app/commands/decidim/invite_user.rb +2 -0
- data/app/constraints/decidim/current_component.rb +41 -0
- data/app/controllers/concerns/decidim/action_authorization.rb +3 -3
- data/app/controllers/concerns/decidim/devise_controllers.rb +2 -1
- data/app/controllers/concerns/decidim/filter_resource.rb +1 -1
- data/app/controllers/concerns/decidim/form_factory.rb +1 -1
- data/app/controllers/concerns/decidim/impersonate_users.rb +6 -2
- data/app/controllers/concerns/decidim/needs_authorization.rb +2 -2
- data/app/controllers/concerns/decidim/participatory_space_context.rb +15 -0
- data/app/controllers/concerns/decidim/settings.rb +5 -5
- data/app/controllers/decidim/application_controller.rb +2 -1
- data/app/controllers/decidim/{features → components}/base_controller.rb +16 -8
- data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +3 -1
- data/app/controllers/decidim/devise/registrations_controller.rb +1 -3
- data/app/controllers/decidim/doorkeeper/authorizations_controller.rb +16 -0
- data/app/controllers/decidim/doorkeeper/credentials_controller.rb +46 -0
- data/app/controllers/decidim/doorkeeper/token_info_controller.rb +9 -0
- data/app/controllers/decidim/doorkeeper/tokens_controller.rb +9 -0
- data/app/controllers/decidim/widgets_controller.rb +1 -1
- data/app/forms/decidim/follow_form.rb +1 -1
- data/app/forms/decidim/form.rb +1 -1
- data/app/forms/decidim/omniauth_registration_form.rb +1 -0
- data/app/forms/decidim/registration_form.rb +5 -5
- data/app/helpers/decidim/card_helper.rb +16 -0
- data/app/helpers/decidim/component_path_helper.rb +36 -0
- data/app/helpers/decidim/icon_helper.rb +7 -7
- data/app/helpers/decidim/messaging/conversation_helper.rb +4 -3
- data/app/helpers/decidim/paginate_helper.rb +1 -1
- data/app/helpers/decidim/resource_helper.rb +2 -2
- data/app/jobs/decidim/export_job.rb +3 -3
- data/app/mailers/decidim/messaging/conversation_mailer.rb +0 -2
- data/app/middleware/decidim/current_organization.rb +2 -2
- data/app/models/decidim/abilities/admin_ability.rb +1 -1
- data/app/models/decidim/abilities/everyone_ability.rb +1 -1
- data/app/models/decidim/abilities/participatory_process_admin_ability.rb +2 -2
- data/app/models/decidim/abilities/participatory_process_collaborator_ability.rb +2 -2
- data/app/models/decidim/action_log.rb +7 -5
- data/app/models/decidim/area.rb +7 -0
- data/app/models/decidim/authorization.rb +14 -0
- data/app/models/decidim/{feature.rb → component.rb} +15 -15
- data/app/models/decidim/moderation.rb +1 -1
- data/app/models/decidim/oauth_application.rb +24 -0
- data/app/models/decidim/organization.rb +5 -0
- data/app/models/decidim/participatory_space_link.rb +20 -0
- data/app/models/decidim/participatory_space_private_user.rb +19 -0
- data/app/models/decidim/user.rb +7 -0
- data/app/presenters/decidim/admin_log/area_presenter.rb +38 -0
- data/app/presenters/decidim/admin_log/{feature_presenter.rb → component_presenter.rb} +5 -5
- data/app/presenters/decidim/admin_log/newsletter_resource_presenter.rb +1 -1
- data/app/presenters/decidim/admin_log/oauth_application_presenter.rb +50 -0
- data/app/presenters/decidim/admin_log/oauth_application_resource_presenter.rb +18 -0
- data/app/presenters/decidim/home_stats_presenter.rb +7 -7
- data/app/presenters/decidim/log/value_types/area_presenter.rb +1 -1
- data/app/presenters/decidim/log/value_types/area_type_presenter.rb +28 -0
- data/app/presenters/decidim/log/value_types/currency_presenter.rb +20 -0
- data/app/presenters/decidim/log/value_types/scope_presenter.rb +1 -1
- data/app/presenters/decidim/log/value_types/scope_type_presenter.rb +1 -1
- data/app/presenters/decidim/resource_locator_presenter.rb +3 -3
- data/app/services/decidim/action_authorizer.rb +9 -9
- data/app/services/decidim/action_logger.rb +9 -7
- data/app/services/decidim/email_notification_generator.rb +1 -1
- data/app/services/decidim/notification_generator_for_recipient.rb +1 -1
- data/app/services/decidim/resource_search.rb +8 -8
- data/app/services/decidim/settings_change.rb +5 -5
- data/app/services/decidim/static_map_generator.rb +1 -1
- data/app/types/decidim/core/attachment_type.rb +14 -0
- data/app/types/decidim/core/category_type.rb +16 -0
- data/app/types/decidim/core/coordinates_type.rb +19 -0
- data/app/types/decidim/core/scope_api_type.rb +16 -0
- data/app/uploaders/decidim/oauth_application_logo_uploader.rb +9 -0
- data/app/validators/geocoding_validator.rb +2 -2
- data/app/views/decidim/account/delete.html.erb +7 -7
- data/app/views/decidim/application/_collection.html.erb +1 -1
- data/app/views/decidim/application/_document.html.erb +1 -1
- data/app/views/decidim/application/_photos.html.erb +1 -1
- data/app/views/decidim/devise/invitations/edit.html.erb +1 -1
- data/app/views/decidim/devise/omniauth_registrations/new.html.erb +1 -1
- data/app/views/decidim/devise/registrations/new.html.erb +1 -1
- data/app/views/decidim/devise/sessions/new.html.erb +2 -2
- data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +1 -1
- data/app/views/decidim/devise/shared/_omniauth_buttons_mini.html.erb +1 -1
- data/app/views/decidim/doorkeeper/authorizations/new.html.erb +58 -0
- data/app/views/decidim/messaging/conversations/_show.html.erb +1 -1
- data/app/views/decidim/messaging/conversations/index.html.erb +1 -1
- data/app/views/decidim/notifications/index.html.erb +1 -1
- data/app/views/decidim/notifications_settings/show.html.erb +2 -2
- data/app/views/decidim/own_user_groups/index.html.erb +3 -3
- data/app/views/decidim/scopes/_scopes_picker_input.html.erb +4 -4
- data/app/views/decidim/scopes/picker.html.erb +3 -3
- data/app/views/decidim/shared/_action_authorization_modal.html.erb +1 -1
- data/app/views/decidim/shared/_author.html.erb +1 -1
- data/app/views/decidim/shared/_author_reference.html.erb +1 -12
- data/app/views/decidim/shared/{_feature_announcement.html.erb → _component_announcement.html.erb} +2 -2
- data/app/views/decidim/shared/_embed_modal.html.erb +1 -1
- data/app/views/decidim/shared/_flag_modal.html.erb +5 -5
- data/app/views/decidim/shared/_login_modal.html.erb +3 -3
- data/app/views/decidim/shared/_private_participatory_space.html.erb +5 -0
- data/app/views/decidim/shared/_share_modal.html.erb +1 -1
- data/app/views/decidim/shared/_tags.html.erb +1 -1
- data/app/views/decidim/shared/_version_author.html.erb +1 -1
- data/app/views/decidim/widgets/_data_picker.html.erb +4 -4
- data/app/views/devise/mailer/confirmation_instructions.html.erb +3 -3
- data/app/views/devise/mailer/invite_private_user.html.erb +17 -0
- data/app/views/devise/mailer/invite_private_user.text.erb +15 -0
- data/app/views/devise/mailer/password_change.html.erb +2 -2
- data/app/views/devise/mailer/reset_password_instructions.html.erb +5 -5
- data/app/views/kaminari/decidim/_first_page.html.erb +2 -3
- data/app/views/kaminari/decidim/_gap.html.erb +2 -3
- data/app/views/kaminari/decidim/_last_page.html.erb +2 -3
- data/app/views/kaminari/decidim/_next_page.html.erb +2 -3
- data/app/views/kaminari/decidim/_page.html.erb +2 -3
- data/app/views/kaminari/decidim/_paginator.html.erb +1 -2
- data/app/views/kaminari/decidim/_prev_page.html.erb +2 -3
- data/app/views/layouts/decidim/_application.html.erb +4 -4
- data/app/views/layouts/decidim/_component_authorization_modals.html.erb +5 -0
- data/app/views/layouts/decidim/_cookie_warning.html.erb +2 -2
- data/app/views/layouts/decidim/_head.html.erb +4 -4
- data/app/views/layouts/decidim/_impersonation_warning.html.erb +4 -4
- data/app/views/layouts/decidim/_language_chooser.html.erb +1 -1
- data/app/views/layouts/decidim/_social_media_links.html.erb +5 -5
- data/app/views/layouts/decidim/_wrapper.html.erb +5 -5
- data/app/views/layouts/decidim/mailer.html.erb +1 -1
- data/app/views/layouts/decidim/widget.html.erb +5 -5
- data/app/views/pages/home/_hero.html.erb +1 -1
- data/app/views/pages/home.html.erb +6 -6
- data/config/locales/ca.yml +66 -27
- data/config/locales/en.yml +69 -30
- data/config/locales/es.yml +66 -27
- data/config/locales/eu.yml +69 -30
- data/config/locales/fi.yml +69 -30
- data/config/locales/fr.yml +85 -46
- data/config/locales/gl.yml +69 -30
- data/config/locales/it.yml +69 -30
- data/config/locales/nl.yml +122 -83
- data/config/locales/pl.yml +69 -30
- data/config/locales/pt-BR.yml +69 -30
- data/config/locales/pt.yml +69 -30
- data/config/locales/ru.yml +0 -7
- data/config/locales/sv.yml +69 -30
- data/config/locales/uk.yml +0 -13
- data/config/routes.rb +8 -0
- data/db/migrate/20180206183235_create_participatory_space_private_users.rb +15 -0
- data/db/migrate/20180221101934_fix_nickname_index.rb +5 -6
- data/db/migrate/20180226140756_add_version_to_action_logs.rb +5 -1
- data/db/migrate/20180227131727_create_participatory_space_links.rb +12 -0
- data/db/migrate/20180305132906_rename_features_to_components.rb +13 -0
- data/db/migrate/20180308113207_doorkeeper_models.rb +85 -0
- data/db/migrate/20180314085339_rename_maximum_votes_per_proposal_to_threshold_per_proposal.rb +2 -2
- data/db/migrate/{20180326075746_change_event_name_and_class_to_rename_to_publish_proposal_event.rb → 20180323102631_change_event_name_and_class_to_rename_to_publish_proposal_event.rb} +0 -0
- data/db/seeds.rb +12 -2
- data/lib/decidim/api/attachable_interface.rb +13 -0
- data/lib/decidim/api/authorable_interface.rb +13 -0
- data/lib/decidim/api/categorizable_interface.rb +13 -0
- data/lib/decidim/api/participatory_space_interface.rb +4 -4
- data/lib/decidim/api/scopable_interface.rb +13 -0
- data/lib/decidim/authorable.rb +8 -0
- data/lib/decidim/{feature_manifest.rb → component_manifest.rb} +24 -21
- data/lib/decidim/{feature_validator.rb → component_validator.rb} +6 -6
- data/lib/decidim/{features → components}/export_manifest.rb +4 -4
- data/lib/decidim/components/namer.rb +35 -0
- data/lib/decidim/components.rb +9 -0
- data/lib/decidim/content_parsers/user_parser.rb +1 -1
- data/lib/decidim/core/api.rb +13 -0
- data/lib/decidim/core/engine.rb +76 -3
- data/lib/decidim/core/test/factories.rb +43 -10
- data/lib/decidim/core/test/shared_examples/announcements_examples.rb +9 -9
- data/lib/decidim/core/test/shared_examples/attachable_interface_examples.rb +16 -0
- data/lib/decidim/core/test/shared_examples/authorable_interface_examples.rb +33 -0
- data/lib/decidim/core/test/shared_examples/categorizable_interface_examples.rb +19 -0
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +3 -3
- data/lib/decidim/core/test/shared_examples/follows_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/has_component.rb +21 -0
- data/lib/decidim/core/test/shared_examples/has_reference.rb +2 -2
- data/lib/decidim/core/test/shared_examples/localised_email.rb +1 -1
- data/lib/decidim/core/test/shared_examples/paginated_resource_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/reportable.rb +8 -6
- data/lib/decidim/core/test/shared_examples/reports_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/scopable_interface_examples.rb +19 -0
- data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +8 -3
- data/lib/decidim/core/test/shared_examples/simple_event.rb +1 -1
- data/lib/decidim/core/test/shared_examples/user_localised_email_examples.rb +1 -1
- data/lib/decidim/core/test.rb +1 -1
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +35 -37
- data/lib/decidim/events/base_event.rb +5 -5
- data/lib/decidim/events/simple_event.rb +8 -8
- data/lib/decidim/form_builder.rb +48 -3
- data/lib/decidim/has_attachment_collections.rb +1 -1
- data/lib/decidim/has_attachments.rb +1 -1
- data/lib/decidim/has_category.rb +2 -2
- data/lib/decidim/has_component.rb +23 -0
- data/lib/decidim/has_private_users.rb +26 -0
- data/lib/decidim/has_reference.rb +3 -3
- data/lib/decidim/page_finder.rb +1 -1
- data/lib/decidim/participatory_space_manifest.rb +3 -3
- data/lib/decidim/participatory_space_resourceable.rb +80 -0
- data/lib/decidim/publicable.rb +2 -2
- data/lib/decidim/query_extensions.rb +2 -2
- data/lib/decidim/rectify_ext.rb +32 -0
- data/lib/decidim/reportable.rb +1 -1
- data/lib/decidim/resource_manifest.rb +13 -13
- data/lib/decidim/resourceable.rb +8 -8
- data/lib/decidim/scopable.rb +1 -1
- data/lib/decidim/{scopable_feature.rb → scopable_component.rb} +1 -1
- data/lib/decidim/settings_manifest.rb +1 -1
- data/lib/decidim/stats_registry.rb +1 -1
- data/lib/decidim/view_model.rb +9 -0
- data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.fr.js +4 -1
- data/vendor/assets/javascripts/form_datepicker.js.es6 +10 -10
- data/vendor/assets/javascripts/quill.min.js +2 -2
- data/vendor/assets/javascripts/quill.min.js.map +1 -1
- data/vendor/assets/javascripts/tagsinput.js +683 -0
- data/vendor/assets/javascripts/tribute.js +1607 -0
- data/vendor/assets/stylesheets/quill.bubble.css +30 -16
- data/vendor/assets/stylesheets/quill.core.css +19 -9
- data/vendor/assets/stylesheets/quill.snow.css +30 -16
- data/vendor/assets/stylesheets/tagsinput.css +55 -0
- data/vendor/assets/stylesheets/tribute.css +27 -0
- metadata +164 -27
- data/app/constraints/decidim/current_feature.rb +0 -41
- data/app/helpers/decidim/feature_path_helper.rb +0 -36
- data/app/views/layouts/decidim/_feature_authorization_modals.html.erb +0 -5
- data/lib/decidim/core/test/shared_examples/has_feature.rb +0 -21
- data/lib/decidim/features/namer.rb +0 -35
- data/lib/decidim/features.rb +0 -9
- data/lib/decidim/has_feature.rb +0 -23
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "decidim/settings_manifest"
|
4
|
-
require "decidim/
|
4
|
+
require "decidim/components/export_manifest"
|
5
5
|
|
6
6
|
module Decidim
|
7
|
-
# This class handles all the logic associated to configuring a
|
7
|
+
# This class handles all the logic associated to configuring a component
|
8
8
|
# associated to a participatory process.
|
9
9
|
#
|
10
10
|
# It's normally not used directly but through the API exposed through
|
11
|
-
# `Decidim.
|
12
|
-
class
|
11
|
+
# `Decidim.register_component`.
|
12
|
+
class ComponentManifest
|
13
13
|
include ActiveModel::Model
|
14
14
|
include Virtus.model
|
15
15
|
|
@@ -31,21 +31,24 @@ module Decidim
|
|
31
31
|
# it can use the scss variables and mixins provided by Decidim::Admin.
|
32
32
|
attribute :admin_stylesheet, String, default: nil
|
33
33
|
|
34
|
-
# A String with the
|
34
|
+
# A String with the component's icon. The icon must be stored in the
|
35
35
|
# engine's assets path.
|
36
36
|
attribute :icon, String
|
37
37
|
|
38
|
-
# Actions are used to validate permissions of a
|
38
|
+
# Actions are used to validate permissions of a component against particular
|
39
39
|
# authorizations or potentially other authorization rules.
|
40
40
|
#
|
41
41
|
# An example would be `vote` on participatory processes, or `create_meeting`
|
42
42
|
# on meetings.
|
43
43
|
#
|
44
|
-
# A
|
44
|
+
# A Component can expose as many actions as it wants and the admin panel will
|
45
45
|
# generate a UI to handle them. There's a set of controller helpers available
|
46
46
|
# as well that allows checking for those permissions.
|
47
47
|
attribute :actions, Array[String]
|
48
48
|
|
49
|
+
# The cell path to use to render the card of a resource.
|
50
|
+
attribute :card, String
|
51
|
+
|
49
52
|
validates :name, presence: true
|
50
53
|
|
51
54
|
# Public: Registers a hook to this manifest. Hooks get fired when some
|
@@ -84,21 +87,21 @@ module Decidim
|
|
84
87
|
self.hooks = {}
|
85
88
|
end
|
86
89
|
|
87
|
-
# Public: A block that gets called when seeding for this
|
90
|
+
# Public: A block that gets called when seeding for this component takes place.
|
88
91
|
#
|
89
92
|
# Returns nothing.
|
90
93
|
def seeds(&block)
|
91
94
|
@seeds = block
|
92
95
|
end
|
93
96
|
|
94
|
-
# Public: Creates the seeds for this
|
97
|
+
# Public: Creates the seeds for this components in order to populate the database.
|
95
98
|
#
|
96
99
|
# Returns nothing.
|
97
100
|
def seed!(participatory_space)
|
98
101
|
@seeds&.call(participatory_space)
|
99
102
|
end
|
100
103
|
|
101
|
-
# Public: Adds configurable attributes for this
|
104
|
+
# Public: Adds configurable attributes for this component, scoped to a name. It
|
102
105
|
# uses the DSL specified under `Decidim::SettingsManifest`.
|
103
106
|
#
|
104
107
|
# name - Either `global` or `step`
|
@@ -106,7 +109,7 @@ module Decidim
|
|
106
109
|
#
|
107
110
|
# Examples:
|
108
111
|
#
|
109
|
-
#
|
112
|
+
# component.settings(:global) do |settings|
|
110
113
|
# settings.attribute :voting_enabled, type: :boolean, default: true
|
111
114
|
# end
|
112
115
|
#
|
@@ -119,7 +122,7 @@ module Decidim
|
|
119
122
|
settings
|
120
123
|
end
|
121
124
|
|
122
|
-
# Public: Registers a resource inside a
|
125
|
+
# Public: Registers a resource inside a component manifest. Exposes a DSL
|
123
126
|
# defined by `Decidim::ResourceManifest`.
|
124
127
|
#
|
125
128
|
# Resource manifests are a way to expose a resource from one engine to
|
@@ -130,21 +133,21 @@ module Decidim
|
|
130
133
|
# Returns nothing.
|
131
134
|
def register_resource
|
132
135
|
manifest = ResourceManifest.new
|
133
|
-
manifest.
|
136
|
+
manifest.component_manifest = self
|
134
137
|
yield(manifest)
|
135
138
|
manifest.validate!
|
136
139
|
resource_manifests << manifest
|
137
140
|
end
|
138
141
|
|
139
142
|
# Public: Registers an export artifact with a name and its properties
|
140
|
-
# defined in `Decidim::
|
143
|
+
# defined in `Decidim::Components::ExportManifest`.
|
141
144
|
#
|
142
|
-
# Export artifacts provide an unified way for
|
145
|
+
# Export artifacts provide an unified way for components to register
|
143
146
|
# exportable collections serialized via a `Serializer` than eventually
|
144
147
|
# are transformed to their formats.
|
145
148
|
#
|
146
149
|
# name - The name of the artifact. Should be unique in the context of
|
147
|
-
# the
|
150
|
+
# the component.
|
148
151
|
# block - A block that receives the manifest as its only argument.
|
149
152
|
#
|
150
153
|
# Returns nothing.
|
@@ -155,12 +158,12 @@ module Decidim
|
|
155
158
|
end
|
156
159
|
|
157
160
|
# Pubic: Returns a collection of previously registered export manifests
|
158
|
-
# for this
|
161
|
+
# for this component.
|
159
162
|
#
|
160
|
-
# Returns an Array<Decidim::
|
163
|
+
# Returns an Array<Decidim::Components::ExportManifest>.
|
161
164
|
def export_manifests
|
162
165
|
@export_manifests ||= @exports.map do |(name, block)|
|
163
|
-
Decidim::
|
166
|
+
Decidim::Components::ExportManifest.new(name).tap do |manifest|
|
164
167
|
block.call(manifest)
|
165
168
|
end
|
166
169
|
end
|
@@ -179,13 +182,13 @@ module Decidim
|
|
179
182
|
@stats ||= StatsRegistry.new
|
180
183
|
end
|
181
184
|
|
182
|
-
# Public: Registers a stat inside a
|
185
|
+
# Public: Registers a stat inside a component manifest.
|
183
186
|
#
|
184
187
|
# name - The name of the stat
|
185
188
|
# options - A hash of options
|
186
189
|
# * primary: Whether the stat is primary or not.
|
187
190
|
# * priority: The priority of the stat used for render issues.
|
188
|
-
# block - A block that receive the
|
191
|
+
# block - A block that receive the components to filter out the stat.
|
189
192
|
#
|
190
193
|
# Returns nothing.
|
191
194
|
def register_stat(name, options = {}, &block)
|
@@ -1,22 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# A custom validator to make sure
|
3
|
+
# A custom validator to make sure components are correctly assigned to a model.
|
4
4
|
#
|
5
5
|
# Adds a presence validation and checks that the manifest is the correct one.
|
6
|
-
class
|
6
|
+
class ComponentValidator < ActiveModel::EachValidator
|
7
7
|
# Validates the arguiments passed to the validator.
|
8
8
|
def check_validity!
|
9
|
-
raise ArgumentError, "You must include a `manifest` option with the name of the manifest to validate when validating a
|
9
|
+
raise ArgumentError, "You must include a `manifest` option with the name of the manifest to validate when validating a component" if options[:manifest].blank?
|
10
10
|
end
|
11
11
|
|
12
12
|
# The actual validator method. It is called when ActiveRecord iterates
|
13
13
|
# over all the validators.
|
14
|
-
def validate_each(record, attribute,
|
15
|
-
unless
|
14
|
+
def validate_each(record, attribute, component)
|
15
|
+
unless component
|
16
16
|
record.errors[attribute] << :blank
|
17
17
|
return
|
18
18
|
end
|
19
19
|
|
20
|
-
record.errors[attribute] << :invalid if
|
20
|
+
record.errors[attribute] << :invalid if component.manifest_name.to_s != options[:manifest].to_s
|
21
21
|
end
|
22
22
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Decidim
|
4
|
-
module
|
4
|
+
module Components
|
5
5
|
# This class serves as a DSL to declarative specify which artifacts are
|
6
|
-
# exportable in a
|
6
|
+
# exportable in a component. It is used via the `ComponentManifest`.
|
7
7
|
#
|
8
8
|
class ExportManifest
|
9
9
|
attr_reader :name
|
@@ -11,7 +11,7 @@ module Decidim
|
|
11
11
|
# Initializes the manifest.
|
12
12
|
#
|
13
13
|
# name - The name of the export artifact. It should be unique in the
|
14
|
-
#
|
14
|
+
# component.
|
15
15
|
#
|
16
16
|
def initialize(name)
|
17
17
|
@name = name.to_sym
|
@@ -20,7 +20,7 @@ module Decidim
|
|
20
20
|
# Public: Sets the collection when a block is given, or returns it if
|
21
21
|
# no block is provided.
|
22
22
|
#
|
23
|
-
# The collection will get passed an instance of `Decidim::
|
23
|
+
# The collection will get passed an instance of `Decidim::Component` when
|
24
24
|
# it's evaluated so you can easily find the elements to export.
|
25
25
|
#
|
26
26
|
# &block - An optional block that returns the collection once evaluated.
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Components
|
5
|
+
# This class automatically names components for the given organization.
|
6
|
+
# In order to do so, it uses the i18n keys of the component, fallback to English,
|
7
|
+
# searching for the key `"decidim.components.<component name>.name"`
|
8
|
+
#
|
9
|
+
# This is intended to be used from the component seeds section.
|
10
|
+
#
|
11
|
+
# Examples:
|
12
|
+
#
|
13
|
+
# Decidim::Component.create!(
|
14
|
+
# participatory_space: process,
|
15
|
+
# name: Decidim::Component::Namer.new(organization.available_locales, :my_component_name).i18n_name
|
16
|
+
# manifest_name: :my_component_name
|
17
|
+
# )
|
18
|
+
class Namer
|
19
|
+
def initialize(locales, component_name)
|
20
|
+
@locales = locales
|
21
|
+
@component_name = component_name
|
22
|
+
end
|
23
|
+
|
24
|
+
def i18n_name
|
25
|
+
locales.inject({}) do |names, locale|
|
26
|
+
names.update(locale => I18n.t("decidim.components.#{component_name}.name", locale: locale))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :locales, :component_name
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
# This module contains all logic related to decidim's Components, the main
|
5
|
+
# building block to extend functionalities in a participatory process.
|
6
|
+
module Components
|
7
|
+
autoload :BaseController, "decidim/components/base_controller"
|
8
|
+
end
|
9
|
+
end
|
@@ -28,7 +28,7 @@ module Decidim
|
|
28
28
|
# @return [String] the content with the valid mentions replaced by a global id
|
29
29
|
def rewrite
|
30
30
|
content.gsub(MENTION_REGEX) do |match|
|
31
|
-
if (user = Decidim::User.
|
31
|
+
if (user = Decidim::User.find_by(nickname: Regexp.last_match[2], organization: context[:current_organization]))
|
32
32
|
Regexp.last_match[1] + user.to_global_id.to_s
|
33
33
|
else
|
34
34
|
match
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Core
|
5
|
+
autoload :ParticipatorySpaceInterface, "decidim/api/participatory_space_interface"
|
6
|
+
autoload :ComponentInterface, "decidim/api/component_interface"
|
7
|
+
autoload :AuthorInterface, "decidim/api/author_interface"
|
8
|
+
autoload :AuthorableInterface, "decidim/api/authorable_interface"
|
9
|
+
autoload :CategorizableInterface, "decidim/api/categorizable_interface"
|
10
|
+
autoload :ScopableInterface, "decidim/api/scopable_interface"
|
11
|
+
autoload :AttachableInterface, "decidim/api/attachable_interface"
|
12
|
+
end
|
13
|
+
end
|
data/lib/decidim/core/engine.rb
CHANGED
@@ -15,7 +15,12 @@ require "foundation-rails"
|
|
15
15
|
require "foundation_rails_helper"
|
16
16
|
require "autoprefixer-rails"
|
17
17
|
require "active_link_to"
|
18
|
+
|
19
|
+
# Until https://github.com/andypike/rectify/pull/45 is attended, we're shipping
|
20
|
+
# with a patched version of rectify
|
18
21
|
require "rectify"
|
22
|
+
require "decidim/rectify_ext"
|
23
|
+
|
19
24
|
require "carrierwave"
|
20
25
|
require "high_voltage"
|
21
26
|
require "rails-i18n"
|
@@ -32,6 +37,10 @@ require "invisible_captcha"
|
|
32
37
|
require "premailer/rails"
|
33
38
|
require "geocoder"
|
34
39
|
require "paper_trail"
|
40
|
+
require "cells/rails"
|
41
|
+
require "cells-erb"
|
42
|
+
require "doorkeeper"
|
43
|
+
require "doorkeeper-i18n"
|
35
44
|
|
36
45
|
require "decidim/api"
|
37
46
|
|
@@ -56,8 +65,8 @@ module Decidim
|
|
56
65
|
app.config.assets.paths << File.expand_path("../../../app/assets/stylesheets", __dir__)
|
57
66
|
app.config.assets.precompile += %w(decidim_core_manifest.js)
|
58
67
|
|
59
|
-
Decidim.
|
60
|
-
app.config.assets.precompile += [
|
68
|
+
Decidim.component_manifests.each do |component|
|
69
|
+
app.config.assets.precompile += [component.icon]
|
61
70
|
end
|
62
71
|
|
63
72
|
app.config.assets.debug = true if Rails.env.test?
|
@@ -92,10 +101,13 @@ module Decidim
|
|
92
101
|
app.config.i18n.fallbacks = true
|
93
102
|
end
|
94
103
|
|
95
|
-
initializer "decidim.
|
104
|
+
initializer "decidim.graphql_api" do
|
96
105
|
Decidim::Api::QueryType.define do
|
97
106
|
Decidim::QueryExtensions.define(self)
|
98
107
|
end
|
108
|
+
|
109
|
+
Decidim::Api.add_orphan_type Decidim::Core::UserType
|
110
|
+
Decidim::Api.add_orphan_type Decidim::Core::UserGroupType
|
99
111
|
end
|
100
112
|
|
101
113
|
initializer "decidim.i18n_exceptions" do
|
@@ -207,6 +219,67 @@ module Decidim
|
|
207
219
|
initializer "paper_trail" do
|
208
220
|
PaperTrail.config.track_associations = false
|
209
221
|
end
|
222
|
+
|
223
|
+
initializer "add_cells_view_paths" do
|
224
|
+
Cell::ViewModel.view_paths << File.expand_path("#{Decidim::Core::Engine.root}/app/cells")
|
225
|
+
Cell::ViewModel.view_paths << File.expand_path("#{Decidim::Core::Engine.root}/app/views") # for partials
|
226
|
+
end
|
227
|
+
|
228
|
+
initializer "doorkeeper" do
|
229
|
+
Doorkeeper.configure do
|
230
|
+
orm :active_record
|
231
|
+
|
232
|
+
# This block will be called to check whether the resource owner is authenticated or not.
|
233
|
+
resource_owner_authenticator do
|
234
|
+
current_user || redirect_to(new_user_session_path)
|
235
|
+
end
|
236
|
+
|
237
|
+
# The controller Doorkeeper::ApplicationController inherits from.
|
238
|
+
# Defaults to ActionController::Base.
|
239
|
+
# https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller
|
240
|
+
base_controller "Decidim::ApplicationController"
|
241
|
+
|
242
|
+
# Provide support for an owner to be assigned to each registered application (disabled by default)
|
243
|
+
# Optional parameter confirmation: true (default false) if you want to enforce ownership of
|
244
|
+
# a registered application
|
245
|
+
# Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support
|
246
|
+
enable_application_owner confirmation: false
|
247
|
+
|
248
|
+
# Define access token scopes for your provider
|
249
|
+
# For more information go to
|
250
|
+
# https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes
|
251
|
+
default_scopes :public
|
252
|
+
optional_scopes []
|
253
|
+
|
254
|
+
# Change the native redirect uri for client apps
|
255
|
+
# When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider
|
256
|
+
# The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL
|
257
|
+
# (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
|
258
|
+
#
|
259
|
+
native_redirect_uri "urn:ietf:wg:oauth:2.0:oob"
|
260
|
+
|
261
|
+
# Forces the usage of the HTTPS protocol in non-native redirect uris (enabled
|
262
|
+
# by default in non-development environments). OAuth2 delegates security in
|
263
|
+
# communication to the HTTPS protocol so it is wise to keep this enabled.
|
264
|
+
#
|
265
|
+
# Callable objects such as proc, lambda, block or any object that responds to
|
266
|
+
# #call can be used in order to allow conditional checks (to allow non-SSL
|
267
|
+
# redirects to localhost for example).
|
268
|
+
#
|
269
|
+
# force_ssl_in_redirect_uri !Rails.env.development?
|
270
|
+
#
|
271
|
+
force_ssl_in_redirect_uri false
|
272
|
+
|
273
|
+
# WWW-Authenticate Realm (default "Doorkeeper").
|
274
|
+
realm "Decidim"
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
initializer "OAuth inflections" do
|
279
|
+
ActiveSupport::Inflector.inflections do |inflect|
|
280
|
+
inflect.acronym "OAuth"
|
281
|
+
end
|
282
|
+
end
|
210
283
|
end
|
211
284
|
end
|
212
285
|
end
|
@@ -4,6 +4,7 @@ require "decidim/faker/localized"
|
|
4
4
|
require "decidim/dev"
|
5
5
|
|
6
6
|
require "decidim/participatory_processes/test/factories"
|
7
|
+
require "decidim/assemblies/test/factories"
|
7
8
|
require "decidim/comments/test/factories"
|
8
9
|
|
9
10
|
FactoryBot.define do
|
@@ -113,6 +114,16 @@ FactoryBot.define do
|
|
113
114
|
end
|
114
115
|
end
|
115
116
|
|
117
|
+
factory :participatory_space_private_user, class: "Decidim::ParticipatorySpacePrivateUser" do
|
118
|
+
user
|
119
|
+
privatable_to { create :participatory_process, organization: user.organization }
|
120
|
+
end
|
121
|
+
|
122
|
+
factory :assembly_private_user, class: "Decidim::ParticipatorySpacePrivateUser" do
|
123
|
+
user
|
124
|
+
privatable_to { create :assembly, organization: user.organization }
|
125
|
+
end
|
126
|
+
|
116
127
|
factory :user_group, class: "Decidim::UserGroup" do
|
117
128
|
name { Faker::Educator.course }
|
118
129
|
document_number { Faker::Number.number(8) + "X" }
|
@@ -208,7 +219,7 @@ FactoryBot.define do
|
|
208
219
|
end
|
209
220
|
end
|
210
221
|
|
211
|
-
factory :
|
222
|
+
factory :component, class: "Decidim::Component" do
|
212
223
|
transient do
|
213
224
|
organization { create(:organization) }
|
214
225
|
end
|
@@ -261,21 +272,24 @@ FactoryBot.define do
|
|
261
272
|
|
262
273
|
factory :dummy_resource, class: "Decidim::DummyResources::DummyResource" do
|
263
274
|
title { generate(:name) }
|
264
|
-
|
265
|
-
author { create(:user, :confirmed, organization:
|
275
|
+
component { create(:component, manifest_name: "dummy") }
|
276
|
+
author { create(:user, :confirmed, organization: component.organization) }
|
266
277
|
end
|
267
278
|
|
268
279
|
factory :resource_link, class: "Decidim::ResourceLink" do
|
269
280
|
name { generate(:slug) }
|
270
281
|
to { build(:dummy_resource) }
|
271
|
-
from { build(:dummy_resource,
|
282
|
+
from { build(:dummy_resource, component: to.component) }
|
272
283
|
end
|
273
284
|
|
274
285
|
factory :newsletter, class: "Decidim::Newsletter" do
|
275
286
|
author { build(:user, :confirmed, organization: organization) }
|
276
287
|
organization
|
277
288
|
|
289
|
+
# rubocop:disable RSpec/EmptyLineAfterSubject
|
290
|
+
# Bug in rubocop-rspec
|
278
291
|
subject { Decidim::Faker::Localized.sentence(3) }
|
292
|
+
# rubocop:enable RSpec/EmptyLineAfterSubject
|
279
293
|
body { Decidim::Faker::Localized.wrapped("<p>", "</p>") { Decidim::Faker::Localized.sentence(4) } }
|
280
294
|
|
281
295
|
trait :sent do
|
@@ -285,7 +299,7 @@ FactoryBot.define do
|
|
285
299
|
|
286
300
|
factory :moderation, class: "Decidim::Moderation" do
|
287
301
|
reportable { build(:dummy_resource) }
|
288
|
-
participatory_space { reportable.
|
302
|
+
participatory_space { reportable.component.participatory_space }
|
289
303
|
|
290
304
|
trait :hidden do
|
291
305
|
hidden_at { 1.day.ago }
|
@@ -339,14 +353,14 @@ FactoryBot.define do
|
|
339
353
|
organization { user.organization }
|
340
354
|
user
|
341
355
|
participatory_space { build :participatory_process, organization: organization }
|
342
|
-
|
343
|
-
resource { build(:dummy_resource,
|
356
|
+
component { build :component, participatory_space: participatory_space }
|
357
|
+
resource { build(:dummy_resource, component: component) }
|
344
358
|
action { "create" }
|
345
359
|
extra do
|
346
360
|
{
|
347
|
-
|
348
|
-
manifest_name:
|
349
|
-
title:
|
361
|
+
component: {
|
362
|
+
manifest_name: component.try(:manifest_name),
|
363
|
+
title: component.try(:name) || component.try(:title)
|
350
364
|
}.compact,
|
351
365
|
participatory_space: {
|
352
366
|
manifest_name: participatory_space.try(:class).try(:participatory_space_manifest).try(:name),
|
@@ -363,4 +377,23 @@ FactoryBot.define do
|
|
363
377
|
}.deep_merge(extra_data)
|
364
378
|
end
|
365
379
|
end
|
380
|
+
|
381
|
+
factory :oauth_application, class: "Decidim::OAuthApplication" do
|
382
|
+
organization
|
383
|
+
sequence(:name) { |n| "OAuth application #{n}" }
|
384
|
+
sequence(:organization_name) { |n| "OAuth application owner #{n}" }
|
385
|
+
organization_url { "http://example.org" }
|
386
|
+
organization_logo { Decidim::Dev.test_file("avatar.jpg", "image/jpeg") }
|
387
|
+
redirect_uri { "https://app.example.org/oauth" }
|
388
|
+
scopes { "public" }
|
389
|
+
end
|
390
|
+
|
391
|
+
factory :oauth_access_token, class: "Doorkeeper::AccessToken" do
|
392
|
+
resource_owner_id { create(:user, organization: application.organization).id }
|
393
|
+
application { build(:oauth_application) }
|
394
|
+
token { SecureRandom.hex(32) }
|
395
|
+
expires_in { 1.month.from_now }
|
396
|
+
created_at { Time.zone.now }
|
397
|
+
scopes { "public" }
|
398
|
+
end
|
366
399
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
shared_examples "manage announcements" do
|
4
|
-
it "customize a general announcement for the
|
5
|
-
visit
|
4
|
+
it "customize a general announcement for the component" do
|
5
|
+
visit edit_component_path(current_component)
|
6
6
|
|
7
7
|
fill_in_i18n_editor(
|
8
|
-
:
|
8
|
+
:component_settings_announcement,
|
9
9
|
"#global-settings-announcement-tabs",
|
10
10
|
en: "An important announcement",
|
11
11
|
es: "Un aviso muy importante",
|
@@ -14,7 +14,7 @@ shared_examples "manage announcements" do
|
|
14
14
|
|
15
15
|
click_button "Update"
|
16
16
|
|
17
|
-
visit
|
17
|
+
visit main_component_path(current_component)
|
18
18
|
|
19
19
|
within ".callout.secondary" do
|
20
20
|
expect(page).to have_content("An important announcement")
|
@@ -23,7 +23,7 @@ shared_examples "manage announcements" do
|
|
23
23
|
|
24
24
|
context "when the general announcement is set" do
|
25
25
|
before do
|
26
|
-
|
26
|
+
current_component.update!(
|
27
27
|
settings: {
|
28
28
|
announcement: {
|
29
29
|
en: "An important announcement",
|
@@ -35,11 +35,11 @@ shared_examples "manage announcements" do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
it "customize an announcement for the current step and it has more priority" do
|
38
|
-
visit
|
39
|
-
step_id =
|
38
|
+
visit edit_component_path(current_component)
|
39
|
+
step_id = current_component.participatory_space.steps.first.id
|
40
40
|
|
41
41
|
fill_in_i18n_editor(
|
42
|
-
:"
|
42
|
+
:"component_step_settings_#{step_id}_announcement",
|
43
43
|
"#step-#{step_id}-settings-announcement-tabs",
|
44
44
|
en: "An announcement for this step",
|
45
45
|
es: "Un aviso para esta fase",
|
@@ -48,7 +48,7 @@ shared_examples "manage announcements" do
|
|
48
48
|
|
49
49
|
click_button "Update"
|
50
50
|
|
51
|
-
visit
|
51
|
+
visit main_component_path(current_component)
|
52
52
|
|
53
53
|
within ".callout.secondary" do
|
54
54
|
expect(page).to have_no_content("An important announcement")
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
shared_examples_for "attachable interface" do
|
6
|
+
let!(:attachments) { create_list(:attachment, 3, attached_to: model) }
|
7
|
+
|
8
|
+
describe "attachments" do
|
9
|
+
let(:query) { "{ attachments { url } }" }
|
10
|
+
|
11
|
+
it "includes the attachment urls" do
|
12
|
+
attachment_urls = response["attachments"].map { |attachment| attachment["url"] }
|
13
|
+
expect(attachment_urls).to include(*attachments.map(&:url))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
shared_examples_for "authorable interface" do
|
6
|
+
describe "author" do
|
7
|
+
describe "with a regular user" do
|
8
|
+
let(:author) { create(:user, organization: model.participatory_space.organization) }
|
9
|
+
let(:query) { "{ author { name } }" }
|
10
|
+
|
11
|
+
before do
|
12
|
+
model.update(author: author, user_group: nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "includes the user's ID" do
|
16
|
+
expect(response["author"]["name"]).to eq(author.name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "with a user group" do
|
21
|
+
let(:user_group) { create(:user_group, organization: model.participatory_space.organization) }
|
22
|
+
let(:query) { "{ author { name } }" }
|
23
|
+
|
24
|
+
before do
|
25
|
+
model.update(user_group: user_group, author: nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "includes the user's ID" do
|
29
|
+
expect(response["author"]["name"]).to eq(user_group.name)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
shared_examples_for "categorizable interface" do
|
6
|
+
let!(:category) { create(:category, participatory_space: model.participatory_space) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
model.update(category: category)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "category" do
|
13
|
+
let(:query) { "{ category { id } }" }
|
14
|
+
|
15
|
+
it "has a category" do
|
16
|
+
expect(response).to include("category" => { "id" => category.id.to_s })
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -115,7 +115,7 @@ shared_examples "comments" do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
describe "arguable option" do
|
118
|
-
context "commenting with alignment" do
|
118
|
+
context "when commenting with alignment" do
|
119
119
|
before do
|
120
120
|
visit resource_path
|
121
121
|
|
@@ -146,7 +146,7 @@ shared_examples "comments" do
|
|
146
146
|
visit resource_path
|
147
147
|
end
|
148
148
|
|
149
|
-
context "upvoting a comment" do
|
149
|
+
context "when upvoting a comment" do
|
150
150
|
it "works according to the setting in the commentable" do
|
151
151
|
within "#comment_#{comments[0].id}" do
|
152
152
|
if commentable.comments_have_votes?
|
@@ -160,7 +160,7 @@ shared_examples "comments" do
|
|
160
160
|
end
|
161
161
|
end
|
162
162
|
|
163
|
-
context "downvoting a comment" do
|
163
|
+
context "when downvoting a comment" do
|
164
164
|
it "works according to the setting in the commentable" do
|
165
165
|
within "#comment_#{comments[0].id}" do
|
166
166
|
if commentable.comments_have_votes?
|