decidim-core 0.13.1 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of decidim-core might be problematic. Click here for more details.

Files changed (236) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/decidim_core_manifest.js +1 -1
  3. data/app/assets/images/decidim/gamification/badges/invitations.svg +117 -0
  4. data/app/assets/javascripts/decidim.js.es6 +4 -1
  5. data/app/assets/javascripts/decidim/ajax_modals.js.es6 +17 -0
  6. data/app/assets/javascripts/decidim/conferences.js.es6 +16 -0
  7. data/app/assets/javascripts/decidim/input_hashtags.js.es6 +115 -0
  8. data/app/assets/javascripts/decidim/input_mentions.js.es6 +2 -3
  9. data/app/assets/javascripts/decidim/vizzs/areachart.js.es6 +226 -0
  10. data/app/assets/javascripts/decidim/vizzs/metrics.js.es6 +26 -0
  11. data/app/assets/javascripts/decidim/vizzs/orgchart.js.es6 +701 -0
  12. data/app/assets/javascripts/decidim/vizzs/renders.js.es6 +11 -0
  13. data/app/assets/stylesheets/decidim/extras/_proposal_form.scss +3 -1
  14. data/app/assets/stylesheets/decidim/layouts/_home.scss +1 -1
  15. data/app/assets/stylesheets/decidim/modules/_areachart.scss +74 -0
  16. data/app/assets/stylesheets/decidim/modules/_badges.scss +116 -0
  17. data/app/assets/stylesheets/decidim/modules/_buttons.scss +5 -0
  18. data/app/assets/stylesheets/decidim/modules/_cards.scss +21 -4
  19. data/app/assets/stylesheets/decidim/modules/_chart-tooltip.scss +42 -0
  20. data/app/assets/stylesheets/decidim/modules/_collapsible-list.scss +12 -8
  21. data/app/assets/stylesheets/decidim/modules/_conference-nav.scss +31 -0
  22. data/app/assets/stylesheets/decidim/modules/_conference-programme.scss +110 -0
  23. data/app/assets/stylesheets/decidim/modules/_conference-speaker.scss +86 -0
  24. data/app/assets/stylesheets/decidim/modules/_conversation.scss +58 -0
  25. data/app/assets/stylesheets/decidim/modules/_help.scss +38 -0
  26. data/app/assets/stylesheets/decidim/modules/_hover-section.scss +29 -0
  27. data/app/assets/stylesheets/decidim/modules/_icons.scss +10 -4
  28. data/app/assets/stylesheets/decidim/modules/_input-hashtags.scss +124 -0
  29. data/app/assets/stylesheets/decidim/modules/_loading-spinner.scss +12 -0
  30. data/app/assets/stylesheets/decidim/modules/_margins.scss +2 -2
  31. data/app/assets/stylesheets/decidim/modules/_modules.scss +15 -0
  32. data/app/assets/stylesheets/decidim/modules/_navbar.scss +9 -0
  33. data/app/assets/stylesheets/decidim/modules/_orgchart.scss +62 -0
  34. data/app/assets/stylesheets/decidim/modules/_status-labels.scss +2 -1
  35. data/app/assets/stylesheets/decidim/modules/_typography.scss +9 -0
  36. data/app/assets/stylesheets/decidim/utils/_helpers.scss +28 -0
  37. data/app/assets/stylesheets/decidim/utils/_mixins.scss +63 -0
  38. data/app/cells/decidim/author/withdraw.erb +1 -1
  39. data/app/cells/decidim/author_cell.rb +1 -1
  40. data/app/cells/decidim/badge/show.erb +36 -0
  41. data/app/cells/decidim/badge_cell.rb +53 -0
  42. data/app/cells/decidim/badges/show.erb +6 -0
  43. data/app/cells/decidim/badges_cell.rb +14 -0
  44. data/app/cells/decidim/card_m/header.erb +1 -1
  45. data/app/cells/decidim/card_m/show.erb +1 -2
  46. data/app/cells/decidim/card_m/top.erb +7 -0
  47. data/app/cells/decidim/card_m_cell.rb +14 -17
  48. data/app/cells/decidim/coauthorships_cell.rb +77 -0
  49. data/app/cells/decidim/collapsible_authors/show.erb +0 -1
  50. data/app/cells/decidim/collapsible_authors_cell.rb +4 -4
  51. data/app/cells/decidim/collapsible_list/show.erb +12 -4
  52. data/app/cells/decidim/collapsible_list_cell.rb +14 -12
  53. data/app/cells/decidim/content_blocks/footer_sub_hero/show.erb +14 -0
  54. data/app/cells/decidim/content_blocks/footer_sub_hero_cell.rb +12 -0
  55. data/app/{views/decidim/pages/home/_hero.html.erb → cells/decidim/content_blocks/hero/show.erb} +4 -4
  56. data/app/cells/decidim/content_blocks/hero_cell.rb +25 -0
  57. data/app/cells/decidim/content_blocks/hero_settings_form/show.erb +7 -0
  58. data/app/cells/decidim/content_blocks/hero_settings_form_cell.rb +13 -0
  59. data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +24 -0
  60. data/app/cells/decidim/content_blocks/highlighted_content_banner_cell.rb +16 -0
  61. data/app/{views/decidim/pages/home/_extended.html.erb → cells/decidim/content_blocks/how_to_participate/show.erb} +10 -10
  62. data/app/cells/decidim/content_blocks/how_to_participate_cell.rb +9 -0
  63. data/app/{views/decidim/pages/home/_statistics.html.erb → cells/decidim/content_blocks/stats/show.erb} +2 -2
  64. data/app/cells/decidim/content_blocks/stats_cell.rb +18 -0
  65. data/app/{views/decidim/pages/home/_sub_hero.html.erb → cells/decidim/content_blocks/sub_hero/show.erb} +2 -2
  66. data/app/cells/decidim/content_blocks/sub_hero_cell.rb +17 -0
  67. data/app/cells/decidim/conversation/show.erb +18 -0
  68. data/app/cells/decidim/conversation_cell.rb +23 -0
  69. data/app/cells/decidim/conversation_header/show.erb +17 -0
  70. data/app/cells/decidim/conversation_header_cell.rb +16 -0
  71. data/app/cells/decidim/conversations/show.erb +45 -0
  72. data/app/cells/decidim/conversations_cell.rb +24 -0
  73. data/app/cells/decidim/follow_button/show.erb +3 -3
  74. data/app/cells/decidim/follow_button_cell.rb +1 -5
  75. data/app/cells/decidim/following_cell.rb +1 -7
  76. data/app/cells/decidim/message/show.erb +15 -0
  77. data/app/cells/decidim/message_cell.rb +23 -0
  78. data/app/cells/decidim/new_conversation/show.erb +19 -0
  79. data/app/cells/decidim/new_conversation_cell.rb +19 -0
  80. data/app/cells/decidim/notifications/show.erb +1 -1
  81. data/app/cells/decidim/profile/show.erb +27 -0
  82. data/app/cells/decidim/profile_cell.rb +33 -0
  83. data/app/cells/decidim/profile_sidebar/show.erb +57 -0
  84. data/app/cells/decidim/profile_sidebar_cell.rb +31 -0
  85. data/app/cells/decidim/tos_page_cell.rb +0 -4
  86. data/app/cells/decidim/user_profile/header.erb +1 -1
  87. data/app/controllers/concerns/decidim/action_authorization.rb +13 -38
  88. data/app/controllers/concerns/decidim/needs_permission.rb +15 -6
  89. data/app/controllers/decidim/application_controller.rb +1 -0
  90. data/app/controllers/decidim/authorization_modals_controller.rb +35 -0
  91. data/app/controllers/decidim/components/base_controller.rb +0 -1
  92. data/app/controllers/decidim/devise/invitations_controller.rb +2 -1
  93. data/app/controllers/decidim/messaging/conversations_controller.rb +2 -11
  94. data/app/controllers/decidim/newsletters_controller.rb +4 -6
  95. data/app/controllers/decidim/notifications_controller.rb +4 -0
  96. data/app/controllers/decidim/pages_controller.rb +3 -7
  97. data/app/controllers/decidim/profiles_controller.rb +17 -7
  98. data/app/forms/decidim/notifications_settings_form.rb +1 -1
  99. data/app/forms/decidim/registration_form.rb +1 -1
  100. data/app/helpers/decidim/action_authorization_helper.rb +51 -46
  101. data/app/helpers/decidim/application_helper.rb +18 -0
  102. data/app/helpers/decidim/card_helper.rb +1 -1
  103. data/app/helpers/decidim/cells_helper.rb +6 -2
  104. data/app/helpers/decidim/resource_helper.rb +8 -1
  105. data/app/helpers/decidim/searches_helper.rb +5 -4
  106. data/app/helpers/decidim/traceability_helper.rb +5 -1
  107. data/app/models/decidim/authorization.rb +2 -2
  108. data/app/models/decidim/content_block.rb +144 -0
  109. data/app/models/decidim/gamification/badge_score.rb +13 -0
  110. data/app/models/decidim/messaging/message.rb +1 -1
  111. data/app/models/decidim/messaging/receipt.rb +1 -1
  112. data/app/models/decidim/organization.rb +1 -5
  113. data/app/models/decidim/resource_permission.rb +8 -0
  114. data/app/models/decidim/searchable_resource.rb +1 -1
  115. data/app/models/decidim/user.rb +17 -1
  116. data/app/permissions/decidim/default_permissions.rb +4 -3
  117. data/app/permissions/decidim/permissions.rb +33 -1
  118. data/app/presenters/decidim/hashtag_presenter.rb +32 -0
  119. data/app/presenters/decidim/resource_locator_presenter.rb +13 -0
  120. data/app/presenters/decidim/user_presenter.rb +1 -1
  121. data/app/queries/decidim/messaging/user_conversations.rb +1 -1
  122. data/app/resolvers/decidim/hashtags_resolver.rb +15 -0
  123. data/app/services/decidim/action_authorizer.rb +9 -8
  124. data/app/types/decidim/core/date_time_type.rb +1 -1
  125. data/app/types/decidim/core/hashtag_type.rb +13 -0
  126. data/app/uploaders/decidim/homepage_image_uploader.rb +1 -1
  127. data/app/uploaders/decidim/image_uploader.rb +1 -0
  128. data/app/views/decidim/authorization_modals/show.html.erb +32 -0
  129. data/app/views/decidim/messaging/conversations/create.js.erb +1 -1
  130. data/app/views/decidim/messaging/conversations/index.html.erb +1 -51
  131. data/app/views/decidim/messaging/conversations/new.html.erb +1 -5
  132. data/app/views/decidim/messaging/conversations/show.html.erb +1 -9
  133. data/app/views/decidim/messaging/conversations/update.js.erb +1 -1
  134. data/app/views/decidim/notifications/index.html.erb +1 -0
  135. data/app/views/decidim/pages/decidim_page.html.erb +9 -0
  136. data/app/views/decidim/pages/home.html.erb +12 -16
  137. data/app/views/decidim/pages/index.html.erb +8 -0
  138. data/app/views/decidim/profiles/_user_follow.erb +2 -2
  139. data/app/views/decidim/profiles/show.html.erb +1 -37
  140. data/app/views/decidim/searches/_results.html.erb +1 -1
  141. data/app/views/decidim/shared/_author_reference.html.erb +1 -1
  142. data/app/views/decidim/shared/_authorization_modal.html.erb +1 -0
  143. data/app/views/decidim/shared/_tags.html.erb +1 -1
  144. data/app/views/kaminari/decidim/_page.html.erb +1 -1
  145. data/app/views/layouts/decidim/_application.html.erb +6 -1
  146. data/app/views/layouts/decidim/_edit_link.html.erb +8 -0
  147. data/app/views/layouts/decidim/_impersonation_warning.html.erb +1 -1
  148. data/app/views/layouts/decidim/_user_menu.html.erb +2 -2
  149. data/app/views/layouts/decidim/_wrapper.html.erb +14 -1
  150. data/config/initializers/carrierwave.rb +15 -0
  151. data/config/locales/ca.yml +78 -30
  152. data/config/locales/en.yml +78 -30
  153. data/config/locales/es-PY.yml +78 -30
  154. data/config/locales/es.yml +78 -30
  155. data/config/locales/eu.yml +78 -30
  156. data/config/locales/fi.yml +262 -214
  157. data/config/locales/fr.yml +78 -30
  158. data/config/locales/gl.yml +78 -30
  159. data/config/locales/hu.yml +781 -0
  160. data/config/locales/it.yml +78 -30
  161. data/config/locales/nl.yml +78 -30
  162. data/config/locales/pl.yml +78 -30
  163. data/config/locales/pt-BR.yml +106 -58
  164. data/config/locales/pt.yml +78 -30
  165. data/config/locales/ru.yml +52 -32
  166. data/config/locales/sv.yml +183 -135
  167. data/config/locales/uk.yml +60 -40
  168. data/config/routes.rb +8 -6
  169. data/db/migrate/20180705091019_create_decidim_resource_permissions.rb +12 -0
  170. data/db/migrate/20180706104107_add_nickname_to_managed_users.rb +14 -0
  171. data/db/migrate/20180706111847_fix_result_follows.rb +9 -0
  172. data/db/migrate/20180724103814_add_content_blocks.rb +22 -0
  173. data/db/migrate/20180726112510_create_decidim_hashtags.rb +17 -0
  174. data/db/migrate/20180730071851_add_core_content_blocks.rb +28 -0
  175. data/db/migrate/20180802132147_rename_content_block_options_to_settings.rb +7 -0
  176. data/db/migrate/20180806095628_add_badge_scores.rb +11 -0
  177. data/db/migrate/20180808135006_add_images_to_content_blocks.rb +7 -0
  178. data/db/migrate/20180810092428_move_organization_fields_to_hero_content_block.rb +23 -0
  179. data/db/seeds.rb +10 -2
  180. data/lib/decidim/api/authorable_interface.rb +1 -1
  181. data/lib/decidim/coauthorable.rb +1 -0
  182. data/lib/decidim/content_block_manifest.rb +58 -0
  183. data/lib/decidim/content_block_registry.rb +87 -0
  184. data/lib/decidim/content_parsers.rb +1 -0
  185. data/lib/decidim/content_parsers/hashtag_parser.rb +36 -0
  186. data/lib/decidim/content_processor.rb +11 -0
  187. data/lib/decidim/content_renderers.rb +1 -0
  188. data/lib/decidim/content_renderers/hashtag_renderer.rb +43 -0
  189. data/lib/decidim/core.rb +28 -6
  190. data/lib/decidim/core/api.rb +1 -0
  191. data/lib/decidim/core/engine.rb +52 -1
  192. data/lib/decidim/core/test.rb +3 -0
  193. data/lib/decidim/core/test/factories.rb +32 -17
  194. data/lib/decidim/core/test/shared_examples/authorable_interface_examples.rb +10 -0
  195. data/lib/decidim/core/test/shared_examples/coauthorable.rb +3 -0
  196. data/lib/decidim/core/test/shared_examples/edit_link_shared_examples.rb +30 -0
  197. data/lib/decidim/core/test/shared_examples/has_space_in_mcell_examples.rb +15 -0
  198. data/lib/decidim/core/test/shared_examples/publicable.rb +1 -1
  199. data/lib/decidim/core/test/shared_examples/railtie_examples.rb +15 -0
  200. data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +1 -0
  201. data/lib/decidim/core/version.rb +1 -1
  202. data/lib/decidim/events/base_event.rb +2 -1
  203. data/lib/decidim/form_builder.rb +9 -3
  204. data/lib/decidim/friendly_dates.rb +1 -1
  205. data/lib/decidim/gamification.rb +109 -0
  206. data/lib/decidim/gamification/badge.rb +54 -0
  207. data/lib/decidim/gamification/badge_earned_event.rb +9 -0
  208. data/lib/decidim/gamification/badge_registry.rb +63 -0
  209. data/lib/decidim/gamification/badge_scorer.rb +118 -0
  210. data/lib/decidim/gamification/badge_status.rb +41 -0
  211. data/lib/decidim/gamification/base_event.rb +40 -0
  212. data/lib/decidim/gamification/level_up_event.rb +9 -0
  213. data/lib/decidim/hashtag.rb +15 -0
  214. data/lib/decidim/hashtaggable.rb +20 -0
  215. data/lib/decidim/query_extensions.rb +10 -0
  216. data/lib/decidim/resource_manifest.rb +10 -0
  217. data/lib/decidim/resourceable.rb +13 -0
  218. data/lib/decidim/search_resource_fields_mapper.rb +8 -3
  219. data/lib/decidim/searchable.rb +8 -0
  220. data/lib/decidim/translatable_attributes.rb +6 -18
  221. data/lib/decidim/view_model.rb +6 -0
  222. data/lib/devise/models/decidim_newsletterable.rb +1 -1
  223. data/vendor/assets/javascripts/d3.js +17813 -0
  224. metadata +125 -27
  225. data/app/cells/decidim/card_m/author.erb +0 -3
  226. data/app/cells/decidim/card_m/authors.erb +0 -9
  227. data/app/views/decidim/messaging/conversations/_message.html.erb +0 -14
  228. data/app/views/decidim/messaging/conversations/_reply.html.erb +0 -11
  229. data/app/views/decidim/messaging/conversations/_show.html.erb +0 -21
  230. data/app/views/decidim/messaging/conversations/_start.html.erb +0 -12
  231. data/app/views/decidim/pages/home/_footer_sub_hero.html.erb +0 -14
  232. data/app/views/decidim/pages/home/_highlighted_content_banner.html.erb +0 -26
  233. data/app/views/decidim/pages/home/_highlighted_processes.html.erb +0 -7
  234. data/app/views/decidim/profiles/_user.html.erb +0 -59
  235. data/app/views/decidim/shared/_action_authorization_modal.html.erb +0 -39
  236. data/app/views/layouts/decidim/_component_authorization_modals.html.erb +0 -5
