decidim-core 0.14.4 → 0.15.0

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 (263) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -0
  3. data/app/assets/images/decidim/cc-badge.png +0 -0
  4. data/app/assets/images/decidim/gamification/badges/continuity.svg +73 -0
  5. data/app/assets/images/decidim/gamification/badges/followers.svg +115 -0
  6. data/app/assets/images/decidim/icons.svg +1 -0
  7. data/app/assets/javascripts/decidim/vizzs/areachart.js.es6 +186 -208
  8. data/app/assets/javascripts/decidim/vizzs/linechart.js.es6 +263 -0
  9. data/app/assets/javascripts/decidim/vizzs/metrics.js.es6 +36 -26
  10. data/app/assets/javascripts/decidim/vizzs/orgchart.js.es6 +3 -2
  11. data/app/assets/javascripts/decidim/vizzs/rowchart.js.es6 +324 -0
  12. data/app/assets/stylesheets/decidim/_decidim.scss +1 -0
  13. data/app/assets/stylesheets/decidim/modules/_cards.scss +1 -0
  14. data/app/assets/stylesheets/decidim/modules/_conference-diploma.scss +75 -0
  15. data/app/assets/stylesheets/decidim/modules/_conference-media.scss +44 -0
  16. data/app/assets/stylesheets/decidim/modules/_conference-programme.scss +5 -1
  17. data/app/assets/stylesheets/decidim/modules/_conference-registration.scss +34 -0
  18. data/app/assets/stylesheets/decidim/modules/_list-request.scss +16 -0
  19. data/app/assets/stylesheets/decidim/modules/_modules.scss +4 -4
  20. data/app/assets/stylesheets/decidim/modules/_process-phase.scss +1 -0
  21. data/app/assets/stylesheets/decidim/modules/_reveal.scss +6 -1
  22. data/app/assets/stylesheets/decidim/utils/_helpers.scss +1 -1
  23. data/app/assets/stylesheets/decidim/{modules → vizzs}/_areachart.scss +8 -11
  24. data/app/assets/stylesheets/decidim/{modules → vizzs}/_chart-tooltip.scss +0 -0
  25. data/app/assets/stylesheets/decidim/vizzs/_linechart.scss +115 -0
  26. data/app/assets/stylesheets/decidim/vizzs/_rowchart.scss +77 -0
  27. data/app/cells/decidim/activities/show.erb +3 -0
  28. data/app/cells/decidim/activities_cell.rb +38 -0
  29. data/app/cells/decidim/activity/show.erb +21 -0
  30. data/app/cells/decidim/activity_cell.rb +85 -0
  31. data/app/cells/decidim/address/details.erb +7 -0
  32. data/app/cells/decidim/address/show.erb +14 -0
  33. data/app/cells/decidim/address_cell.rb +19 -0
  34. data/app/cells/decidim/author/contact.erb +1 -1
  35. data/app/cells/decidim/author_cell.rb +1 -0
  36. data/app/cells/decidim/badge/show.erb +2 -2
  37. data/app/cells/decidim/badge/small.erb +5 -0
  38. data/app/cells/decidim/badge_cell.rb +36 -14
  39. data/app/cells/decidim/badges/show.erb +6 -3
  40. data/app/cells/decidim/badges_cell.rb +4 -4
  41. data/app/cells/decidim/coauthorships_cell.rb +8 -2
  42. data/app/cells/decidim/collapsible_authors/show.erb +9 -7
  43. data/app/cells/decidim/content_blocks/html/show.erb +3 -0
  44. data/app/cells/decidim/content_blocks/html_cell.rb +11 -0
  45. data/app/cells/decidim/content_blocks/html_settings_form/show.erb +3 -0
  46. data/app/cells/decidim/content_blocks/html_settings_form_cell.rb +17 -0
  47. data/app/cells/decidim/content_blocks/last_activity/show.erb +17 -0
  48. data/app/cells/decidim/content_blocks/last_activity_cell.rb +60 -0
  49. data/app/cells/decidim/content_blocks/metrics/show.erb +13 -0
  50. data/app/cells/decidim/content_blocks/metrics_cell.rb +18 -0
  51. data/app/cells/decidim/content_blocks/stats/show.erb +2 -1
  52. data/app/cells/decidim/groups/show.erb +10 -0
  53. data/app/cells/decidim/groups_cell.rb +19 -0
  54. data/app/cells/decidim/members/show.erb +9 -0
  55. data/app/cells/decidim/members_cell.rb +32 -0
  56. data/app/cells/decidim/profile/show.erb +3 -11
  57. data/app/cells/decidim/profile/user_group_tabs.erb +5 -0
  58. data/app/cells/decidim/profile/user_tabs.erb +12 -0
  59. data/app/cells/decidim/profile_cell.rb +7 -2
  60. data/app/cells/decidim/profile_sidebar/show.erb +108 -23
  61. data/app/cells/decidim/profile_sidebar_cell.rb +36 -2
  62. data/app/cells/decidim/user_group_admin_membership_profile/footer.erb +29 -0
  63. data/app/cells/decidim/user_group_admin_membership_profile_cell.rb +14 -0
  64. data/app/cells/decidim/user_group_membership_profile/tags.erb +1 -0
  65. data/app/cells/decidim/user_group_membership_profile_cell.rb +8 -0
  66. data/app/cells/decidim/user_group_pending_invitations_list/show.erb +23 -0
  67. data/app/cells/decidim/user_group_pending_invitations_list_cell.rb +26 -0
  68. data/app/cells/decidim/user_group_pending_requests_list/show.erb +23 -0
  69. data/app/cells/decidim/user_group_pending_requests_list_cell.rb +26 -0
  70. data/app/cells/decidim/user_profile/header.erb +1 -1
  71. data/app/cells/decidim/user_profile_cell.rb +15 -9
  72. data/app/commands/decidim/accept_group_invitation.rb +43 -0
  73. data/app/commands/decidim/accept_user_group_join_request.rb +53 -0
  74. data/app/commands/decidim/create_follow.rb +6 -0
  75. data/app/commands/decidim/create_registration.rb +13 -23
  76. data/app/commands/decidim/create_user_group.rb +57 -0
  77. data/app/commands/decidim/delete_follow.rb +7 -0
  78. data/app/commands/decidim/demote_membership.rb +57 -0
  79. data/app/commands/decidim/destroy_account.rb +6 -0
  80. data/app/commands/decidim/invite_user.rb +1 -3
  81. data/app/commands/decidim/invite_user_to_group.rb +62 -0
  82. data/app/commands/decidim/join_user_group.rb +63 -0
  83. data/app/commands/decidim/leave_user_group.rb +41 -0
  84. data/app/commands/decidim/promote_membership.rb +55 -0
  85. data/app/commands/decidim/reject_group_invitation.rb +42 -0
  86. data/app/commands/decidim/reject_user_group_join_request.rb +53 -0
  87. data/app/commands/decidim/remove_user_from_group.rb +53 -0
  88. data/app/commands/decidim/update_user_group.rb +53 -0
  89. data/app/controllers/concerns/decidim/locale_switcher.rb +3 -3
  90. data/app/controllers/concerns/decidim/paginable.rb +1 -0
  91. data/app/controllers/decidim/application_controller.rb +7 -0
  92. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +1 -1
  93. data/app/controllers/decidim/devise/sessions_controller.rb +1 -1
  94. data/app/controllers/decidim/gamification/badges_controller.rb +11 -0
  95. data/app/controllers/decidim/group_admins_controller.rb +41 -0
  96. data/app/controllers/decidim/group_invites_controller.rb +74 -0
  97. data/app/controllers/decidim/group_members_controller.rb +59 -0
  98. data/app/controllers/decidim/groups_controller.rb +85 -0
  99. data/app/controllers/decidim/last_activities_controller.rb +46 -0
  100. data/app/controllers/decidim/pages_controller.rb +9 -1
  101. data/app/controllers/decidim/profiles_controller.rb +35 -5
  102. data/app/controllers/decidim/user_group_join_requests_controller.rb +69 -0
  103. data/app/events/decidim/demoted_membership_event.rb +28 -0
  104. data/app/events/decidim/invited_to_group_event.rb +33 -0
  105. data/app/events/decidim/join_request_accepted_event.rb +28 -0
  106. data/app/events/decidim/join_request_created_event.rb +28 -0
  107. data/app/events/decidim/join_request_rejected_event.rb +28 -0
  108. data/app/events/decidim/promoted_to_admin_event.rb +28 -0
  109. data/app/events/decidim/removed_from_group_event.rb +28 -0
  110. data/app/forms/decidim/account_form.rb +1 -1
  111. data/app/forms/decidim/invite_user_to_group_form.rb +29 -0
  112. data/app/forms/decidim/notifications_settings_form.rb +4 -0
  113. data/app/forms/decidim/registration_form.rb +0 -27
  114. data/app/forms/decidim/user_group_form.rb +81 -0
  115. data/app/helpers/decidim/component_path_helper.rb +10 -0
  116. data/app/helpers/decidim/filters_helper.rb +3 -2
  117. data/app/helpers/decidim/icon_helper.rb +3 -1
  118. data/app/helpers/decidim/map_helper.rb +1 -1
  119. data/app/jobs/decidim/metric_job.rb +14 -0
  120. data/app/mailers/decidim/newsletter_mailer.rb +2 -0
  121. data/app/mailers/decidim/notification_mailer.rb +1 -1
  122. data/app/models/decidim/action_log.rb +66 -0
  123. data/app/models/decidim/coauthorship.rb +9 -0
  124. data/app/models/decidim/component.rb +5 -0
  125. data/app/models/decidim/continuity_badge_status.rb +9 -0
  126. data/app/models/decidim/gamification/badge_score.rb +1 -1
  127. data/app/models/decidim/messaging/message.rb +1 -0
  128. data/app/models/decidim/metric.rb +13 -0
  129. data/app/models/decidim/participatory_space_private_user.rb +4 -0
  130. data/app/models/decidim/user.rb +14 -38
  131. data/app/models/decidim/user_base_entity.rb +52 -0
  132. data/app/models/decidim/user_group.rb +48 -9
  133. data/app/models/decidim/user_group_membership.rb +8 -0
  134. data/app/permissions/decidim/permissions.rb +21 -0
  135. data/app/presenters/decidim/admin_log/organization_presenter.rb +0 -2
  136. data/app/presenters/decidim/admin_log/participatory_space_private_user_presenter.rb +38 -0
  137. data/app/presenters/decidim/metric_charts_presenter.rb +53 -0
  138. data/app/presenters/decidim/metric_object_presenter.rb +28 -0
  139. data/app/presenters/decidim/user_group_presenter.rb +16 -8
  140. data/app/presenters/decidim/user_presenter.rb +14 -0
  141. data/app/queries/decidim/metric_manage.rb +59 -0
  142. data/app/queries/decidim/metrics/users_metric_manage.rb +26 -0
  143. data/app/queries/decidim/user_groups/accepted_memberships.rb +36 -0
  144. data/app/queries/decidim/user_groups/accepted_user_groups.rb +38 -0
  145. data/app/queries/decidim/user_groups/accepted_users.rb +36 -0
  146. data/app/queries/decidim/user_groups/admin_memberships.rb +37 -0
  147. data/app/queries/decidim/user_groups/invited_memberships.rb +36 -0
  148. data/app/queries/decidim/user_groups/manageable_user_groups.rb +39 -0
  149. data/app/queries/decidim/user_groups/member_memberships.rb +37 -0
  150. data/app/resolvers/decidim/core/metric_resolver.rb +38 -0
  151. data/app/services/decidim/action_logger.rb +4 -2
  152. data/app/services/decidim/activity_search.rb +76 -0
  153. data/app/services/decidim/continuity_badge_tracker.rb +64 -0
  154. data/app/services/decidim/resource_search.rb +0 -1
  155. data/app/types/decidim/core/metric_history_type.rb +17 -0
  156. data/app/types/decidim/core/metric_type.rb +14 -0
  157. data/app/types/decidim/core/session_type.rb +1 -1
  158. data/app/types/decidim/core/user_group_type.rb +2 -2
  159. data/app/views/decidim/authorization_modals/show.html.erb +40 -27
  160. data/app/views/decidim/devise/registrations/new.html.erb +0 -19
  161. data/app/views/decidim/gamification/badges/index.html.erb +42 -0
  162. data/app/views/decidim/group_admins/index.html.erb +18 -0
  163. data/app/views/decidim/group_invites/index.html.erb +27 -0
  164. data/app/views/decidim/group_members/index.html.erb +19 -0
  165. data/app/views/decidim/groups/_form.html.erb +23 -0
  166. data/app/views/decidim/groups/edit.html.erb +26 -0
  167. data/app/views/decidim/groups/new.html.erb +26 -0
  168. data/app/views/decidim/last_activities/_activities.html.erb +13 -0
  169. data/app/views/decidim/last_activities/index.html.erb +18 -0
  170. data/app/views/decidim/last_activities/index.js.erb +6 -0
  171. data/app/views/decidim/profiles/show.html.erb +1 -1
  172. data/app/views/layouts/decidim/_user_menu.html.erb +0 -1
  173. data/app/views/layouts/decidim/_wrapper.html.erb +1 -1
  174. data/config/initializers/devise.rb +1 -1
  175. data/config/initializers/foundation_rails_helper.rb +1 -0
  176. data/config/locales/ca.yml +325 -32
  177. data/config/locales/de.yml +325 -32
  178. data/config/locales/en.yml +325 -32
  179. data/config/locales/es-PY.yml +325 -32
  180. data/config/locales/es.yml +325 -32
  181. data/config/locales/eu.yml +325 -32
  182. data/config/locales/fi.yml +330 -37
  183. data/config/locales/fr.yml +325 -32
  184. data/config/locales/gl.yml +325 -32
  185. data/config/locales/hu.yml +327 -34
  186. data/config/locales/it.yml +325 -32
  187. data/config/locales/nl.yml +325 -32
  188. data/config/locales/pl.yml +329 -32
  189. data/config/locales/pt-BR.yml +326 -33
  190. data/config/locales/pt.yml +325 -32
  191. data/config/locales/ru.yml +4 -33
  192. data/config/locales/sv.yml +346 -53
  193. data/config/locales/uk.yml +4 -33
  194. data/config/routes.rb +27 -1
  195. data/db/migrate/20170128112958_change_user_groups_verified_to_timestamp.rb +11 -0
  196. data/db/migrate/20180705134647_create_decidim_metrics.rb +16 -0
  197. data/db/migrate/20180730071851_add_core_content_blocks.rb +3 -3
  198. data/db/migrate/20180810092428_move_organization_fields_to_hero_content_block.rb +4 -2
  199. data/db/migrate/20180918072506_add_visibility_to_action_logs.rb +8 -0
  200. data/db/migrate/20181001124950_move_users_groups_to_users_table.rb +84 -0
  201. data/db/migrate/20181008102144_add_badge_switch_to_organizations.rb +8 -0
  202. data/db/migrate/20181010044613_create_decidim_continuity_badge_statuses.rb +11 -0
  203. data/db/migrate/20181011080252_add_roles_to_memberships.rb +24 -0
  204. data/db/migrate/20181016091601_make_authors_polymorphic.rb +31 -0
  205. data/db/migrate/20181029112820_fix_user_follows.rb +18 -0
  206. data/db/migrate/20181030090144_destroy_deleted_users_follows.rb +16 -0
  207. data/db/seeds.rb +18 -4
  208. data/lib/decidim/attributes.rb +1 -0
  209. data/lib/decidim/attributes/localized_date.rb +16 -0
  210. data/lib/decidim/attributes/time_with_zone.rb +3 -1
  211. data/lib/decidim/authorable.rb +5 -4
  212. data/lib/decidim/authorization_form_builder.rb +2 -2
  213. data/lib/decidim/coauthorable.rb +68 -18
  214. data/lib/decidim/content_block_manifest.rb +7 -0
  215. data/lib/decidim/content_processor.rb +17 -7
  216. data/lib/decidim/core.rb +12 -0
  217. data/lib/decidim/core/engine.rb +54 -6
  218. data/lib/decidim/core/test/factories.rb +63 -17
  219. data/lib/decidim/core/test/shared_examples/coauthorable.rb +27 -9
  220. data/lib/decidim/core/test/shared_examples/coauthorable_interface_examples.rb +2 -2
  221. data/lib/decidim/core/version.rb +1 -1
  222. data/lib/decidim/data_portability.rb +3 -1
  223. data/lib/decidim/data_portability_file_reader.rb +1 -1
  224. data/lib/decidim/events/author_event.rb +4 -1
  225. data/lib/decidim/events/coauthor_event.rb +4 -1
  226. data/lib/decidim/faker/localized.rb +5 -4
  227. data/lib/decidim/form_builder.rb +18 -17
  228. data/lib/decidim/gamification.rb +8 -2
  229. data/lib/decidim/gamification/badge.rb +34 -0
  230. data/lib/decidim/gamification/badge_scorer.rb +29 -14
  231. data/lib/decidim/gamification/badge_status.rb +2 -0
  232. data/lib/decidim/hashtaggable.rb +1 -1
  233. data/lib/decidim/manifest_registry.rb +5 -3
  234. data/lib/decidim/metric_manifest.rb +20 -0
  235. data/lib/decidim/metric_registry.rb +71 -0
  236. data/lib/decidim/participable.rb +1 -1
  237. data/lib/decidim/participatory_space_resourceable.rb +0 -1
  238. data/lib/decidim/query_extensions.rb +19 -0
  239. data/lib/decidim/resourceable.rb +1 -0
  240. data/lib/decidim/searchable.rb +2 -1
  241. data/lib/tasks/decidim_metrics_tasks.rake +41 -0
  242. data/lib/tasks/decidim_tasks.rake +1 -0
  243. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.ca.js +1 -2
  244. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.es.js +1 -2
  245. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.fr.js +1 -2
  246. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.gl.js +1 -2
  247. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.pt.js +1 -2
  248. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.ru.js +1 -2
  249. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.uk.js +1 -2
  250. data/vendor/assets/javascripts/form_datepicker.js.es6 +1 -11
  251. metadata +144 -23
  252. data/app/cells/decidim/invitations_toggle/content.erb +0 -1
  253. data/app/cells/decidim/invitations_toggle/label.erb +0 -1
  254. data/app/cells/decidim/invitations_toggle_cell.rb +0 -27
  255. data/app/cells/decidim/toggle/show.erb +0 -8
  256. data/app/cells/decidim/toggle_cell.rb +0 -42
  257. data/app/commands/decidim/invite_friends.rb +0 -48
  258. data/app/controllers/decidim/invitations_controller.rb +0 -32
  259. data/app/forms/decidim/invitations_form.rb +0 -37
  260. data/app/views/decidim/invitations/index.html.erb +0 -48
  261. data/app/views/devise/mailer/invite_friend.html.erb +0 -27
  262. data/app/views/devise/mailer/invite_friend.text.erb +0 -19
  263. data/lib/decidim/rectify_ext.rb +0 -32
