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.
Files changed (269) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -11
  3. data/app/assets/images/decidim/icons.svg +25 -6
  4. data/app/assets/javascripts/decidim/account_form.js.es6 +8 -8
  5. data/app/assets/javascripts/decidim/append_elements.js.es6 +1 -1
  6. data/app/assets/javascripts/decidim/append_redirect_url_to_modals.js.es6 +5 -5
  7. data/app/assets/javascripts/decidim/data_picker.js.es6 +10 -10
  8. data/app/assets/javascripts/decidim/editor.js.es6 +37 -22
  9. data/app/assets/javascripts/decidim/filters.js.es6 +1 -1
  10. data/app/assets/javascripts/decidim/form_filter.component.js.es6 +15 -15
  11. data/app/assets/javascripts/decidim/form_filter.component.test.js +29 -29
  12. data/app/assets/javascripts/decidim/impersonation.js.es6 +3 -3
  13. data/app/assets/javascripts/decidim/input_mentions.js.es6 +100 -0
  14. data/app/assets/javascripts/decidim/input_tags.js.es6 +12 -0
  15. data/app/assets/javascripts/decidim/{map.js.es6.erb → map.js.es6} +9 -9
  16. data/app/assets/javascripts/decidim/notifications.js.es6 +10 -10
  17. data/app/assets/javascripts/decidim/orders.js.es6 +5 -5
  18. data/app/assets/javascripts/decidim/user_registrations.js.es6 +4 -4
  19. data/app/assets/javascripts/decidim/widget.js.es6 +1 -1
  20. data/app/assets/javascripts/decidim.js.es6 +10 -0
  21. data/app/assets/stylesheets/decidim/application.scss.erb +1 -1
  22. data/app/assets/stylesheets/decidim/modules/_author-avatar.scss +39 -0
  23. data/app/assets/stylesheets/decidim/modules/_cards.scss +158 -3
  24. data/app/assets/stylesheets/decidim/modules/_definition-data.scss +6 -0
  25. data/app/assets/stylesheets/decidim/modules/_extra.scss +1 -3
  26. data/app/assets/stylesheets/decidim/modules/_icons.scss +14 -6
  27. data/app/assets/stylesheets/decidim/modules/_inline-filters.scss +61 -0
  28. data/app/assets/stylesheets/decidim/modules/_input-mentions.scss +124 -0
  29. data/app/assets/stylesheets/decidim/modules/_input-tags.scss +55 -0
  30. data/app/assets/stylesheets/decidim/modules/_modules.scss +3 -0
  31. data/app/assets/stylesheets/decidim/modules/_status-labels.scss +4 -0
  32. data/app/assets/stylesheets/decidim/modules/_typography.scss +16 -0
  33. data/app/assets/stylesheets/decidim/utils/_helpers.scss +29 -0
  34. data/app/assets/stylesheets/decidim/utils/_mixins.scss +6 -0
  35. data/app/cells/decidim/author_box/show.erb +10 -0
  36. data/app/cells/decidim/author_box_cell.rb +21 -0
  37. data/app/cells/decidim/card/show.erb +17 -0
  38. data/app/cells/decidim/card_cell.rb +29 -0
  39. data/app/cells/decidim/profile/profile_inline.erb +21 -0
  40. data/app/cells/decidim/profile/show.erb +13 -0
  41. data/app/cells/decidim/profile_cell.rb +17 -0
  42. data/app/commands/decidim/create_omniauth_registration.rb +3 -2
  43. data/app/commands/decidim/create_report.rb +1 -1
  44. data/app/commands/decidim/invite_user.rb +2 -0
  45. data/app/constraints/decidim/current_component.rb +41 -0
  46. data/app/controllers/concerns/decidim/action_authorization.rb +3 -3
  47. data/app/controllers/concerns/decidim/devise_controllers.rb +2 -1
  48. data/app/controllers/concerns/decidim/filter_resource.rb +1 -1
  49. data/app/controllers/concerns/decidim/form_factory.rb +1 -1
  50. data/app/controllers/concerns/decidim/impersonate_users.rb +6 -2
  51. data/app/controllers/concerns/decidim/needs_authorization.rb +2 -2
  52. data/app/controllers/concerns/decidim/participatory_space_context.rb +15 -0
  53. data/app/controllers/concerns/decidim/settings.rb +5 -5
  54. data/app/controllers/decidim/application_controller.rb +2 -1
  55. data/app/controllers/decidim/{features → components}/base_controller.rb +16 -8
  56. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +3 -1
  57. data/app/controllers/decidim/devise/registrations_controller.rb +1 -3
  58. data/app/controllers/decidim/doorkeeper/authorizations_controller.rb +16 -0
  59. data/app/controllers/decidim/doorkeeper/credentials_controller.rb +46 -0
  60. data/app/controllers/decidim/doorkeeper/token_info_controller.rb +9 -0
  61. data/app/controllers/decidim/doorkeeper/tokens_controller.rb +9 -0
  62. data/app/controllers/decidim/widgets_controller.rb +1 -1
  63. data/app/forms/decidim/follow_form.rb +1 -1
  64. data/app/forms/decidim/form.rb +1 -1
  65. data/app/forms/decidim/omniauth_registration_form.rb +1 -0
  66. data/app/forms/decidim/registration_form.rb +5 -5
  67. data/app/helpers/decidim/card_helper.rb +16 -0
  68. data/app/helpers/decidim/component_path_helper.rb +36 -0
  69. data/app/helpers/decidim/icon_helper.rb +7 -7
  70. data/app/helpers/decidim/messaging/conversation_helper.rb +4 -3
  71. data/app/helpers/decidim/paginate_helper.rb +1 -1
  72. data/app/helpers/decidim/resource_helper.rb +2 -2
  73. data/app/jobs/decidim/export_job.rb +3 -3
  74. data/app/mailers/decidim/messaging/conversation_mailer.rb +0 -2
  75. data/app/middleware/decidim/current_organization.rb +2 -2
  76. data/app/models/decidim/abilities/admin_ability.rb +1 -1
  77. data/app/models/decidim/abilities/everyone_ability.rb +1 -1
  78. data/app/models/decidim/abilities/participatory_process_admin_ability.rb +2 -2
  79. data/app/models/decidim/abilities/participatory_process_collaborator_ability.rb +2 -2
  80. data/app/models/decidim/action_log.rb +7 -5
  81. data/app/models/decidim/area.rb +7 -0
  82. data/app/models/decidim/authorization.rb +14 -0
  83. data/app/models/decidim/{feature.rb → component.rb} +15 -15
  84. data/app/models/decidim/moderation.rb +1 -1
  85. data/app/models/decidim/oauth_application.rb +24 -0
  86. data/app/models/decidim/organization.rb +5 -0
  87. data/app/models/decidim/participatory_space_link.rb +20 -0
  88. data/app/models/decidim/participatory_space_private_user.rb +19 -0
  89. data/app/models/decidim/user.rb +7 -0
  90. data/app/presenters/decidim/admin_log/area_presenter.rb +38 -0
  91. data/app/presenters/decidim/admin_log/{feature_presenter.rb → component_presenter.rb} +5 -5
  92. data/app/presenters/decidim/admin_log/newsletter_resource_presenter.rb +1 -1
  93. data/app/presenters/decidim/admin_log/oauth_application_presenter.rb +50 -0
  94. data/app/presenters/decidim/admin_log/oauth_application_resource_presenter.rb +18 -0
  95. data/app/presenters/decidim/home_stats_presenter.rb +7 -7
  96. data/app/presenters/decidim/log/value_types/area_presenter.rb +1 -1
  97. data/app/presenters/decidim/log/value_types/area_type_presenter.rb +28 -0
  98. data/app/presenters/decidim/log/value_types/currency_presenter.rb +20 -0
  99. data/app/presenters/decidim/log/value_types/scope_presenter.rb +1 -1
  100. data/app/presenters/decidim/log/value_types/scope_type_presenter.rb +1 -1
  101. data/app/presenters/decidim/resource_locator_presenter.rb +3 -3
  102. data/app/services/decidim/action_authorizer.rb +9 -9
  103. data/app/services/decidim/action_logger.rb +9 -7
  104. data/app/services/decidim/email_notification_generator.rb +1 -1
  105. data/app/services/decidim/notification_generator_for_recipient.rb +1 -1
  106. data/app/services/decidim/resource_search.rb +8 -8
  107. data/app/services/decidim/settings_change.rb +5 -5
  108. data/app/services/decidim/static_map_generator.rb +1 -1
  109. data/app/types/decidim/core/attachment_type.rb +14 -0
  110. data/app/types/decidim/core/category_type.rb +16 -0
  111. data/app/types/decidim/core/coordinates_type.rb +19 -0
  112. data/app/types/decidim/core/scope_api_type.rb +16 -0
  113. data/app/uploaders/decidim/oauth_application_logo_uploader.rb +9 -0
  114. data/app/validators/geocoding_validator.rb +2 -2
  115. data/app/views/decidim/account/delete.html.erb +7 -7
  116. data/app/views/decidim/application/_collection.html.erb +1 -1
  117. data/app/views/decidim/application/_document.html.erb +1 -1
  118. data/app/views/decidim/application/_photos.html.erb +1 -1
  119. data/app/views/decidim/devise/invitations/edit.html.erb +1 -1
  120. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +1 -1
  121. data/app/views/decidim/devise/registrations/new.html.erb +1 -1
  122. data/app/views/decidim/devise/sessions/new.html.erb +2 -2
  123. data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +1 -1
  124. data/app/views/decidim/devise/shared/_omniauth_buttons_mini.html.erb +1 -1
  125. data/app/views/decidim/doorkeeper/authorizations/new.html.erb +58 -0
  126. data/app/views/decidim/messaging/conversations/_show.html.erb +1 -1
  127. data/app/views/decidim/messaging/conversations/index.html.erb +1 -1
  128. data/app/views/decidim/notifications/index.html.erb +1 -1
  129. data/app/views/decidim/notifications_settings/show.html.erb +2 -2
  130. data/app/views/decidim/own_user_groups/index.html.erb +3 -3
  131. data/app/views/decidim/scopes/_scopes_picker_input.html.erb +4 -4
  132. data/app/views/decidim/scopes/picker.html.erb +3 -3
  133. data/app/views/decidim/shared/_action_authorization_modal.html.erb +1 -1
  134. data/app/views/decidim/shared/_author.html.erb +1 -1
  135. data/app/views/decidim/shared/_author_reference.html.erb +1 -12
  136. data/app/views/decidim/shared/{_feature_announcement.html.erb → _component_announcement.html.erb} +2 -2
  137. data/app/views/decidim/shared/_embed_modal.html.erb +1 -1
  138. data/app/views/decidim/shared/_flag_modal.html.erb +5 -5
  139. data/app/views/decidim/shared/_login_modal.html.erb +3 -3
  140. data/app/views/decidim/shared/_private_participatory_space.html.erb +5 -0
  141. data/app/views/decidim/shared/_share_modal.html.erb +1 -1
  142. data/app/views/decidim/shared/_tags.html.erb +1 -1
  143. data/app/views/decidim/shared/_version_author.html.erb +1 -1
  144. data/app/views/decidim/widgets/_data_picker.html.erb +4 -4
  145. data/app/views/devise/mailer/confirmation_instructions.html.erb +3 -3
  146. data/app/views/devise/mailer/invite_private_user.html.erb +17 -0
  147. data/app/views/devise/mailer/invite_private_user.text.erb +15 -0
  148. data/app/views/devise/mailer/password_change.html.erb +2 -2
  149. data/app/views/devise/mailer/reset_password_instructions.html.erb +5 -5
  150. data/app/views/kaminari/decidim/_first_page.html.erb +2 -3
  151. data/app/views/kaminari/decidim/_gap.html.erb +2 -3
  152. data/app/views/kaminari/decidim/_last_page.html.erb +2 -3
  153. data/app/views/kaminari/decidim/_next_page.html.erb +2 -3
  154. data/app/views/kaminari/decidim/_page.html.erb +2 -3
  155. data/app/views/kaminari/decidim/_paginator.html.erb +1 -2
  156. data/app/views/kaminari/decidim/_prev_page.html.erb +2 -3
  157. data/app/views/layouts/decidim/_application.html.erb +4 -4
  158. data/app/views/layouts/decidim/_component_authorization_modals.html.erb +5 -0
  159. data/app/views/layouts/decidim/_cookie_warning.html.erb +2 -2
  160. data/app/views/layouts/decidim/_head.html.erb +4 -4
  161. data/app/views/layouts/decidim/_impersonation_warning.html.erb +4 -4
  162. data/app/views/layouts/decidim/_language_chooser.html.erb +1 -1
  163. data/app/views/layouts/decidim/_social_media_links.html.erb +5 -5
  164. data/app/views/layouts/decidim/_wrapper.html.erb +5 -5
  165. data/app/views/layouts/decidim/mailer.html.erb +1 -1
  166. data/app/views/layouts/decidim/widget.html.erb +5 -5
  167. data/app/views/pages/home/_hero.html.erb +1 -1
  168. data/app/views/pages/home.html.erb +6 -6
  169. data/config/locales/ca.yml +66 -27
  170. data/config/locales/en.yml +69 -30
  171. data/config/locales/es.yml +66 -27
  172. data/config/locales/eu.yml +69 -30
  173. data/config/locales/fi.yml +69 -30
  174. data/config/locales/fr.yml +85 -46
  175. data/config/locales/gl.yml +69 -30
  176. data/config/locales/it.yml +69 -30
  177. data/config/locales/nl.yml +122 -83
  178. data/config/locales/pl.yml +69 -30
  179. data/config/locales/pt-BR.yml +69 -30
  180. data/config/locales/pt.yml +69 -30
  181. data/config/locales/ru.yml +0 -7
  182. data/config/locales/sv.yml +69 -30
  183. data/config/locales/uk.yml +0 -13
  184. data/config/routes.rb +8 -0
  185. data/db/migrate/20180206183235_create_participatory_space_private_users.rb +15 -0
  186. data/db/migrate/20180221101934_fix_nickname_index.rb +5 -6
  187. data/db/migrate/20180226140756_add_version_to_action_logs.rb +5 -1
  188. data/db/migrate/20180227131727_create_participatory_space_links.rb +12 -0
  189. data/db/migrate/20180305132906_rename_features_to_components.rb +13 -0
  190. data/db/migrate/20180308113207_doorkeeper_models.rb +85 -0
  191. data/db/migrate/20180314085339_rename_maximum_votes_per_proposal_to_threshold_per_proposal.rb +2 -2
  192. 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
  193. data/db/seeds.rb +12 -2
  194. data/lib/decidim/api/attachable_interface.rb +13 -0
  195. data/lib/decidim/api/authorable_interface.rb +13 -0
  196. data/lib/decidim/api/categorizable_interface.rb +13 -0
  197. data/lib/decidim/api/participatory_space_interface.rb +4 -4
  198. data/lib/decidim/api/scopable_interface.rb +13 -0
  199. data/lib/decidim/authorable.rb +8 -0
  200. data/lib/decidim/{feature_manifest.rb → component_manifest.rb} +24 -21
  201. data/lib/decidim/{feature_validator.rb → component_validator.rb} +6 -6
  202. data/lib/decidim/{features → components}/export_manifest.rb +4 -4
  203. data/lib/decidim/components/namer.rb +35 -0
  204. data/lib/decidim/components.rb +9 -0
  205. data/lib/decidim/content_parsers/user_parser.rb +1 -1
  206. data/lib/decidim/core/api.rb +13 -0
  207. data/lib/decidim/core/engine.rb +76 -3
  208. data/lib/decidim/core/test/factories.rb +43 -10
  209. data/lib/decidim/core/test/shared_examples/announcements_examples.rb +9 -9
  210. data/lib/decidim/core/test/shared_examples/attachable_interface_examples.rb +16 -0
  211. data/lib/decidim/core/test/shared_examples/authorable_interface_examples.rb +33 -0
  212. data/lib/decidim/core/test/shared_examples/categorizable_interface_examples.rb +19 -0
  213. data/lib/decidim/core/test/shared_examples/comments_examples.rb +3 -3
  214. data/lib/decidim/core/test/shared_examples/follows_examples.rb +1 -1
  215. data/lib/decidim/core/test/shared_examples/has_component.rb +21 -0
  216. data/lib/decidim/core/test/shared_examples/has_reference.rb +2 -2
  217. data/lib/decidim/core/test/shared_examples/localised_email.rb +1 -1
  218. data/lib/decidim/core/test/shared_examples/paginated_resource_examples.rb +1 -1
  219. data/lib/decidim/core/test/shared_examples/reportable.rb +8 -6
  220. data/lib/decidim/core/test/shared_examples/reports_examples.rb +1 -1
  221. data/lib/decidim/core/test/shared_examples/scopable_interface_examples.rb +19 -0
  222. data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +8 -3
  223. data/lib/decidim/core/test/shared_examples/simple_event.rb +1 -1
  224. data/lib/decidim/core/test/shared_examples/user_localised_email_examples.rb +1 -1
  225. data/lib/decidim/core/test.rb +1 -1
  226. data/lib/decidim/core/version.rb +1 -1
  227. data/lib/decidim/core.rb +35 -37
  228. data/lib/decidim/events/base_event.rb +5 -5
  229. data/lib/decidim/events/simple_event.rb +8 -8
  230. data/lib/decidim/form_builder.rb +48 -3
  231. data/lib/decidim/has_attachment_collections.rb +1 -1
  232. data/lib/decidim/has_attachments.rb +1 -1
  233. data/lib/decidim/has_category.rb +2 -2
  234. data/lib/decidim/has_component.rb +23 -0
  235. data/lib/decidim/has_private_users.rb +26 -0
  236. data/lib/decidim/has_reference.rb +3 -3
  237. data/lib/decidim/page_finder.rb +1 -1
  238. data/lib/decidim/participatory_space_manifest.rb +3 -3
  239. data/lib/decidim/participatory_space_resourceable.rb +80 -0
  240. data/lib/decidim/publicable.rb +2 -2
  241. data/lib/decidim/query_extensions.rb +2 -2
  242. data/lib/decidim/rectify_ext.rb +32 -0
  243. data/lib/decidim/reportable.rb +1 -1
  244. data/lib/decidim/resource_manifest.rb +13 -13
  245. data/lib/decidim/resourceable.rb +8 -8
  246. data/lib/decidim/scopable.rb +1 -1
  247. data/lib/decidim/{scopable_feature.rb → scopable_component.rb} +1 -1
  248. data/lib/decidim/settings_manifest.rb +1 -1
  249. data/lib/decidim/stats_registry.rb +1 -1
  250. data/lib/decidim/view_model.rb +9 -0
  251. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.fr.js +4 -1
  252. data/vendor/assets/javascripts/form_datepicker.js.es6 +10 -10
  253. data/vendor/assets/javascripts/quill.min.js +2 -2
  254. data/vendor/assets/javascripts/quill.min.js.map +1 -1
  255. data/vendor/assets/javascripts/tagsinput.js +683 -0
  256. data/vendor/assets/javascripts/tribute.js +1607 -0
  257. data/vendor/assets/stylesheets/quill.bubble.css +30 -16
  258. data/vendor/assets/stylesheets/quill.core.css +19 -9
  259. data/vendor/assets/stylesheets/quill.snow.css +30 -16
  260. data/vendor/assets/stylesheets/tagsinput.css +55 -0
  261. data/vendor/assets/stylesheets/tribute.css +27 -0
  262. metadata +164 -27
  263. data/app/constraints/decidim/current_feature.rb +0 -41
  264. data/app/helpers/decidim/feature_path_helper.rb +0 -36
  265. data/app/views/layouts/decidim/_feature_authorization_modals.html.erb +0 -5
  266. data/lib/decidim/core/test/shared_examples/has_feature.rb +0 -21
  267. data/lib/decidim/features/namer.rb +0 -35
  268. data/lib/decidim/features.rb +0 -9
  269. 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/features/export_manifest"