@@ -45,7 +45,7 @@ module Decidim
45
45
  return [] unless klass.respond_to?(:linked_classes_for)
46
46
 
47
47
  klass.linked_classes_for(current_component).map do |k|
48
- [k.underscore, t(k.demodulize.downcase, scope: "decidim.filters.linked_classes")]
48
+ [k.underscore, t(k.demodulize.underscore, scope: "decidim.filters.linked_classes")]
49
49
  end
50
50
  end
51
51
 
@@ -69,5 +69,12 @@ module Decidim
69
69
  def resource_locator(resource)
70
70
  ::Decidim::ResourceLocatorPresenter.new(resource)
71
71
  end
72
+
73
+ # Returns a descriptive title for the resource
74
+ def resource_title(resource)
75
+ title = resource.try(:title) || resource.try(:name) || resource.try(:subject) || "#{resource.model_name.human} ##{resource.id}"
76
+ title = translated_attribute(title) if title.is_a?(Hash)
77
+ title
78
+ end
72
79
  end
73
80
  end
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Decidim
4
- # A Helper to render and link to resources.
4
+ # A Helper to render and link to searchables.
5
5
  module SearchesHelper
6
- def searchable_resource_human_name(resource)
7
- resource.model_name.human.pluralize
6
+ # @param count: (optional) the number of resources so that the I18n backend can decide to translate into singluar or plural form.
7
+ def searchable_resource_human_name(resource, count: 1)
8
+ resource.model_name.human(count: count)
8
9
  end