data/db/seeds.rb CHANGED
@@ -7,6 +7,15 @@ if !Rails.env.production? || ENV["SEED"]
7
7
 
8
8
  seeds_root = File.join(__dir__, "seeds")
9
9
 
10
+ # Since we usually migrate and seed in the same process, make sure
11
+ # that we don't have invalid or cached information after a migration.
12
+ decidim_tables = ActiveRecord::Base.connection.tables.select do |table|
13
+ table.starts_with?("decidim_")
14
+ end
15
+ decidim_tables.map do |table|
16
+ table.tr("_", "/").classify.safe_constantize
17
+ end.compact.each(&:reset_column_information)
18
+
10
19
  organization = Decidim::Organization.first || Decidim::Organization.create!(
11
20
  name: Faker::Company.name,
12
21
  twitter_handler: Faker::Hipster.word,
@@ -22,7 +31,8 @@ if !Rails.env.production? || ENV["SEED"]
22
31
  available_locales: Decidim.available_locales,
23
32
  reference_prefix: Faker::Name.suffix,
24
33
  available_authorizations: Decidim.authorization_workflows.map(&:name),
25
- tos_version: Time.current
34
+ tos_version: Time.current,
35
+ badges_enabled: true
26
36
  )
27
37
 
28
38
  if organization.top_scopes.none?
