decidim-core 0.8.4 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (249) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +1 -1
  3. data/app/assets/images/decidim/decidim-logo.svg +23 -23
  4. data/app/assets/images/decidim/default-avatar.svg +7 -7
  5. data/app/assets/images/decidim/icons.svg +1 -0
  6. data/app/assets/javascripts/decidim.js.es6 +5 -2
  7. data/app/assets/javascripts/decidim/append_redirect_url_to_modals.js.es6 +84 -0
  8. data/app/assets/javascripts/decidim/data_picker.js.es6 +177 -0
  9. data/app/assets/javascripts/decidim/form_filter.component.js.es6 +25 -20
  10. data/app/assets/javascripts/decidim/form_filter.component.test.js +24 -13
  11. data/app/assets/javascripts/decidim/history.js.es6 +3 -3
  12. data/app/assets/stylesheets/decidim/_decidim.scss +1 -4
  13. data/app/assets/stylesheets/decidim/_variables.scss +4 -4
  14. data/app/assets/stylesheets/decidim/editor.scss +13 -0
  15. data/app/assets/stylesheets/decidim/email.css +9 -1
  16. data/app/assets/stylesheets/decidim/extras/_add_comments.scss +3 -3
  17. data/app/assets/stylesheets/decidim/extras/_announcement.scss +1 -1
  18. data/app/assets/stylesheets/decidim/extras/_collection-sort-controls.scss +2 -2
  19. data/app/assets/stylesheets/decidim/extras/_embed.scss +6 -5
  20. data/app/assets/stylesheets/decidim/extras/_impersonation-bar.scss +4 -0
  21. data/app/assets/stylesheets/decidim/extras/_label-required.scss +1 -1
  22. data/app/assets/stylesheets/decidim/extras/_leaflet.scss +6 -4
  23. data/app/assets/stylesheets/decidim/extras/_meeting-registrations.scss +4 -4
  24. data/app/assets/stylesheets/decidim/extras/_process_stats.scss +11 -4
  25. data/app/assets/stylesheets/decidim/extras/_proposal_form.scss +3 -3
  26. data/app/assets/stylesheets/decidim/extras/_quill.scss +1 -1
  27. data/app/assets/stylesheets/decidim/extras/_reference.scss +3 -3
  28. data/app/assets/stylesheets/decidim/extras/_register_form.scss +3 -3
  29. data/app/assets/stylesheets/decidim/extras/_results-per-page.scss +10 -10
  30. data/app/assets/stylesheets/decidim/extras/_social_icons_mini.scss +4 -3
  31. data/app/assets/stylesheets/decidim/layouts/_highlighted_banner.scss +38 -0
  32. data/app/assets/stylesheets/decidim/layouts/_home.scss +33 -3
  33. data/app/assets/stylesheets/decidim/layouts/_user.scss +33 -5
  34. data/app/assets/stylesheets/decidim/layouts/_view.scss +1 -2
  35. data/app/assets/stylesheets/decidim/map.css +5 -3
  36. data/app/assets/stylesheets/decidim/modules/_address.scss +1 -0
  37. data/app/assets/stylesheets/decidim/modules/_author-avatar.scss +24 -9
  38. data/app/assets/stylesheets/decidim/modules/_buttons.scss +24 -10
  39. data/app/assets/stylesheets/decidim/modules/_callout.scss +5 -1
  40. data/app/assets/stylesheets/decidim/modules/_card-grid.scss +1 -1
  41. data/app/assets/stylesheets/decidim/modules/_cards.scss +102 -31
  42. data/app/assets/stylesheets/decidim/modules/_comments.scss +21 -20
  43. data/app/assets/stylesheets/decidim/modules/_cookie-bar.scss +4 -0
  44. data/app/assets/stylesheets/decidim/modules/_data-picker.scss +159 -0
  45. data/app/assets/stylesheets/decidim/modules/_datepicker.scss +36 -36
  46. data/app/assets/stylesheets/decidim/modules/_definition-data.scss +12 -9
  47. data/app/assets/stylesheets/decidim/modules/_extra.scss +4 -1
  48. data/app/assets/stylesheets/decidim/modules/_filter-tags.scss +3 -0
  49. data/app/assets/stylesheets/decidim/modules/_filters.scss +9 -5
  50. data/app/assets/stylesheets/decidim/modules/_flag.scss +1 -0
  51. data/app/assets/stylesheets/decidim/modules/_footer.scss +10 -0
  52. data/app/assets/stylesheets/decidim/modules/_forms.scss +2 -1
  53. data/app/assets/stylesheets/decidim/modules/_help.scss +2 -0
  54. data/app/assets/stylesheets/decidim/modules/_icons.scss +1 -0
  55. data/app/assets/stylesheets/decidim/modules/_layout.scss +4 -0
  56. data/app/assets/stylesheets/decidim/modules/_list-docs.scss +3 -0
  57. data/app/assets/stylesheets/decidim/modules/_main-container.scss +13 -7
  58. data/app/assets/stylesheets/decidim/modules/_map.scss +13 -1
  59. data/app/assets/stylesheets/decidim/modules/_margins.scss +1 -0
  60. data/app/assets/stylesheets/decidim/modules/_messages.scss +2 -1
  61. data/app/assets/stylesheets/decidim/modules/_modules.scss +3 -0
  62. data/app/assets/stylesheets/decidim/modules/_navbar.scss +36 -16
  63. data/app/assets/stylesheets/decidim/modules/_omnipresent_banner.scss +26 -0
  64. data/app/assets/stylesheets/decidim/modules/_opinion-toggle.scss +5 -0
  65. data/app/assets/stylesheets/decidim/modules/_order-by.scss +10 -10
  66. data/app/assets/stylesheets/decidim/modules/_pagination.scss +3 -2
  67. data/app/assets/stylesheets/decidim/modules/_process-header.scss +11 -2
  68. data/app/assets/stylesheets/decidim/modules/_process-info.scss +9 -1
  69. data/app/assets/stylesheets/decidim/modules/_process-nav.scss +20 -3
  70. data/app/assets/stylesheets/decidim/modules/_process-phase.scss +12 -3
  71. data/app/assets/stylesheets/decidim/modules/_progress-bar.scss +69 -0
  72. data/app/assets/stylesheets/decidim/modules/_reference.scss +1 -2
  73. data/app/assets/stylesheets/decidim/modules/_reveal.scss +1 -1
  74. data/app/assets/stylesheets/decidim/modules/_share.scss +2 -0
  75. data/app/assets/stylesheets/decidim/modules/_signup.scss +5 -1
  76. data/app/assets/stylesheets/decidim/modules/_static-pages.scss +6 -0
  77. data/app/assets/stylesheets/decidim/modules/_status-labels.scss +2 -0
  78. data/app/assets/stylesheets/decidim/modules/_tags.scss +3 -1
  79. data/app/assets/stylesheets/decidim/modules/_timeline.scss +41 -30
  80. data/app/assets/stylesheets/decidim/modules/_title-action.scss +2 -1
  81. data/app/assets/stylesheets/decidim/modules/_typography.scss +13 -4
  82. data/app/assets/stylesheets/decidim/modules/_user-form.scss +1 -0
  83. data/app/assets/stylesheets/decidim/modules/_video.scss +2 -2
  84. data/app/assets/stylesheets/decidim/utils/_fontface.scss +22 -20
  85. data/app/assets/stylesheets/decidim/utils/_helpers.scss +6 -6
  86. data/app/assets/stylesheets/decidim/utils/_keyframes.scss +6 -6
  87. data/app/assets/stylesheets/decidim/utils/_mixins.scss +24 -7
  88. data/app/assets/stylesheets/decidim/utils/_settings.scss +50 -52
  89. data/app/assets/stylesheets/decidim/utils/_toggle-expand.scss +1 -0
  90. data/app/commands/decidim/create_omniauth_registration.rb +3 -0
  91. data/app/commands/decidim/create_registration.rb +3 -1
  92. data/app/commands/decidim/destroy_account.rb +1 -0
  93. data/app/commands/decidim/invite_user_again.rb +1 -1
  94. data/app/commands/decidim/messaging/reply_to_conversation.rb +1 -3
  95. data/app/commands/decidim/unsubscribe_settings.rb +29 -0
  96. data/app/commands/decidim/update_account.rb +16 -3
  97. data/app/controllers/concerns/decidim/action_authorization.rb +1 -1
  98. data/app/controllers/concerns/decidim/devise_controllers.rb +10 -0
  99. data/app/controllers/concerns/decidim/form_factory.rb +2 -1
  100. data/app/controllers/concerns/decidim/impersonate_users.rb +13 -8
  101. data/app/controllers/concerns/decidim/participatory_space_context.rb +1 -1
  102. data/app/controllers/decidim/application_controller.rb +16 -0
  103. data/app/controllers/decidim/cookie_policy_controller.rb +2 -0
  104. data/app/controllers/decidim/devise/invitations_controller.rb +9 -1
  105. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +10 -1
  106. data/app/controllers/decidim/devise/sessions_controller.rb +9 -1
  107. data/app/controllers/decidim/locales_controller.rb +2 -3
  108. data/app/controllers/decidim/messaging/conversations_controller.rb +2 -2
  109. data/app/controllers/decidim/newsletters_controller.rb +60 -0
  110. data/app/controllers/decidim/pages_controller.rb +1 -0
  111. data/app/controllers/decidim/profiles_controller.rb +23 -0
  112. data/app/controllers/decidim/scopes_controller.rb +19 -20
  113. data/app/events/decidim/profile_updated_event.rb +27 -0
  114. data/app/forms/decidim/account_form.rb +34 -0
  115. data/app/forms/decidim/form.rb +1 -0
  116. data/app/forms/decidim/messaging/conversation_form.rb +5 -2
  117. data/app/forms/decidim/omniauth_registration_form.rb +5 -0
  118. data/app/forms/decidim/registration_form.rb +8 -1
  119. data/app/helpers/decidim/action_authorization_helper.rb +2 -2
  120. data/app/helpers/decidim/application_helper.rb +8 -0
  121. data/app/helpers/decidim/feature_path_helper.rb +12 -2
  122. data/app/helpers/decidim/feature_reference_helper.rb +1 -1
  123. data/app/helpers/decidim/messaging/conversation_helper.rb +27 -9
  124. data/app/helpers/decidim/newsletters_helper.rb +49 -0
  125. data/app/helpers/decidim/scopes_helper.rb +43 -2
  126. data/app/helpers/decidim/translations_helper.rb +6 -2
  127. data/app/mailers/decidim/decidim_devise_mailer.rb +1 -3
  128. data/app/mailers/decidim/messaging/conversation_mailer.rb +1 -1
  129. data/app/mailers/decidim/newsletter_mailer.rb +7 -8
  130. data/app/models/decidim/abilities/everyone_ability.rb +1 -0
  131. data/app/models/decidim/authorization.rb +19 -5
  132. data/app/models/decidim/impersonation_log.rb +2 -1
  133. data/app/models/decidim/messaging/conversation.rb +2 -0
  134. data/app/models/decidim/messaging/message.rb +4 -0
  135. data/app/models/decidim/organization.rb +1 -0
  136. data/app/models/decidim/scope.rb +10 -2
  137. data/app/models/decidim/user.rb +10 -2
  138. data/app/presenters/decidim/home_stats_presenter.rb +10 -4
  139. data/app/presenters/decidim/user_group_presenter.rb +28 -0
  140. data/app/presenters/decidim/user_presenter.rb +42 -0
  141. data/app/services/decidim/action_authorizer.rb +32 -68
  142. data/app/services/decidim/notification_generator_for_recipient.rb +8 -3
  143. data/app/uploaders/decidim/avatar_uploader.rb +2 -2
  144. data/app/views/decidim/account/delete.html.erb +1 -1
  145. data/app/views/decidim/account/show.html.erb +4 -1
  146. data/app/views/decidim/devise/invitations/edit.html.erb +2 -0
  147. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +7 -1
  148. data/app/views/decidim/devise/registrations/new.html.erb +7 -1
  149. data/app/views/decidim/messaging/conversations/_message.html.erb +6 -12
  150. data/app/views/decidim/messaging/conversations/_reply.html.erb +1 -1
  151. data/app/views/decidim/messaging/conversations/index.html.erb +1 -1
  152. data/app/views/decidim/messaging/conversations/update.js.erb +1 -0
  153. data/app/views/decidim/newsletter_mailer/newsletter.html.erb +11 -0
  154. data/app/views/decidim/newsletters/show.html.erb +11 -0
  155. data/app/views/decidim/newsletters/unsubscribe.html.erb +4 -0
  156. data/app/views/decidim/notifications/_notification.html.erb +1 -1
  157. data/app/views/decidim/profiles/show.html.erb +64 -0
  158. data/app/views/decidim/scopes/_scopes_picker_input.html.erb +6 -0
  159. data/app/views/decidim/scopes/picker.html.erb +36 -0
  160. data/app/views/decidim/shared/_action_authorization_modal.html.erb +25 -51
  161. data/app/views/decidim/shared/_author.html.erb +21 -0
  162. data/app/views/decidim/shared/_author_reference.html.erb +12 -0
  163. data/app/views/layouts/decidim/_application.html.erb +1 -0
  164. data/app/views/layouts/decidim/_impersonation_warning.html.erb +1 -1
  165. data/app/views/layouts/decidim/_mailer_logo.html.erb +6 -1
  166. data/app/views/layouts/decidim/_omnipresent_banner.html.erb +14 -0
  167. data/app/views/layouts/decidim/_user_menu.html.erb +3 -0
  168. data/app/views/layouts/decidim/mailer.html.erb +16 -4
  169. data/app/views/layouts/decidim/widget.html.erb +14 -9
  170. data/app/views/pages/home.html.erb +2 -0
  171. data/app/views/pages/home/_highlighted_content_banner.html.erb +26 -0
  172. data/config/initializers/devise.rb +1 -3
  173. data/config/locales/ca.yml +67 -9
  174. data/config/locales/en.yml +65 -4
  175. data/config/locales/es.yml +74 -14
  176. data/config/locales/eu.yml +66 -4
  177. data/config/locales/fi.yml +87 -25
  178. data/config/locales/fr.yml +71 -9
  179. data/config/locales/gl.yml +493 -0
  180. data/config/locales/it.yml +79 -17
  181. data/config/locales/nl.yml +71 -9
  182. data/config/locales/pl.yml +66 -4
  183. data/config/locales/pt-BR.yml +493 -0
  184. data/config/locales/pt.yml +99 -37
  185. data/config/locales/ru.yml +85 -13
  186. data/config/locales/sv.yml +493 -0
  187. data/config/locales/uk.yml +78 -16
  188. data/config/routes.rb +11 -1
  189. data/db/migrate/20171212103803_create_unique_nicknames.rb +29 -0
  190. data/db/migrate/20180115090038_extend_user_profile.rb +8 -0
  191. data/db/migrate/20180123125308_add_enable_omnipresent_banner_to_decidim_organizations.rb +7 -0
  192. data/db/migrate/20180123125409_add_omnipresent_banner_title_to_decidim_organizations.rb +7 -0
  193. data/db/migrate/20180123125432_add_omnipresent_banner_short_description_to_decidim_organizations.rb +7 -0
  194. data/db/migrate/20180123125452_add_omnipresent_banner_url_to_decidim_organizations.rb +7 -0
  195. data/db/migrate/20180125063433_add_highlighted_content_banner_to_decidim_organizations.rb +13 -0
  196. data/db/seeds.rb +8 -2
  197. data/lib/decidim/abilities/participatory_process_role_ability.rb +1 -3
  198. data/lib/decidim/content_parsers.rb +8 -0
  199. data/lib/decidim/content_parsers/base_parser.rb +58 -0
  200. data/lib/decidim/content_parsers/user_parser.rb +46 -0
  201. data/lib/decidim/content_processor.rb +84 -0
  202. data/lib/decidim/content_renderers.rb +8 -0
  203. data/lib/decidim/content_renderers/base_renderer.rb +37 -0
  204. data/lib/decidim/content_renderers/user_renderer.rb +32 -0
  205. data/lib/decidim/core.rb +66 -1
  206. data/lib/decidim/core/api/author_interface.rb +3 -3
  207. data/lib/decidim/core/api/user_group_type.rb +10 -8
  208. data/lib/decidim/core/api/user_type.rb +13 -7
  209. data/lib/decidim/core/engine.rb +7 -5
  210. data/lib/decidim/core/test.rb +1 -1
  211. data/lib/decidim/core/test/factories.rb +21 -45
  212. data/lib/decidim/core/test/shared_examples/announcements_examples.rb +3 -2
  213. data/lib/decidim/core/test/shared_examples/comments_examples.rb +5 -2
  214. data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +40 -3
  215. data/lib/decidim/core/test/shared_examples/simple_event.rb +73 -0
  216. data/lib/decidim/core/version.rb +1 -1
  217. data/lib/decidim/events.rb +2 -0
  218. data/lib/decidim/events/author_event.rb +41 -0
  219. data/lib/decidim/events/base_event.rb +28 -3
  220. data/lib/decidim/events/email_event.rb +1 -1
  221. data/lib/decidim/events/notification_event.rb +1 -1
  222. data/lib/decidim/events/simple_event.rb +79 -0
  223. data/lib/decidim/filter_form_builder.rb +2 -3
  224. data/lib/decidim/form_builder.rb +39 -27
  225. data/lib/decidim/friendly_dates.rb +26 -0
  226. data/lib/decidim/has_feature.rb +1 -0
  227. data/lib/decidim/has_reference.rb +1 -1
  228. data/lib/decidim/i18n_exceptions.rb +1 -3
  229. data/lib/decidim/menu.rb +1 -1
  230. data/lib/decidim/newsletter_encryptor.rb +22 -0
  231. data/lib/decidim/nicknamizable.rb +56 -0
  232. data/lib/decidim/participable.rb +8 -0
  233. data/lib/decidim/participatory_space_manifest.rb +10 -1
  234. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.gl.js +13 -0
  235. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.pt-br.js +14 -0
  236. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.pt.js +5 -1
  237. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.ru.js +4 -1
  238. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.sv.js +14 -0
  239. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.uk.js +4 -1
  240. data/vendor/assets/javascripts/form_datepicker.js.es6 +4 -2
  241. data/vendor/assets/javascripts/foundation-datepicker.js +42 -26
  242. metadata +124 -84
  243. data/app/assets/javascripts/decidim/select2.field.js.es6 +0 -47
  244. data/app/assets/javascripts/decidim/select2.js.es6 +0 -11
  245. data/app/assets/stylesheets/decidim/editor.sass +0 -4
  246. data/app/assets/stylesheets/decidim/plugins/_select2.scss +0 -63
  247. data/app/helpers/decidim/datetime_helper.rb +0 -23
  248. data/app/queries/decidim/freetext_scopes.rb +0 -39
  249. data/lib/decidim/core/test/shared_examples/manage_moderations_examples.rb +0 -64
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # This module contains all logic related to decidim's ability for process a content.
5
+ # Their main job is to {ContentProcessor#parse parse} or {ContentProcessor#render render}
6
+ # a content calling all the registered processors in the Decidim.content_processors config.
7
+ #
8
+ # Note that to render a content this must have been parsed before.
9
+ #
10
+ # When creating a new processor, the both sides must be declared: parser and renderer
11
+ # e.g. If we are creating a processor to parse and render user mentions, we can call this
12
+ # the `user` processor, so we will declare the parser and renderer classes like that:
13
+ #
14
+ # Decidim::ContentParsers::UserParser
15
+ # Decidim::ContentRenderers::UserRenderer
16
+ #
17
+ # and register it in an initializer, so it is executed:
18
+ #
19
+ # Decidim.content_processors += [:user]
20
+ #
21
+ # If for some reason you only want to do something in one of the both sides, please, also
22
+ # declare the other side making it "transparent" (declaring the class and leaving it empty).
23
+ #
24
+ # @example How to parse a content
25
+ # parsed = Decidim::ContentProcessor.parse(content)
26
+ # parsed.rewrite # contains rewritten content
27
+ # parsed.metadata # contains the merged metadata of all parsers
28
+ #
29
+ # @example How to render a content (must have been parsed before)
30
+ # rendered = Decidim::ContentProcessor.render(content)
31
+ # puts rendered
32
+ module ContentProcessor
33
+ # Class that represents the result of processing a text
34
+ #
35
+ # @!attribute rewrite
36
+ # @return [String] the rewritten content
37
+ # @!attribute metadata
38
+ # @return [Hash<Symbol, Metadata>] a hash where the keys are the parsers
39
+ # names, and the values are the Metadata object returned by the parser
40
+ Result = Struct.new(:rewrite, :metadata)
41
+
42
+ # This calls all registered processors one after the other and collects the
43
+ # metadata for each one and the resulting modified content
44
+ #
45
+ # @return [Result] a Result object with the content rewritten and the metadata
46
+ def self.parse(content)
47
+ parsed = Decidim.content_processors.each_with_object(rewrite: content, metadata: {}) do |type, result|
48
+ parser = parser_klass(type).constantize.new(result[:rewrite])
49
+ result[:rewrite] = parser.rewrite
50
+ result[:metadata][type] = parser.metadata
51
+ end
52
+
53
+ Result.new(parsed[:rewrite], parsed[:metadata])
54
+ end
55
+
56
+ # This calls all registered processors one after the other and returns
57
+ # the processed content ready to display.
58
+ #
59
+ # @return [String] the content processed and ready to display (it is expected to include HTML)
60
+ def self.render(content)
61
+ Decidim.content_processors.reduce(content) do |result, type|
62
+ renderer_klass(type).constantize.new(result).render
63
+ end
64
+ end
65
+
66
+ # Guess the class name of the parser for a processor
67
+ # represented by the given symbol
68
+ #
69
+ # @api private
70
+ # @return [String] the content parser class name
71
+ def self.parser_klass(type)
72
+ "Decidim::ContentParsers::#{type.to_s.camelize}Parser"
73
+ end
74
+
75
+ # Guess the class name of the renderer for a processor
76
+ # represented by the given symbol
77
+ #
78
+ # @api private
79
+ # @return [String] the content renderer class name
80
+ def self.renderer_klass(type)
81
+ "Decidim::ContentRenderers::#{type.to_s.camelize}Renderer"
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ContentRenderers
5
+ autoload :BaseRenderer, "decidim/content_renderers/base_renderer"
6
+ autoload :UserRenderer, "decidim/content_renderers/user_renderer"
7
+ end
8
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ContentRenderers
5
+ # Abstract base class for content renderers, so they have the same contract
6
+ #
7
+ # @example How to use a content renderer class
8
+ # renderer = Decidim::ContentRenderers::CustomRenderer.new(content)
9
+ # parser.render # returns the content formatted
10
+ #
11
+ # @abstract Subclass and override {#render} to implement a content renderer
12
+ class BaseRenderer
13
+ # @return [String] the content to be formatted
14
+ attr_reader :content
15
+
16
+ # Gets initialized with the `content` to format
17
+ #
18
+ # @param content [String] content to be formatted
19
+ def initialize(content)
20
+ @content = content || ""
21
+ end
22
+
23
+ # Format the content and return it ready to display
24
+ #
25
+ # @example Implementation to display prohibited words
26
+ # def render
27
+ # content.gsub(/\~\~(.*?)\~\~/, '<del>\1</del>')
28
+ # end
29
+ #
30
+ # @abstract Subclass is expected to implement it
31
+ # @return [String] the content processed and ready to display
32
+ def render
33
+ content
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module ContentRenderers
5
+ # A renderer that searches Global IDs representing users in content
6
+ # and replaces it with a link to their profile with the nickname.
7
+ #
8
+ # e.g. gid://<APP_NAME>/Decidim::User/1
9
+ #
10
+ # @see BaseRenderer Examples of how to use a content renderer
11
+ class UserRenderer < BaseRenderer
12
+ # Matches a global id representing a Decidim::User
13
+ GLOBAL_ID_REGEX = %r{gid://.*/Decidim::User/\d+}
14
+
15
+ # Replaces found Global IDs matching an existing user with
16
+ # a link to their profile. The Global IDs representing an
17
+ # invalid Decidim::User are replaced with an empty string.
18
+ #
19
+ # @return [String] the content ready to display (contains HTML)
20
+ def render
21
+ content.gsub(GLOBAL_ID_REGEX) do |user_gid|
22
+ begin
23
+ user = GlobalID::Locator.locate(user_gid)
24
+ Decidim::UserPresenter.new(user).display_mention
25
+ rescue ActiveRecord::RecordNotFound => _ex
26
+ ""
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
data/lib/decidim/core.rb CHANGED
@@ -21,6 +21,9 @@ module Decidim
21
21
  autoload :Participable, "decidim/participable"
22
22
  autoload :Publicable, "decidim/publicable"
23
23
  autoload :Scopable, "decidim/scopable"
24
+ autoload :ContentParsers, "decidim/content_parsers"
25
+ autoload :ContentRenderers, "decidim/content_renderers"
26
+ autoload :ContentProcessor, "decidim/content_processor"
24
27
  autoload :Features, "decidim/features"
25
28
  autoload :HasAttachments, "decidim/has_attachments"
26
29
  autoload :FeatureValidator, "decidim/feature_validator"
@@ -29,6 +32,8 @@ module Decidim
29
32
  autoload :HasScope, "decidim/has_scope"
30
33
  autoload :HasCategory, "decidim/has_category"
31
34
  autoload :Followable, "decidim/followable"
35
+ autoload :FriendlyDates, "decidim/friendly_dates"
36
+ autoload :Nicknamizable, "decidim/nicknamizable"
32
37
  autoload :HasReference, "decidim/has_reference"
33
38
  autoload :Attributes, "decidim/attributes"
34
39
  autoload :StatsRegistry, "decidim/stats_registry"
@@ -43,6 +48,7 @@ module Decidim
43
48
  autoload :EngineRouter, "decidim/engine_router"
44
49
  autoload :Events, "decidim/events"
45
50
  autoload :ViewHooks, "decidim/view_hooks"
51
+ autoload :NewsletterEncryptor, "decidim/newsletter_encryptor"
46
52
 
47
53
  include ActiveSupport::Configurable
48
54
 
@@ -87,7 +93,24 @@ module Decidim
87
93
 
88
94
  # Exposes a configuration option: The application available locales.
89
95
  config_accessor :available_locales do
90
- %w(en ca es eu it fi fr nl uk ru)
96
+ %w(en ca es eu fi fr gl it nl pt pr-BR ru sv uk)
97
+ end
98
+
99
+ # Exposes a configuration option: an array of symbols representing processors
100
+ # that will be automatically executed when a content is parsed or rendered.
101
+ #
102
+ # A content processor is a concept to refer to a set of two classes:
103
+ # the content parser class and the content renderer class.
104
+ # e.g. If we register a content processor named `user`:
105
+ #
106
+ # Decidim.content_processors += [:user]
107
+ #
108
+ # we must declare the following classes:
109
+ #
110
+ # Decidim::ContentParsers::UserParser < BaseParser
111
+ # Decidim::ContentRenderers::UserRenderer < BaseRenderer
112
+ config_accessor :content_processors do
113
+ []
91
114
  end
92
115
 
93
116
  # Exposes a configuration option: The application default locale.
@@ -143,12 +166,54 @@ module Decidim
143
166
  true
144
167
  end
145
168
 
169
+ # Allow organization's administrators to track newsletter links
170
+ config_accessor :track_newsletter_links do
171
+ true
172
+ end
173
+
146
174
  # A base path for the uploads. If set, make sure it ends in a slash.
147
175
  # Uploads will be set to `<base_path>/uploads/`. This can be useful if you
148
176
  # want to use the same uploads place for both staging and production
149
177
  # environments, but in different folders.
150
178
  config_accessor :base_uploads_path
151
179
 
180
+ # Public: Registers a global engine. This method is intended to be used
181
+ # by feature engines that also offer unscoped functionality
182
+ #
183
+ # name - The name of the engine to register. Should be unique.
184
+ # engine - The engine to register.
185
+ # options - Options to pass to the engine.
186
+ # :at - The route to mount the engine to.
187
+ #
188
+ # Returns nothing.
189
+ def self.register_global_engine(name, engine, options = {})
190
+ return if global_engines.keys.include?(name)
191
+
192
+ options[:at] ||= "/#{name}"
193
+
194
+ global_engines[name.to_sym] = {
195
+ at: options[:at],
196
+ engine: engine
197
+ }
198
+ end
199
+
200
+ # Semiprivate: Removes a global engine from the registry. Mostly used on testing,
201
+ # no real reason to use this on production.
202
+ #
203
+ # name - The name of the global engine to remove.
204
+ #
205
+ # Returns nothing.
206
+ def self.unregister_global_engine(name)
207
+ global_engines.delete(name.to_sym)
208
+ end
209
+
210
+ # Public: Finds all registered engines via the 'register_global_engine' method.
211
+ #
212
+ # Returns an Array[::Rails::Engine]
213
+ def self.global_engines
214
+ @global_engines ||= {}
215
+ end
216
+
152
217
  # Public: Registers a feature, usually held in an external library or in a
153
218
  # separate folder in the main repository. Exposes a DSL defined by
154
219
  # `Decidim::FeatureManifest`.
@@ -7,12 +7,12 @@ module Decidim
7
7
  description "An author"
8
8
 
9
9
  field :name, !types.String, "The author's name"
10
+ field :nickname, !types.String, "The author's nickname"
10
11
 
11
12
  field :avatarUrl, !types.String, "The author's avatar url"
12
-
13
- field :isVerified, !types.Boolean, "Whether the author is verified or not"
13
+ field :profilePath, !types.String, "The author's profile path"
14
+ field :badge, !types.String, "The author's badge icon"
14
15
 
15
16
  field :deleted, !types.Boolean, "Whether the author's account has been deleted or not"
16
- field :isUser, !types.Boolean, "Whether the author is a user or another kind of author (User Group)"
17
17
  end
18
18
  end
@@ -14,22 +14,24 @@ module Decidim
14
14
 
15
15
  field :name, !types.String, "The user group's name"
16
16
 
17
+ field :nickname, !types.String, "User groups have no nickname" do
18
+ resolve ->(obj, _args, _ctx) { UserGroupPresenter.new(obj).nickname }
19
+ end
20
+
17
21
  field :avatarUrl, !types.String, "The user's avatar url" do
18
- resolve ->(obj, _args, _ctx) { obj.avatar.url }
22
+ resolve ->(obj, _args, _ctx) { UserGroupPresenter.new(obj).avatar_url }
19
23
  end
20
24
 
21
- field :isVerified, !types.Boolean, "Whether the user group is verified or not" do
22
- resolve lambda { |obj, _args, _ctx|
23
- obj.verified?
24
- }
25
+ field :profilePath, !types.String, "The user's profile url" do
26
+ resolve ->(obj, _args, _ctx) { UserGroupPresenter.new(obj).profile_path }
25
27
  end
26
28
 
27
29
  field :deleted, !types.Boolean, "Whether the user group's has been deleted or not" do
28
- resolve ->(_obj, _args, _ctx) { false }
30
+ resolve ->(obj, _args, _ctx) { UserGroupPresenter.new(obj).deleted? }
29
31
  end
30
32
 
31
- field :isUser, !types.Boolean, "User groups are not users" do
32
- resolve ->(_obj, _args, _ctx) { false }
33
+ field :badge, !types.String, "A badge for the user group" do
34
+ resolve ->(obj, _args, _ctx) { UserGroupPresenter.new(obj).badge }
33
35
  end
34
36
  end
35
37
  end
@@ -12,22 +12,28 @@ module Decidim
12
12
 
13
13
  field :name, !types.String, "The user's name"
14
14
 
15
+ field :nickname, !types.String, "The user's nickname" do
16
+ resolve ->(obj, _args, _ctx) { UserPresenter.new(obj).nickname }
17
+ end
18
+
15
19
  field :avatarUrl, !types.String, "The user's avatar url" do
16
- resolve ->(obj, _args, _ctx) { obj.avatar.url }
20
+ resolve ->(obj, _args, _ctx) { UserPresenter.new(obj).avatar_url(:thumb) }
21
+ end
22
+
23
+ field :profilePath, !types.String, "The user's profile url" do
24
+ resolve ->(obj, _args, _ctx) { UserPresenter.new(obj).profile_path }
17
25
  end
18
26
 
19
27
  field :organizationName, !types.String, "The user's organization name" do
20
28
  resolve ->(obj, _args, _ctx) { obj.organization.name }
21
29
  end
22
30
 
23
- field :isVerified, !types.Boolean, "Whether the author is verified or not" do
24
- resolve ->(_obj, _args, _ctx) { false }
31
+ field :deleted, !types.Boolean, "Whether the user's account has been deleted or not" do
32
+ resolve ->(obj, _args, _ctx) { UserPresenter.new(obj).deleted? }
25
33
  end
26
34
 
27
- field :deleted, !types.Boolean, "Whether the user's account has been deleted or not", property: :deleted?
28
-
29
- field :isUser, !types.Boolean, "User groups are not users" do
30
- resolve ->(_obj, _args, _ctx) { true }
35
+ field :badge, !types.String, "A badge for the user group" do
36
+ resolve ->(obj, _args, _ctx) { UserPresenter.new(obj).badge }
31
37
  end
32
38
  end
33
39
  end
@@ -56,6 +56,7 @@ module Decidim
56
56
  end
57
57
 
58
58
  initializer "decidim.assets" do |app|
59
+ app.config.assets.paths << File.expand_path("../../../app/assets/stylesheets", __dir__)
59
60
  app.config.assets.precompile += %w(decidim_core_manifest.js)
60
61
 
61
62
  Decidim.feature_manifests.each do |feature|
@@ -107,19 +108,14 @@ module Decidim
107
108
  Geocoder.configure(
108
109
  # geocoding service (see below for supported options):
109
110
  lookup: :here,
110
-
111
111
  # IP address geocoding service (see below for supported options):
112
112
  # :ip_lookup => :maxmind,
113
-
114
113
  # to use an API key:
115
114
  api_key: [Decidim.geocoder&.fetch(:here_app_id), Decidim.geocoder&.fetch(:here_app_code)]
116
-
117
115
  # geocoding service request timeout, in seconds (default 3):
118
116
  # :timeout => 5,
119
-
120
117
  # set default units to kilometers:
121
118
  # :units => :km,
122
-
123
119
  # caching (see below for details):
124
120
  # :cache => Redis.new,
125
121
  # :cache_prefix => "..."
@@ -203,6 +199,12 @@ module Decidim
203
199
  end
204
200
  end
205
201
 
202
+ initializer "decidim.content_processors" do |_app|
203
+ Decidim.configure do |config|
204
+ config.content_processors += [:user]
205
+ end
206
+ end
207
+
206
208
  initializer "paper_trail" do
207
209
  PaperTrail.config.track_associations = false
208
210
  end
@@ -13,9 +13,9 @@ require "decidim/core/test/shared_examples/announcements_examples"
13
13
  require "decidim/core/test/shared_examples/process_announcements_examples"
14
14
  require "decidim/core/test/shared_examples/reportable"
15
15
  require "decidim/core/test/shared_examples/reports_examples"
16
- require "decidim/core/test/shared_examples/manage_moderations_examples"
17
16
  require "decidim/core/test/shared_examples/paginated_resource_examples"
18
17
  require "decidim/core/test/shared_examples/errors"
19
18
  require "decidim/core/test/shared_examples/scope_helper_examples"
20
19
  require "decidim/core/test/shared_examples/user_localised_email_examples"
21
20
  require "decidim/core/test/shared_examples/follows_examples"
21
+ require "decidim/core/test/shared_examples/simple_event"
@@ -11,6 +11,10 @@ FactoryBot.define do
11
11
  "#{Faker::Name.name} #{n}"
12
12
  end
13
13
 
14
+ sequence(:nickname) do |n|
15
+ "#{Faker::Lorem.characters(rand(1..10))}_#{n}"
16
+ end
17
+
14
18
  sequence(:email) do |n|
15
19
  "user#{n}@example.org"
16
20
  end
@@ -58,6 +62,8 @@ FactoryBot.define do
58
62
  official_img_header { Decidim::Dev.test_file("avatar.jpg", "image/jpeg") }
59
63
  official_img_footer { Decidim::Dev.test_file("avatar.jpg", "image/jpeg") }
60
64
  official_url { Faker::Internet.url }
65
+ highlighted_content_banner_enabled false
66
+ enable_omnipresent_banner false
61
67
  end
62
68
 
63
69
  factory :user, class: "Decidim::User" do
@@ -65,10 +71,13 @@ FactoryBot.define do
65
71
  password "password1234"
66
72
  password_confirmation "password1234"
67
73
  name { generate(:name) }
74
+ nickname { generate(:nickname) }
68
75
  organization
69
76
  locale { organization.default_locale }
70
77
  tos_agreement "1"
71
78
  avatar { Decidim::Dev.test_file("avatar.jpg", "image/jpeg") }
79
+ personal_url { Faker::Internet.url }
80
+ about { Faker::Lorem.paragraph(2) }
72
81
 
73
82
  trait :confirmed do
74
83
  confirmed_at { Time.current }
@@ -87,57 +96,16 @@ FactoryBot.define do
87
96
  roles { ["user_manager"] }
88
97
  end
89
98
 
90
- trait :process_admin do
91
- transient do
92
- participatory_process { create(:participatory_process) }
93
- end
94
-
95
- organization { participatory_process.organization }
96
-
97
- after(:create) do |user, evaluator|
98
- create :participatory_process_user_role,
99
- user: user,
100
- participatory_process: evaluator.participatory_process,
101
- role: :admin
102
- end
103
- end
104
-
105
- trait :process_collaborator do
106
- transient do
107
- participatory_process { create(:participatory_process) }
108
- end
109
-
110
- organization { participatory_process.organization }
111
-
112
- after(:create) do |user, evaluator|
113
- create :participatory_process_user_role,
114
- user: user,
115
- participatory_process: evaluator.participatory_process,
116
- role: :collaborator
117
- end
118
- end
119
-
120
- trait :process_moderator do
121
- transient do
122
- participatory_process { create(:participatory_process) }
123
- end
124
-
125
- organization { participatory_process.organization }
126
-
127
- after(:create) do |user, evaluator|
128
- create :participatory_process_user_role,
129
- user: user,
130
- participatory_process: evaluator.participatory_process,
131
- role: :moderator
132
- end
133
- end
134
-
135
99
  trait :managed do
136
100
  email { "" }
137
101
  password { "" }
138
102
  password_confirmation { "" }
139
103
  managed { true }
140
104
  end
105
+
106
+ trait :officialized do
107
+ officialized_at { Time.zone.now }
108
+ end
141
109
  end
142
110
 
143
111
  factory :participatory_process_user_role, class: "Decidim::ParticipatoryProcessUserRole" do
@@ -218,6 +186,8 @@ FactoryBot.define do
218
186
  description { Decidim::Faker::Localized.wrapped("<p>", "</p>") { Decidim::Faker::Localized.sentence(4) } }
219
187
  file { Decidim::Dev.test_file("city.jpeg", "image/jpeg") }
220
188
  attached_to { build(:participatory_process) }
189
+ content_type { "image/jpeg" }
190
+ file_size { 108_908 }
221
191
 
222
192
  trait :with_image do
223
193
  file { Decidim::Dev.test_file("city.jpeg", "image/jpeg") }
@@ -225,6 +195,8 @@ FactoryBot.define do
225
195
 
226
196
  trait :with_pdf do
227
197
  file { Decidim::Dev.test_file("Exampledocument.pdf", "application/pdf") }
198
+ content_type { "application/pdf" }
199
+ file_size { 17_525 }
228
200
  end
229
201
  end
230
202
 
@@ -291,6 +263,10 @@ FactoryBot.define do
291
263
  factory :moderation, class: "Decidim::Moderation" do
292
264
  reportable { build(:dummy_resource) }
293
265
  participatory_space { reportable.feature.participatory_space }
266
+
267
+ trait :hidden do
268
+ hidden_at { 1.day.ago }
269
+ end
294
270
  end
295
271
 
296
272
  factory :report, class: "Decidim::Report" do