9
10
 
10
11
  def searchable_resources_as_options(all_label)
11
12
  [["", all_label]] + Decidim::Searchable.searchable_resources.values.collect do |r|
12
- [r.name, searchable_resource_human_name(r)]
13
+ [r.name, searchable_resource_human_name(r, count: 2)]
13
14
  end.sort
14
15
  end
15
16
  end
@@ -31,7 +31,11 @@ module Decidim
31
31
 
32
32
  # Caches a DiffRenderer instance for the `current_version`.
33
33
  def diff_renderer
34
- @diff_renderer ||= Decidim::Accountability::DiffRenderer.new(current_version)
34
+ @diff_renderer ||= if current_version.item_type.include? "Decidim::Proposals"
35
+ Decidim::Proposals::DiffRenderer.new(current_version)
36
+ elsif current_version.item_type.include? "Decidim::Accountability"
37
+ Decidim::Accountability::DiffRenderer.new(current_version)
38
+ end
35
39
  end
36
40
 
37
41
  # Renders the diff between `:old_data` and `:new_data` keys in the `data` param.
@@ -39,7 +39,7 @@ module Decidim
39
39
  def grant!
40
40
  remove_verification_attachment!
41
41
 
42
- update!(granted_at: Time.zone.now, verification_metadata: {})
42
+ update!(granted_at: Time.current, verification_metadata: {})
43
43
  end