@@ -129,14 +139,18 @@ if !Rails.env.production? || ENV["SEED"]
129
139
  [nil, Time.current].each do |verified_at|
130
140
  user_group = Decidim::UserGroup.create!(
131
141
  name: Faker::Company.unique.name,
132
- document_number: Faker::Number.number(10),
133
- phone: Faker::PhoneNumber.phone_number,
134
- verified_at: verified_at,
142
+ nickname: Faker::Twitter.unique.screen_name,
143
+ extended_data: {
144
+ document_number: Faker::Number.number(10),
145
+ phone: Faker::PhoneNumber.phone_number,
146
+ verified_at: verified_at
147
+ },
135
148
  decidim_organization_id: user.organization.id
136
149
  )
137
150
 
138
151
  Decidim::UserGroupMembership.create!(
139
152
  user: user,
153
+ role: "creator",
140
154
  user_group: user_group
141
155
  )
142
156
  end
@@ -3,5 +3,6 @@
3
3
  module Decidim
4
4
  module Attributes
5
5
  autoload :TimeWithZone, "decidim/attributes/time_with_zone"
6
+ autoload :LocalizedDate, "decidim/attributes/localized_date"
6
7
  end
7
8
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Attributes
5
+ # Custom Virtus value to parse a String representing a Date using
6
+ # the app localization format.
7
+ class LocalizedDate < Virtus::Attribute
8
+ def coerce(value)
9
+ return value unless value.is_a?(String)
10
+ Date.strptime(value, I18n.t("date.formats.decidim_short"))
11
+ rescue ArgumentError
12
+ nil
13
+ end
14
+ end
15
+ end
16
+ end
@@ -7,7 +7,9 @@ module Decidim
7
7
  class TimeWithZone < Virtus::Attribute