4
+ require "decidim/components/export_manifest"
5
5
 
6
6
  module Decidim
7
- # This class handles all the logic associated to configuring a feature
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.register_feature`.
12
- class FeatureManifest
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 feature's icon. The icon must be stored in 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 feature against particular
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 Feature can expose as many actions as it wants and the admin panel will
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 feature takes place.
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 features in order to populate the database.
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 feature, scoped to a name. It
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
- # feature.settings(:global) do |settings|
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 feature manifest. Exposes a DSL
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.feature_manifest = self
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::Features::ExportManifest`.
143
+ # defined in `Decidim::Components::ExportManifest`.
141
144
  #
142
- # Export artifacts provide an unified way for features to register
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 feature.
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 feature.
161
+ # for this component.
159
162
  #
160
- # Returns an Array<Decidim::Features::ExportManifest>.
163
+ # Returns an Array<Decidim::Components::ExportManifest>.
161
164
  def export_manifests
162
165
  @export_manifests ||= @exports.map do |(name, block)|
163
- Decidim::Features::ExportManifest.new(name).tap do |manifest|
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 feature manifest.
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 features to filter out the stat.
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 features are correctly assigned to a model.
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 FeatureValidator < ActiveModel::EachValidator
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 feature" if options[:manifest].blank?
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, feature)
15
- unless feature
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 feature.manifest_name.to_s != options[:manifest].to_s
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 Features
4
+ module Components
5
5
  # This class serves as a DSL to declarative specify which artifacts are