44
44
 
45
45
  def granted?
@@ -57,7 +57,7 @@ module Decidim
57
57
  end
58
58
 
59
59
  def expired?
60
- expires_at.present? && expires_at < Time.zone.now
60
+ expires_at.present? && expires_at < Time.current
61
61
  end
62
62
 
63
63
  private
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # this class represents a content block manifest instance in the DB. Check the
5
+ # docs on `ContentBlockRegistry` and `ContentBlockManifest` for more info.
6
+ class ContentBlock < ApplicationRecord
7
+ include Publicable
8
+
9
+ belongs_to :organization, foreign_key: :decidim_organization_id, class_name: "Decidim::Organization"
10
+
11
+ delegate :public_name_key, :has_settings?, :settings_form_cell, :cell, to: :manifest
12
+
13
+ before_save :save_images
14
+ after_save :reload_images
15
+
16
+ # Public: finds the published content blocks for the given scope and
17
+ # organization. Returns them ordered by ascending weight (lowest first).
18
+ def self.for_scope(scope, organization:)
19
+ where(organization: organization, scope: scope)
20
+ .order(weight: :asc)
21
+ end
22
+
23
+ def manifest
24
+ @manifest ||= Decidim.content_blocks.for(scope).find { |manifest| manifest.name.to_s == manifest_name }
25
+ end
26
+
27
+ # Public: Uses the `SettingsManifest` class to generate a settings schema
28
+ # and fill it with the content blocks current settings. This eases the
29
+ # access to those settings values.
30
+ #
31
+ # Returns an object that responds to the settings defined in the content
32
+ # block manifest.
33
+ def settings
34
+ manifest.settings.schema.new(self[:settings])
35
+ end
36
+
37
+ def reload(*)
38
+ @images_container = nil
39
+ super
40
+ end
41
+
42
+ # Public: Holds access to the images related to the content block. This
43
+ # method generates a dynamic class that encapsulates the uploaders for the
44
+ # content block images, and eases the access to them. It's a little bit
45
+ # hacky, but it's the only way I could come up with in order to let content
46
+ # block images have different uploaders.
47
+ #
48
+ # Examples:
49
+ #
50
+ # # This will process the image with the uploader defined at the
51
+ # # manifest, upload it and save the record.
52
+ # content_block.images_container.my_image = params[:my_image]
53
+ # content_block.save!
54
+ #
55
+ # # This is how you can access the image data, just like with any other
56
+ # # uploader field. You can use the uploader versions too.
57
+ # content_block.images_container.my_image.url
58
+ # content_block.images_container.my_image.big.url
59
+ # content_block.save!
60
+ #
61
+ # # This will delete the attached image
62
+ # content_block.images_container.my_image = nil
63
+ # content_block.save!
64
+ #
65
+ # Returns an object that responds to the image names defined in the content
66
+ # block manifest.
67
+ def images_container
68
+ return @images_container if @images_container
69
+ manifest = self.manifest
70
+
71
+ @images_container = Class.new do
72
+ extend ::CarrierWave::Mount
73
+ include ActiveModel::Validations
74
+
75
+ cattr_accessor :manifest, :manifest_scope
76
+ attr_reader :content_block
77
+
78
+ # Needed to calculate uploads URLs
79
+ delegate :id, to: :content_block
80
+
81
+ # Needed to customize the upload URL
82
+ def self.name
83
+ to_s.camelize
84
+ end
85
+
86
+ # Needed to customize the upload URL
87
+ def self.to_s
88
+ "decidim/#{manifest.name.to_s.underscore}_#{manifest_scope.to_s.underscore}_content_block"
89
+ end
90
+
91
+ def initialize(content_block)
92
+ @content_block = content_block
93
+ end
94
+
95
+ def manifest
96
+ self.class.manifest
97
+ end
98
+
99
+ manifest.images.each do |image_config|
100
+ mount_uploader image_config[:name], image_config[:uploader].constantize
101
+ end
102
+
103
+ # This is used to access the upload file name from the container, given
104
+ # an image name.
105
+ def read_uploader(column)
106
+ content_block.images[column.to_s]
107
+ end
108
+
109
+ # This is used to set the upload file name from the container, given
110
+ # an image name.
111
+ def write_uploader(column, value)
112
+ content_block.images[column.to_s] = value
113
+ end
114
+
115
+ # When we save the content block, we force the container to save itself
116
+ # too, so images can be processed, uploaded and stored in the DB.
117
+ def save
118
+ manifest.images.each do |image_config|
119
+ send(:"write_#{image_config[:name]}_identifier")
120
+ send(:"store_#{image_config[:name]}!")
121
+ end
122
+ end
123
+ end
124
+
125
+ @images_container.manifest = manifest
126
+ @images_container.manifest_scope = scope
127
+ @images_container = @images_container.new(self)
128
+ end
129
+
130
+ private
131
+
132
+ # Internal: Since we're using the `images_container` hack to hold the
133
+ # uploaders, we need to manually trigger it to save the attached images.
134
+ def save_images
135
+ images_container.save
136
+ end
137
+
138
+ # On instance reloading we need to remove the `images_cointainer` cached
139
+ # class so it gets regenerated with the new values.
140
+ def reload_images
141
+ @images_container = nil
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Gamification
5
+ class BadgeScore < ApplicationRecord
6
+ self.table_name = "decidim_gamification_badge_scores"
7
+
8
+ belongs_to :user, class_name: "Decidim::User"
9
+ validates :user, presence: true
10
+ validates :value, numericality: { greater_than_or_equal_to: 0 }
11
+ end
12
+ end
13
+ end
@@ -38,7 +38,7 @@ module Decidim
38
38
  # @param recipients [Array<Decidim::User>]