8
8
  def coerce(value)
9
9
  return value unless value.is_a?(String)
10
- Time.zone.parse(value)
10
+ Time.zone.strptime(value, I18n.t("time.formats.decidim_short"))
11
+ rescue ArgumentError
12
+ nil
11
13
  end
12
14
  end
13
15
  end
@@ -9,9 +9,10 @@ module Decidim
9
9
  extend ActiveSupport::Concern
10
10
 
11
11
  included do
12
- belongs_to :author, foreign_key: "decidim_author_id", class_name: "Decidim::User", optional: true
12
+ belongs_to :author, polymorphic: true, foreign_key: "decidim_author_id", foreign_type: "decidim_author_type"
13
13
  belongs_to :user_group, foreign_key: "decidim_user_group_id", class_name: "Decidim::UserGroup", optional: true
14
14
 
15
+ validates :author, presence: true
15
16
  validate :verified_user_group, :user_group_membership
16
17
  validate :author_belongs_to_organization
17
18
 
@@ -19,8 +20,8 @@ module Decidim
19
20
  # authoring it or via a user group.
20
21
  #
21
22
  # user - the user to check for authorship
22
- def authored_by?(user)
23
- author == user || user.user_groups.include?(user_group)
23
+ def authored_by?(other_author)
24
+ other_author == author || other_author.respond_to?(:user_groups) && other_author.user_groups.include?(user_group)
24
25
  end