6
- # exportable in a feature. It is used via the `FeatureManifest`.
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
- # feature.
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::Feature` when
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.where(nickname: Regexp.last_match[2], organization: context[:current_organization]).first)
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
@@ -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.feature_manifests.each do |feature|
60
- app.config.assets.precompile += [feature.icon]
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.query_extensions" do
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 :feature, class: "Decidim::Feature" do
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
- feature { create(:feature, manifest_name: "dummy") }
265
- author { create(:user, :confirmed, organization: feature.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, feature: to.feature) }
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.feature.participatory_space }
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
- feature { build :feature, participatory_space: participatory_space }
343
- resource { build(:dummy_resource, feature: feature) }
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
- feature: {
348
- manifest_name: feature.try(:manifest_name),
349
- title: feature.try(:name) || feature.try(: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 feature" do
5
- visit edit_feature_path(current_feature)
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
- :feature_settings_announcement,
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 main_feature_path(current_feature)
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
- current_feature.update!(
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 edit_feature_path(current_feature)
39
- step_id = current_feature.participatory_space.steps.first.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
- :"feature_step_settings_#{step_id}_announcement",
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 main_feature_path(current_feature)
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?
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  shared_examples "follows" do
4
- include_context "with a feature"
4
+ include_context "with a component"
5
5
 
6
6
  before do
7
7
  login_as user, scope: :user