39
39
  #
40
40
  def envelope_for(recipients)
41
- receipts.build(recipient: sender, read_at: Time.zone.now)
41
+ receipts.build(recipient: sender, read_at: Time.current)
42
42
 
43
43
  recipients.each { |recipient| receipts.build(recipient: recipient) }
44
44
  end
@@ -19,7 +19,7 @@ module Decidim
19
19
 
20
20
  # rubocop:disable Rails/SkipsModelValidations
21
21
  def self.mark_as_read(user)
22
- recipient(user).update_all(read_at: Time.zone.now)
22
+ recipient(user).update_all(read_at: Time.current)
23
23
  end
24
24
  # rubocop:enable Rails/SkipsModelValidations
25
25
  end
@@ -19,12 +19,12 @@ module Decidim
19
19
  has_many :users_with_any_role, -> { where.not(roles: []) }, foreign_key: "decidim_organization_id", class_name: "Decidim::User"
20
20
  has_many :users, foreign_key: "decidim_organization_id", class_name: "Decidim::User", dependent: :destroy
21
21
  has_many :oauth_applications, foreign_key: "decidim_organization_id", class_name: "Decidim::OAuthApplication", inverse_of: :organization, dependent: :destroy
22
+ has_many :hashtags, foreign_key: "decidim_organization_id", class_name: "Decidim::Hashtag", dependent: :destroy
22
23
 