25
26
 
26
27
  # Returns the normalized author, whether it's a user group or a user. Ideally this should be
@@ -45,7 +46,7 @@ module Decidim
45
46
 
46
47
  def author_belongs_to_organization
47
48
  return if !author || !organization
48
- errors.add(:author, :invalid) unless author.organization == organization
49
+ errors.add(:author, :invalid) unless author == organization || author.respond_to?(:organization) && author.organization == organization
49
50
  end
50
51
  end
51
52
  end
@@ -39,7 +39,7 @@ module Decidim
39
39
  return hidden_field(name) if name.to_s == "handler_name"
40
40
 
41
41
  case type.name
42
- when "Date"
42
+ when "Date", "Decidim::Attributes::LocalizedDate"
43
43
  date_field name
44
44
  else
45
45
  text_field name
@@ -58,7 +58,7 @@ module Decidim
58
58
 
59
59
  def public_attributes
60
60
  form_attributes.inject({}) do |all, attribute|
61
- all.update(attribute.name => attribute.type.primitive)
61
+ all.update(attribute.name => attribute.class)
62
62
  end
63
63
  end
64
64
 
@@ -12,23 +12,62 @@ module Decidim
12
12
  extend ActiveSupport::Concern
13
13
 
14
14
  included do
15
- has_many :coauthorships, -> { order(:created_at) }, as: :coauthorable, class_name: "Decidim::Coauthorship", dependent: :destroy
16
- has_many :authors, -> { order(:created_at) }, through: :coauthorships, class_name: "Decidim::User"
15
+ has_many :coauthorships, -> { order(:created_at) }, as: :coauthorable, class_name: "Decidim::Coauthorship", dependent: :destroy, inverse_of: :coauthorable
17
16
  has_many :user_groups, -> { order(:created_at) }, as: :coauthorable, class_name: "Decidim::UserGroup", through: :coauthorships