23
24
  validates :name, :host, uniqueness: true
24
25
  validates :reference_prefix, presence: true
25
26
  validates :default_locale, inclusion: { in: :available_locales }
26
27
 
27
- mount_uploader :homepage_image, Decidim::HomepageImageUploader
28
28
  mount_uploader :official_img_header, Decidim::OfficialImageHeaderUploader
29
29
  mount_uploader :official_img_footer, Decidim::OfficialImageFooterUploader
30
30
  mount_uploader :logo, Decidim::OrganizationLogoUploader
@@ -46,10 +46,6 @@ module Decidim
46
46
  @top_scopes ||= scopes.top_level
47
47
  end
48
48
 
49
- def homepage_big_url
50
- homepage_image.big.url
51
- end
52
-
53
49
  def public_participatory_spaces
54
50
  @public_participatory_spaces ||= Decidim.participatory_space_manifests.flat_map do |manifest|
55
51
  manifest.participatory_spaces.call(self).public_spaces
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # A ResourcePermission allows to override component permissions for an specific resource.
5
+ class ResourcePermission < ApplicationRecord
6
+ belongs_to :resource, polymorphic: true
7
+ end
8
+ end
@@ -26,7 +26,7 @@ module Decidim
26
26
  class_name: "Decidim::Scope",