18
17
 
19
- # retrieves models from all identities of the user.
20
- scope :from_all_user_identities, ->(user) { joins(:coauthorships).where("decidim_coauthorships.decidim_author_id": user.id) }
21
- # retrieves models from the given User, ignoring the UserGroups it belongs to.
22
- scope :from_author, ->(author) { joins(:coauthorships).where("decidim_coauthorships.decidim_author_id": author.id).where("decidim_coauthorships.decidim_user_group_id": nil) }
18
+ # retrieves models from all identities of the author.
19
+ scope :from_all_author_identities, lambda { |author|
20
+ joins(:coauthorships).where("decidim_coauthorships.decidim_author_id = ? AND decidim_coauthorships.decidim_author_type = ?", author.id, author.class.base_class.name)
21
+ }
22
+ # retrieves models from the given author, ignoring the UserGroups it belongs to.
23
+ scope :from_author, ->(author) { from_all_author_identities(author).where("decidim_coauthorships.decidim_user_group_id": nil) }
23
24
  # retrieves models from the given UserGroup.
24
25
  scope :from_user_group, ->(user_group) { joins(:coauthorships).where("decidim_coauthorships.decidim_user_group_id": user_group.id) }
25
26
 
27
+ validates :coauthorships, presence: true
28
+
29
+ # Overwrite default reload method to unset the instance variables so reloading works as expected.
30
+ def reload(options = nil)
31
+ remove_instance_variable(:@authors) if defined?(@authors)
32
+ remove_instance_variable(:@notifiable_authors) if defined?(@notifiable_authors)
33
+ super(options)
34
+ end
35
+
36
+ # Returns all the authors of a coauthorable.
37
+ #
38
+ # We need to do it this ways since the authors are polymorphic, and we can't have a has_many through relation
39
+ # with polymorphic objects.
40
+ def authors
41
+ return @authors if defined?(@authors)
42
+
43
+ authors = coauthorships.pluck(:decidim_author_id, :decidim_author_type).each_with_object({}) do |(id, klass), all|
44
+ all[klass] ||= []
45
+ all[klass] << id
46
+ end
47
+
48
+ @authors = authors.flat_map do |klass, ids|
49
+ klass.constantize.where(id: ids)
50
+ end.compact.uniq
51
+ end
52
+
53
+ # Returns the authors that should be notified for a coauthorable.
54
+ #
55
+ def notifiable_authors
56
+ @notifiable_authors ||= authors.flat_map do |author|
57
+ if author.is_a?(Decidim::User)
58
+ author
59
+ elsif respond_to?(:component)
60
+ component.participatory_space.admins
61
+ end
62
+ end.compact.uniq
63
+ end
64
+
26
65
  # Checks whether the user is author of the given proposal, either directly
27
66
  # authoring it or via a user group.
28
67
  #
29
- # user - the user to check for authorship
30
- def authored_by?(user)
31
- coauthorships.where(author: user).exists?
68
+ # author - the author to check for authorship
69
+ def authored_by?(author)
70
+ coauthorships.where(author: author).exists?
32
71
  end
33
72
 
34
73
  # Returns the identities for the authors, whether they are user groups or users.
@@ -40,30 +79,41 @@ module Decidim
40
79
 
41
80
  # Syntactic sugar to access first coauthor as a Coauthorship.
42
81
  def creator
43
- coauthorships.first
82
+ coauthorships.order(:created_at).first
44
83
  end
45
84
 
46
85
  # Syntactic sugar to access first coauthor Author
47
86
  def creator_author
48
- authors.first
87
+ creator.try(:author)
49
88
  end
50
89
 
51
90
  # Syntactic sugar to access first identity whether it is a User or a UserGroup.
52
91
  # @return The User od UserGroup that created this Coauthorable.
53
92
  def creator_identity
54
- coauthorships.order(:created_at).first&.identity
93
+ creator.try(:identity)
55
94
  end
56
95
 
57
96
  # Adds a new coauthor to the list of coauthors. The coauthorship is created with
58
97
  # current object as coauthorable and `user` param as author. To set the user group
59
- # use `extra_attrs` either with `user_group` or `decidim_user_group_id` keys.
98
+ # use `extra_attributes` either with `user_group` or `decidim_user_group_id` keys.
60
99
  #
61
- # @param user: The new coauthor.
100
+ # @param author: The new coauthor.
62
101
  # @extra_attrs: Extra