27
27
  optional: true
28
28
  belongs_to :resource, polymorphic: true
29
- belongs_to :decidim_participatory_space, polymorphic: true
29
+ belongs_to :decidim_participatory_space, polymorphic: true, optional: true
30
30
 
31
31
  validates :locale, uniqueness: { scope: :resource }
32
32
 
@@ -12,6 +12,7 @@ module Decidim
12
12
  include Decidim::Followable
13
13
  include Decidim::Loggable
14
14
  include Decidim::DataPortability
15
+ include Decidim::Searchable
15
16
 
16
17
  OMNIAUTH_PROVIDERS = [:facebook, :twitter, :google_oauth2, (:developer if Rails.env.development?)].compact
17
18
  ROLES = %w(admin user_manager).freeze
@@ -54,6 +55,15 @@ module Decidim
54
55
 
55
56
  attr_accessor :newsletter_notifications
56
57
 
58
+ searchable_fields({
59
+ # scope_id: :decidim_scope_id,
60
+ organization_id: :decidim_organization_id,
61
+ A: :name,
62
+ datetime: :created_at
63
+ },
64
+ index_on_create: ->(user) { !user.deleted? },
65
+ index_on_update: ->(user) { !user.deleted? })
66
+
57
67
  def user_invited?
58
68
  invitation_token_changed? && invitation_accepted_at_changed?