63
- def add_coauthor(user, extra_attrs = {})
64
- attrs = { coauthorable: self, author: user }
65
- Decidim::Coauthorship.create!(attrs.merge(extra_attrs))
66
- Decidim::Follow.create!(followable: self, user: user) unless followers.exists?(user.id)
102
+ def add_coauthor(author, extra_attributes = {})
103
+ user_group = extra_attributes[:user_group]
104
+
105
+ return if coauthorships.where(decidim_author_id: author.id, decidim_author_type: author.class.base_class.name).exists? && user_group.blank?
106
+ return if user_group && coauthorships.where(user_group: user_group).exists?
107
+
108
+ coauthorship_attributes = extra_attributes.merge(author: author)
109
+
110
+ if persisted?
111
+ coauthorships.create!(coauthorship_attributes)
112
+ else
113
+ coauthorships.build(coauthorship_attributes)
114
+ end
115
+
116
+ authors << author
67
117
  end
68
118
  end
69
119
  end
@@ -27,12 +27,19 @@ module Decidim
27
27
  attribute :cell, String
28
28
  attribute :settings_form_cell, String
29
29
  attribute :images, Array[Hash]
30
+ attribute :default, Boolean, default: false
30
31
 
31
32
  validates :name, :cell, :public_name_key, presence: true
32
33
  validates :settings_form_cell, presence: true, if: :has_settings?
33
34
  validate :image_names_are_unique
34
35
  validate :images_have_an_uploader
35
36
 
37
+ # Public: Registers whether this content block should be shown by default
38
+ # when creating an organization. Use `#default` to retrieve it.
39
+ def default!
40
+ self.default = true
41
+ end
42
+
36
43
  def has_settings?
37
44
  settings.attributes.any?
38
45
  end
@@ -61,13 +61,23 @@ module Decidim
61
61
  end
62
62
 
63
63
  def self.parse_with_processor(_type, content, context)
64
- parsed = Decidim.content_processors.each_with_object(rewrite: content, metadata: {}) do |type, result|
65
- next unless type == :hashtag
66
- parser = parser_klass(type).constantize.new(result[:rewrite], context)
67
- result[:rewrite] = parser.rewrite
68
- result[:metadata][type] = parser.metadata
69
- end
70
-
64
+ parsed = if content.is_a?(Hash)
65
+ Decidim.content_processors.each_with_object(rewrite: content, metadata: {}) do |type, result|
66
+ next unless type == :hashtag
67
+ result[:rewrite].each do |key, value|
68
+ parser = parser_klass(type).constantize.new(value, context)
69
+ result[:rewrite][key] = parser.rewrite
70
+ result[:metadata][type] = parser.metadata
71
+ end
72
+ end
73
+ else
74
+ Decidim.content_processors.each_with_object(rewrite: content, metadata: {}) do |type, result|
75
+ next unless type == :hashtag
76
+ parser = parser_klass(type).constantize.new(result[:rewrite], context)
77
+ result[:rewrite] = parser.rewrite
78
+ result[:metadata][type] = parser.metadata
79
+ end
80
+ end
71
81
  Result.new(parsed[:rewrite], parsed[:metadata])
72
82
  end
73
83
 
data/lib/decidim/core.rb CHANGED
@@ -50,6 +50,8 @@ module Decidim
50
50
  autoload :ViewHooks, "decidim/view_hooks"
51
51
  autoload :ContentBlockRegistry, "decidim/content_block_registry"
52
52
  autoload :ContentBlockManifest, "decidim/content_block_manifest"
53
+ autoload :MetricRegistry, "decidim/metric_registry"
54
+ autoload :MetricManifest, "decidim/metric_manifest"
53
55
  autoload :NewsletterEncryptor, "decidim/newsletter_encryptor"
54
56
  autoload :Searchable, "decidim/searchable"
55
57
  autoload :SearchResourceFieldsMapper, "decidim/search_resource_fields_mapper"
@@ -213,6 +215,11 @@ module Decidim
213
215
  1.minute
214
216
  end
215
217
 
218
+ # Time window were users can access the website even if their email is not confirmed.
219
+ config_accessor :unconfirmed_access_for do
220
+ 2.days
221
+ end
222
+
216
223
  # A base path for the uploads. If set, make sure it ends in a slash.
217
224
  # Uploads will be set to `<base_path>/uploads/`. This can be useful if you
218
225
  # want to use the same uploads place for both staging and production
@@ -380,4 +387,9 @@ module Decidim
380
387
  def self.traceability
381
388
  @traceability ||= Traceability.new
382
389
  end
390
+
391
+ # Public: Stores an instance of ContentBlockRegistry
392
+ def self.metrics_registry
393
+ @metrics_registry ||= MetricRegistry.new
394
+ end
383
395
  end
@@ -15,12 +15,7 @@ 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
21
18
  require "rectify"
22
- require "decidim/rectify_ext"
23
-
24
19
  require "carrierwave"
25
20
  require "rails-i18n"
26
21
  require "date_validator"
@@ -42,6 +37,7 @@ require "doorkeeper"
42
37
  require "doorkeeper-i18n"
43
38
  require "nobspw"
44
39
  require "kaminari"
40
+ require "batch-loader"
45
41
 
46
42
  require "decidim/api"
47
43
 
@@ -60,6 +56,7 @@ module Decidim
60
56
 
61
57
  initializer "decidim.middleware" do |app|
62
58
  app.config.middleware.use Decidim::CurrentOrganization
59
+ app.config.middleware.use BatchLoader::Middleware
63
60
  end
64
61
 
65
62
  initializer "decidim.assets" do |app|
@@ -140,7 +137,7 @@ module Decidim
140
137
 
141
138
  menu.item I18n.t("menu.more_information", scope: "decidim"),
142
139
  decidim.pages_path,
143
- position: 3,
140
+ position: 7,
144
141
  active: :inclusive
145
142
  end
146
143
  end
@@ -274,6 +271,20 @@ module Decidim
274
271
  resource.model_class_name = "Decidim::User"
275
272
  resource.card = "decidim/user_profile"
276
273
  end
274
+
275
+ Decidim.register_resource(:user_group) do |resource|
276
+ resource.model_class_name = "Decidim::UserGroup"
277
+ resource.card = "decidim/user_profile"
278
+ end
279
+ end
280
+
281
+ initializer "decidim.core.register_metrics" do
282
+ Decidim.metrics_registry.register(
283
+ :users,
284
+ "Decidim::Metrics::UsersMetricManage",
285
+ Decidim::MetricRegistry::HIGHLIGHTED,
286
+ 1
287
+ )
277
288
  end
278
289
 
279
290
  initializer "decidim.core.content_blocks" do
@@ -292,31 +303,59 @@ module Decidim
292
303
  content_block.settings do |settings|
293
304
  settings.attribute :welcome_text, type: :text, translated: true
294
305
  end
306
+
307
+ content_block.default!
295
308
  end
296
309
 
297
310
  Decidim.content_blocks.register(:homepage, :sub_hero) do |content_block|
298
311
  content_block.cell = "decidim/content_blocks/sub_hero"
299
312
  content_block.public_name_key = "decidim.content_blocks.sub_hero.name"
313
+ content_block.default!
300
314
  end
301
315
 
302
316
  Decidim.content_blocks.register(:homepage, :highlighted_content_banner) do |content_block|
303
317
  content_block.cell = "decidim/content_blocks/highlighted_content_banner"
304
318
  content_block.public_name_key = "decidim.content_blocks.highlighted_content_banner.name"
319
+ content_block.default!
305
320
  end
306
321
 
307
322
  Decidim.content_blocks.register(:homepage, :how_to_participate) do |content_block|
308
323
  content_block.cell = "decidim/content_blocks/how_to_participate"
309
324
  content_block.public_name_key = "decidim.content_blocks.how_to_participate.name"
325
+ content_block.default!
326
+ end
327
+
328
+ Decidim.content_blocks.register(:homepage, :last_activity) do |content_block|
329
+ content_block.cell = "decidim/content_blocks/last_activity"
330
+ content_block.public_name_key = "decidim.content_blocks.last_activity.name"
331
+ content_block.default!
310
332
  end
311
333
 
312
334
  Decidim.content_blocks.register(:homepage, :stats) do |content_block|
313
335
  content_block.cell = "decidim/content_blocks/stats"
314
336
  content_block.public_name_key = "decidim.content_blocks.stats.name"
337
+ content_block.default!
338
+ end
339
+
340
+ Decidim.content_blocks.register(:homepage, :metrics) do |content_block|
341
+ content_block.cell = "decidim/content_blocks/metrics"
342
+ content_block.public_name_key = "decidim.content_blocks.metrics.name"
315
343
  end
316
344
 
317
345
  Decidim.content_blocks.register(:homepage, :footer_sub_hero) do |content_block|
318
346
  content_block.cell = "decidim/content_blocks/footer_sub_hero"
319
347
  content_block.public_name_key = "decidim.content_blocks.footer_sub_hero.name"
348
+ content_block.default!
349
+ end
350
+
351
+ Decidim.content_blocks.register(:homepage, :html) do |content_block|
352
+ content_block.cell = "decidim/content_blocks/html"
353
+ content_block.public_name_key = "decidim.content_blocks.html.name"
354
+ content_block.settings_form_cell = "decidim/content_blocks/html_settings_form"
355
+
356
+ content_block.settings do |settings|
357
+ settings.attribute :html_content, type: :text, translated: true
358
+ end
320
359
  end
321
360
  end
322
361
 
@@ -325,6 +364,15 @@ module Decidim
325
364
  badge.levels = [1, 5, 10, 30, 50]
326
365
  badge.reset = ->(user) { Decidim::User.where(invited_by: user.id).count }
327
366
  end
367
+
368
+ Decidim::Gamification.register_badge(:followers) do |badge|
369
+ badge.levels = [1, 15, 30, 60, 100]
370
+ badge.reset = ->(user) { user.followers.count }
371
+ end
372
+
373
+ Decidim::Gamification.register_badge(:continuity) do |badge|
374
+ badge.levels = [2, 10, 30, 60, 180, 365]
375
+ end
328
376
  end
329
377
  end
330
378
  end