59
69
  end
@@ -124,6 +134,12 @@ module Decidim
124
134
  end
125
135
  end
126
136
 
137
+ def following_users
138
+ @following_users ||= following.select do |f|
139
+ f.is_a?(Decidim::User)
140
+ end
141
+ end
142
+
127
143
  def unread_conversations
128
144
  Decidim::Messaging::Conversation.unread_by(self)
129
145
  end
@@ -155,7 +171,7 @@ module Decidim
155
171
  end
156
172
 
157
173
  def tos_accepted?
158
- return true if managed
174
+ return true if managed || organization.tos_version.nil?
159
175
  return false if accepted_tos_version.nil?
160
176
  accepted_tos_version >= organization.tos_version
161
177
  end
@@ -38,10 +38,11 @@ module Decidim
38
38
  [:participatory_space, :component].include?(permission_action.subject)
39
39
  end
40
40
 
41
- def authorized?(permission_action)
42
- return unless component
41
+ def authorized?(permission_action, resource: nil)
42
+ return unless resource || component
43
+ return if component && resource && component != resource.component
43
44
 
44
- ActionAuthorizer.new(user, component, permission_action).authorize.ok?
45
+ ActionAuthorizer.new(user, permission_action, component, resource).authorize.ok?
45
46
  end
46
47
 
47
48
  def current_settings
@@ -3,6 +3,8 @@
3
3
  module Decidim
4
4
  class Permissions < DefaultPermissions
5
5
  def permissions
6
+ return permission_action unless permission_action.scope == :public
7
+
6
8
  read_public_pages_action?
7
9
  locales_action?
8
10
  component_public_action?
@@ -37,7 +39,10 @@ module Decidim
37
39
  return unless permission_action.subject == :component &&
38
40
  permission_action.action == :read
39
41
 
40
- toggle_allow(component.published?)
42
+ return allow! if component.published?
43
+ return allow! if user_can_admin_component?
44
+ return allow! if user_can_admin_component_via_space?
45
+ disallow!
41
46
  end
42
47
 
43
48
  def search_scope_action?
@@ -86,6 +91,33 @@ module Decidim
86
91
  toggle_allow(conversation.participants.include?(user))
87
92
  end
88
93
 
94
+ def user_can_admin_component?
95
+ new_permission_action = Decidim::PermissionAction.new(
96
+ action: permission_action.action,
97
+ scope: :admin,
98
+ subject: permission_action.subject
99
+ )
100
+ Decidim::Admin::Permissions.new(user, new_permission_action, context).permissions.allowed?
101
+ rescue Decidim::PermissionAction::PermissionNotSetError
102
+ nil
103
+ end
104
+
105
+ def user_can_admin_component_via_space?
106
+ Decidim.participatory_space_manifests.any? do |manifest|
107
+ begin
108
+ new_permission_action = Decidim::PermissionAction.new(
109
+ action: permission_action.action,
110
+ scope: :admin,
111
+ subject: permission_action.subject
112
+ )
113
+ new_context = context.merge(current_participatory_space: component.participatory_space)
114
+ manifest.permissions_class.new(user, new_permission_action, new_context).permissions.allowed?
115
+ rescue Decidim::PermissionAction::PermissionNotSetError
116
+ nil
117
+ end
118
+ end
119
+ end
120
+
89
121
  def not_already_active?(authorization)
90
122
  Verifications::Authorizations.new(organization: user.organization, user: user, name: authorization.name).none?
91
123
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ #
5
+ # Decorator for users
6
+ #
7
+ class HashtagPresenter < SimpleDelegator
8
+ include Rails.application.routes.mounted_helpers
9
+ include ActionView::Helpers::UrlHelper
10
+
11
+ #
12
+ # name presented in a twitter-like style
13
+ #
14
+ def name
15
+ "##{super}"
16
+ end
17
+
18
+ delegate :url, to: :hashtag, prefix: true
19
+
20
+ def hashtag_path
21
+ decidim.hashtag_path(__getobj__.name)
22
+ end
23
+
24
+ def display_hashtag
25
+ link_to name, decidim.search_path(term: name), target: "_blank", class: "hashtag-mention"
26
+ end
27
+
28
+ def display_hashtag_name
29
+ name
30
+ end
31
+ end
32
+ end