decidim-core 0.26.2 → 0.27.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (543) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/cells/decidim/amendable/announcement_cell.rb +3 -8
  4. data/app/cells/decidim/announcement_cell.rb +1 -1
  5. data/app/cells/decidim/author_cell.rb +1 -1
  6. data/app/cells/decidim/content_blocks/footer_sub_hero/show.erb +1 -1
  7. data/app/cells/decidim/content_blocks/hero/show.erb +1 -1
  8. data/app/cells/decidim/content_blocks/highlighted_content_banner/show.erb +3 -3
  9. data/app/cells/decidim/content_blocks/highlighted_elements_cell.rb +1 -1
  10. data/app/cells/decidim/content_blocks/how_to_participate/show.erb +1 -1
  11. data/app/cells/decidim/content_blocks/last_activity/show.erb +1 -1
  12. data/app/cells/decidim/content_blocks/last_activity_cell.rb +3 -3
  13. data/app/cells/decidim/content_blocks/stats_cell.rb +4 -4
  14. data/app/cells/decidim/content_blocks/sub_hero/show.erb +1 -1
  15. data/app/cells/decidim/data_consent/category.erb +64 -0
  16. data/app/cells/decidim/data_consent/dialog.erb +29 -0
  17. data/app/cells/decidim/data_consent/modal.erb +39 -0
  18. data/app/cells/decidim/data_consent/show.erb +3 -0
  19. data/app/cells/decidim/data_consent_cell.rb +21 -0
  20. data/app/cells/decidim/follow_button_cell.rb +5 -7
  21. data/app/cells/decidim/profile_sidebar_cell.rb +1 -1
  22. data/app/cells/decidim/search_results_cell.rb +1 -1
  23. data/app/cells/decidim/tos_page/refuse_btn_modal.erb +1 -1
  24. data/app/cells/decidim/upload_modal/files.erb +52 -0
  25. data/app/cells/decidim/upload_modal/modal.erb +49 -0
  26. data/app/cells/decidim/upload_modal/show.erb +3 -0
  27. data/app/cells/decidim/upload_modal_cell.rb +205 -0
  28. data/app/cells/decidim/user_conversation/reply.erb +1 -1
  29. data/app/cells/decidim/user_conversations/add_conversation_users.erb +5 -3
  30. data/app/cells/decidim/version_cell.rb +2 -13
  31. data/app/cells/decidim/versions_list_cell.rb +2 -13
  32. data/app/cells/decidim/versions_list_item_cell.rb +2 -13
  33. data/app/commands/decidim/accept_group_invitation.rb +1 -1
  34. data/app/commands/decidim/accept_user_group_join_request.rb +1 -1
  35. data/app/commands/decidim/amendable/accept.rb +1 -1
  36. data/app/commands/decidim/amendable/create_draft.rb +1 -1
  37. data/app/commands/decidim/amendable/destroy_draft.rb +1 -1
  38. data/app/commands/decidim/amendable/promote.rb +1 -1
  39. data/app/commands/decidim/amendable/publish_draft.rb +1 -1
  40. data/app/commands/decidim/amendable/reject.rb +1 -1
  41. data/app/commands/decidim/amendable/update_draft.rb +1 -1
  42. data/app/commands/decidim/amendable/withdraw.rb +1 -1
  43. data/app/commands/decidim/attachment_methods.rb +3 -2
  44. data/app/commands/decidim/create_editor_image.rb +1 -1
  45. data/app/commands/decidim/create_follow.rb +1 -1
  46. data/app/commands/decidim/create_omniauth_registration.rb +2 -3
  47. data/app/commands/decidim/create_registration.rb +1 -2
  48. data/app/commands/decidim/create_report.rb +1 -1
  49. data/app/commands/decidim/create_user_group.rb +2 -2
  50. data/app/commands/decidim/create_user_report.rb +5 -3
  51. data/app/commands/decidim/delete_follow.rb +1 -1
  52. data/app/commands/decidim/demote_membership.rb +1 -1
  53. data/app/commands/decidim/destroy_account.rb +1 -1
  54. data/app/commands/decidim/endorse_resource.rb +1 -1
  55. data/app/commands/decidim/gallery_methods.rb +45 -10
  56. data/app/commands/decidim/invite_user.rb +1 -3
  57. data/app/commands/decidim/invite_user_again.rb +1 -1
  58. data/app/commands/decidim/invite_user_to_group.rb +1 -1
  59. data/app/commands/decidim/join_user_group.rb +1 -1
  60. data/app/commands/decidim/leave_user_group.rb +8 -2
  61. data/app/commands/decidim/messaging/reply_to_conversation.rb +2 -2
  62. data/app/commands/decidim/messaging/start_conversation.rb +2 -2
  63. data/app/commands/decidim/multiple_attachments_methods.rb +44 -5
  64. data/app/commands/decidim/promote_membership.rb +1 -1
  65. data/app/commands/decidim/reject_group_invitation.rb +1 -1
  66. data/app/commands/decidim/reject_user_group_join_request.rb +1 -1
  67. data/app/commands/decidim/remove_user_from_group.rb +1 -1
  68. data/app/commands/decidim/resend_confirmation_instructions.rb +18 -0
  69. data/app/commands/decidim/search.rb +10 -9
  70. data/app/commands/decidim/unendorse_resource.rb +1 -1
  71. data/app/commands/decidim/unsubscribe_settings.rb +1 -1
  72. data/app/commands/decidim/update_account.rb +2 -2
  73. data/app/commands/decidim/update_notifications_settings.rb +3 -2
  74. data/app/commands/decidim/update_password.rb +31 -0
  75. data/app/commands/decidim/update_user_group.rb +2 -2
  76. data/app/commands/decidim/update_user_interests.rb +1 -1
  77. data/app/commands/decidim/validate_upload.rb +15 -0
  78. data/app/controllers/concerns/decidim/devise_controllers.rb +0 -1
  79. data/app/controllers/concerns/decidim/filter_resource.rb +23 -24
  80. data/app/controllers/concerns/decidim/force_authentication.rb +1 -2
  81. data/app/controllers/concerns/decidim/http_caching_disabler.rb +1 -1
  82. data/app/controllers/concerns/decidim/needs_password_change.rb +43 -0
  83. data/app/controllers/concerns/decidim/needs_tos_accepted.rb +3 -3
  84. data/app/controllers/concerns/decidim/orderable.rb +1 -1
  85. data/app/controllers/concerns/decidim/participatory_space_context.rb +2 -2
  86. data/app/controllers/decidim/account_controller.rb +45 -0
  87. data/app/controllers/decidim/application_controller.rb +1 -1
  88. data/app/controllers/decidim/devise/invitations_controller.rb +2 -0
  89. data/app/controllers/decidim/devise/passwords_controller.rb +33 -0
  90. data/app/controllers/decidim/devise/registrations_controller.rb +2 -0
  91. data/app/controllers/decidim/devise/sessions_controller.rb +2 -0
  92. data/app/controllers/decidim/{data_portability_controller.rb → download_your_data_controller.rb} +8 -8
  93. data/app/controllers/decidim/groups_controller.rb +5 -0
  94. data/app/controllers/decidim/last_activities_controller.rb +7 -9
  95. data/app/controllers/decidim/manifests_controller.rb +11 -0
  96. data/app/controllers/decidim/newsletters_controller.rb +1 -1
  97. data/app/controllers/decidim/notifications_subscriptions_controller.rb +16 -0
  98. data/app/controllers/decidim/offline_controller.rb +7 -0
  99. data/app/controllers/decidim/profiles_controller.rb +1 -1
  100. data/app/controllers/decidim/searches_controller.rb +4 -3
  101. data/app/controllers/decidim/short_links_controller.rb +35 -0
  102. data/app/controllers/decidim/upload_validations_controller.rb +44 -0
  103. data/app/controllers/decidim/user_activities_controller.rb +32 -16
  104. data/app/controllers/decidim/user_interests_controller.rb +0 -2
  105. data/app/controllers/decidim/user_timeline_controller.rb +6 -8
  106. data/app/events/decidim/change_nickname_event.rb +21 -0
  107. data/app/forms/decidim/account_form.rb +7 -6
  108. data/app/forms/decidim/form.rb +1 -1
  109. data/app/forms/decidim/messaging/conversation_form.rb +1 -1
  110. data/app/forms/decidim/notifications_settings_form.rb +8 -2
  111. data/app/forms/decidim/password_form.rb +10 -0
  112. data/app/forms/decidim/registration_form.rb +10 -4
  113. data/app/forms/decidim/upload_validation_form.rb +54 -0
  114. data/app/forms/decidim/user_group_form.rb +1 -1
  115. data/app/forms/decidim/user_interest_scope_form.rb +1 -1
  116. data/app/forms/decidim/user_interests_form.rb +1 -1
  117. data/app/forms/translatable_presence_validator.rb +2 -2
  118. data/app/forms/url_validator.rb +1 -1
  119. data/app/helpers/decidim/application_helper.rb +2 -2
  120. data/app/helpers/decidim/attachments_helper.rb +1 -1
  121. data/app/helpers/decidim/cells_paginate_helper.rb +1 -1
  122. data/app/helpers/decidim/datalist_select_helper.rb +40 -0
  123. data/app/helpers/decidim/decidim_form_helper.rb +1 -1
  124. data/app/helpers/decidim/followable_helper.rb +1 -1
  125. data/app/helpers/decidim/icon_helper.rb +1 -1
  126. data/app/helpers/decidim/layout_helper.rb +15 -1
  127. data/app/helpers/decidim/map_helper.rb +12 -8
  128. data/app/helpers/decidim/meta_tags_helper.rb +0 -2
  129. data/app/helpers/decidim/notifications_settings_helper.rb +15 -0
  130. data/app/helpers/decidim/passwords_helper.rb +41 -0
  131. data/app/helpers/decidim/sanitize_helper.rb +1 -0
  132. data/app/helpers/decidim/searches_helper.rb +6 -6
  133. data/app/helpers/decidim/short_link_helper.rb +28 -0
  134. data/app/helpers/decidim/translations_helper.rb +2 -2
  135. data/app/jobs/decidim/{data_portability_export_job.rb → download_your_data_export_job.rb} +5 -5
  136. data/app/jobs/decidim/email_notifications_digest_generator_job.rb +21 -0
  137. data/app/jobs/decidim/notification_generator_for_recipient_job.rb +5 -3
  138. data/app/jobs/decidim/reminder_generator_job.rb +12 -0
  139. data/app/jobs/decidim/resend_confirmation_instructions_job.rb +11 -0
  140. data/app/jobs/decidim/user_report_job.rb +2 -2
  141. data/app/mailers/concerns/decidim/multitenant_asset_host.rb +11 -3
  142. data/app/mailers/decidim/application_mailer.rb +1 -1
  143. data/app/mailers/decidim/block_user_mailer.rb +8 -7
  144. data/app/mailers/decidim/export_mailer.rb +2 -2
  145. data/app/mailers/decidim/newsletter_mailer.rb +2 -2
  146. data/app/mailers/decidim/newsletters_opt_in_mailer.rb +7 -5
  147. data/app/mailers/decidim/notifications_digest_mailer.rb +23 -0
  148. data/app/mailers/decidim/user_report_mailer.rb +10 -11
  149. data/app/models/decidim/action_log.rb +86 -2
  150. data/app/models/decidim/amendment.rb +0 -1
  151. data/app/models/decidim/area.rb +1 -2
  152. data/app/models/decidim/area_type.rb +5 -0
  153. data/app/models/decidim/attachment.rb +6 -0
  154. data/app/models/decidim/attachment_collection.rb +5 -0
  155. data/app/models/decidim/category.rb +9 -4
  156. data/app/models/decidim/coauthorship.rb +0 -2
  157. data/app/models/decidim/contextual_help_section.rb +5 -1
  158. data/app/models/decidim/follow.rb +2 -2
  159. data/app/models/decidim/gamification/badge_score.rb +0 -1
  160. data/app/models/decidim/identity.rb +2 -2
  161. data/app/models/decidim/messaging/conversation.rb +4 -4
  162. data/app/models/decidim/messaging/message.rb +1 -2
  163. data/app/models/decidim/messaging/participation.rb +0 -2
  164. data/app/models/decidim/messaging/receipt.rb +0 -2
  165. data/app/models/decidim/notification.rb +5 -2
  166. data/app/models/decidim/oauth_application.rb +12 -1
  167. data/app/models/decidim/organization.rb +7 -7
  168. data/app/models/decidim/participatory_space_private_user.rb +4 -2
  169. data/app/models/decidim/permission_action.rb +1 -0
  170. data/app/models/decidim/reminder.rb +10 -0
  171. data/app/models/decidim/reminder_delivery.rb +7 -0
  172. data/app/models/decidim/reminder_record.rb +29 -0
  173. data/app/models/decidim/report.rb +2 -2
  174. data/app/models/decidim/scope.rb +3 -4
  175. data/app/models/decidim/scope_type.rb +5 -0
  176. data/app/models/decidim/share_token.rb +0 -2
  177. data/app/models/decidim/short_link.rb +162 -0
  178. data/app/models/decidim/user.rb +34 -6
  179. data/app/models/decidim/user_base_entity.rb +1 -1
  180. data/app/models/decidim/user_group.rb +3 -3
  181. data/app/models/decidim/user_moderation.rb +0 -2
  182. data/app/models/decidim/user_report.rb +2 -2
  183. data/app/packs/entrypoints/decidim_core.js +2 -2
  184. data/app/packs/entrypoints/decidim_sw.js +1 -0
  185. data/app/packs/src/decidim/autocomplete.js +298 -0
  186. data/app/packs/src/decidim/cookie_consent/consent_manager.js +133 -0
  187. data/app/packs/src/decidim/cookie_consent/cookie_consent.js +103 -0
  188. data/app/packs/src/decidim/datalist_select.js +36 -0
  189. data/app/packs/src/decidim/direct_uploads/upload_field.js +117 -0
  190. data/app/packs/src/decidim/direct_uploads/upload_modal.js +264 -0
  191. data/app/packs/src/decidim/direct_uploads/upload_utility.js +49 -0
  192. data/app/packs/src/decidim/direct_uploads/uploader.js +89 -0
  193. data/app/packs/src/decidim/external_domain_warning.js +1 -1
  194. data/app/packs/src/decidim/external_link.js +14 -3
  195. data/app/packs/src/decidim/external_link.test.js +64 -0
  196. data/app/packs/src/decidim/geocoding.js +10 -35
  197. data/app/packs/src/decidim/identity_selector_dialog.js +1 -1
  198. data/app/packs/src/decidim/impersonation.js +3 -3
  199. data/app/packs/src/decidim/input_character_counter.js +177 -7
  200. data/app/packs/src/decidim/input_multiple_mentions.js +87 -187
  201. data/app/packs/src/decidim/map/factory.js +3 -1
  202. data/app/packs/src/decidim/map/icon.js +2 -1
  203. data/app/packs/src/decidim/map/legacy.js +2 -2
  204. data/app/packs/src/decidim/map/svg-icon.js +248 -0
  205. data/app/packs/src/decidim/map.js +2 -2
  206. data/app/packs/src/decidim/security/selfxss_warning.js +5 -1
  207. data/app/packs/src/decidim/session_timeouter.js +15 -15
  208. data/app/packs/src/decidim/sw/a2hs.js +28 -0
  209. data/app/packs/src/decidim/sw/index.js +3 -0
  210. data/app/packs/src/decidim/sw/loader.js +18 -0
  211. data/app/packs/src/decidim/sw/push-permissions.js +87 -0
  212. data/app/packs/src/decidim/sw/sw.js +80 -0
  213. data/app/packs/src/decidim/vizzs/areachart.js +33 -28
  214. data/app/packs/src/decidim/vizzs/{metrics.js → index.js} +0 -0
  215. data/app/packs/src/decidim/vizzs/linechart.js +23 -18
  216. data/app/packs/src/decidim/vizzs/rowchart.js +15 -11
  217. data/app/packs/stylesheets/decidim/email.scss +66 -0
  218. data/app/packs/stylesheets/decidim/layouts/_user.scss +8 -0
  219. data/app/packs/stylesheets/decidim/modules/_autocomplete.scss +99 -0
  220. data/app/packs/stylesheets/decidim/modules/_cookie-consent.scss +115 -0
  221. data/app/packs/stylesheets/decidim/modules/_footer.scss +4 -0
  222. data/app/packs/stylesheets/decidim/modules/_input-multiple-mentions.scss +29 -2
  223. data/app/packs/stylesheets/decidim/modules/_modules.scss +3 -1
  224. data/app/packs/stylesheets/decidim/modules/_reveal.scss +15 -0
  225. data/app/packs/stylesheets/decidim/modules/_upload_modal.scss +143 -0
  226. data/app/packs/stylesheets/decidim/utils/_fontface.scss +3 -0
  227. data/app/permissions/decidim/permissions.rb +2 -4
  228. data/app/presenters/decidim/admin_log/area_type_presenter.rb +34 -0
  229. data/app/presenters/decidim/admin_log/attachment_collection_presenter.rb +35 -0
  230. data/app/presenters/decidim/admin_log/attachment_presenter.rb +27 -0
  231. data/app/presenters/decidim/admin_log/category_presenter.rb +36 -0
  232. data/app/presenters/decidim/admin_log/component_presenter.rb +35 -3
  233. data/app/presenters/decidim/admin_log/contextual_help_section_presenter.rb +33 -0
  234. data/app/presenters/decidim/admin_log/organization_presenter.rb +9 -4
  235. data/app/presenters/decidim/admin_log/scope_type_presenter.rb +34 -0
  236. data/app/presenters/decidim/home_stats_presenter.rb +4 -2
  237. data/app/presenters/decidim/log/base_presenter.rb +1 -1
  238. data/app/presenters/decidim/menu_item_presenter.rb +1 -1
  239. data/app/presenters/decidim/metric_charts_presenter.rb +7 -1
  240. data/app/presenters/decidim/nil_presenter.rb +3 -1
  241. data/app/presenters/decidim/notification_to_mailer_presenter.rb +39 -0
  242. data/app/presenters/decidim/notifications_digest_presenter.rb +42 -0
  243. data/app/presenters/decidim/official_author_presenter.rb +4 -0
  244. data/app/presenters/decidim/organization_presenter.rb +22 -0
  245. data/app/presenters/decidim/push_notification_presenter.rb +24 -0
  246. data/app/presenters/decidim/stats_presenter.rb +1 -1
  247. data/app/presenters/decidim/validation_errors_presenter.rb +1 -1
  248. data/app/queries/decidim/messaging/user_conversations.rb +1 -1
  249. data/app/queries/decidim/metric_manage.rb +1 -1
  250. data/app/queries/decidim/own_activities.rb +11 -0
  251. data/app/queries/decidim/participatory_processes_with_user_role.rb +1 -1
  252. data/app/{services/decidim/activity_search.rb → queries/decidim/public_activities.rb} +35 -77
  253. data/app/queries/decidim/public_components.rb +1 -1
  254. data/app/queries/decidim/similar_emendations.rb +1 -1
  255. data/app/queries/decidim/stats_users_count.rb +1 -1
  256. data/app/queries/decidim/user_groups/accepted_memberships.rb +1 -1
  257. data/app/queries/decidim/user_groups/accepted_user_groups.rb +1 -1
  258. data/app/queries/decidim/user_groups/accepted_users.rb +1 -1
  259. data/app/queries/decidim/user_groups/admin_memberships.rb +1 -1
  260. data/app/queries/decidim/user_groups/invited_memberships.rb +1 -1
  261. data/app/queries/decidim/user_groups/manageable_user_groups.rb +1 -1
  262. data/app/queries/decidim/user_groups/member_memberships.rb +1 -1
  263. data/app/services/decidim/{data_portability_exporter.rb → download_your_data_exporter.rb} +6 -6
  264. data/app/services/decidim/email_notification_generator.rb +2 -2
  265. data/app/services/decidim/engine_resolver.rb +66 -0
  266. data/app/services/decidim/events_manager.rb +1 -1
  267. data/app/services/decidim/iframe_disabler.rb +31 -0
  268. data/app/services/decidim/notification_generator_for_recipient.rb +1 -1
  269. data/app/services/decidim/notifications_digest_sending_decider.rb +18 -0
  270. data/app/services/decidim/notifications_subscriptions_persistor.rb +37 -0
  271. data/app/services/decidim/open_data_exporter.rb +1 -1
  272. data/app/services/decidim/resource_search.rb +17 -164
  273. data/app/services/decidim/send_push_notification.rb +59 -0
  274. data/app/services/decidim/traceability.rb +1 -1
  275. data/app/uploaders/decidim/application_uploader.rb +2 -12
  276. data/app/uploaders/decidim/cw/attachment_uploader.rb +1 -1
  277. data/app/uploaders/decidim/cw/{data_portability_uploader.rb → download_your_data_uploader.rb} +3 -3
  278. data/app/uploaders/decidim/cw/image_uploader.rb +2 -2
  279. data/app/uploaders/decidim/organization_favicon_uploader.rb +3 -2
  280. data/app/validators/passthru_validator.rb +29 -21
  281. data/app/validators/password_validator.rb +25 -4
  282. data/app/validators/uploader_image_dimensions_validator.rb +1 -1
  283. data/app/views/decidim/account/_account_notification.js.erb +20 -0
  284. data/app/views/decidim/account/_password_fields.html.erb +2 -2
  285. data/app/views/decidim/account/cancel_email_change.js.erb +6 -0
  286. data/app/views/decidim/account/resend_confirmation_instructions.erb +1 -0
  287. data/app/views/decidim/account/show.html.erb +19 -6
  288. data/app/views/decidim/application/{_attachments.html.erb → _attachments.erb} +2 -2
  289. data/app/views/decidim/application/_collection.html.erb +1 -1
  290. data/app/views/decidim/application/{_document.html.erb → _document.erb} +0 -0
  291. data/app/views/decidim/application/{_documents.html.erb → _documents.erb} +2 -2
  292. data/app/views/decidim/application/{_photos.html.erb → _photos.erb} +0 -0
  293. data/app/views/decidim/devise/confirmations/new.html.erb +1 -1
  294. data/app/views/decidim/devise/invitations/edit.html.erb +3 -4
  295. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +3 -3
  296. data/app/views/decidim/devise/passwords/edit.html.erb +7 -5
  297. data/app/views/decidim/devise/passwords/new.html.erb +1 -1
  298. data/app/views/decidim/devise/registrations/edit.html.erb +5 -5
  299. data/app/views/decidim/devise/registrations/new.html.erb +5 -5
  300. data/app/views/decidim/devise/sessions/new.html.erb +2 -2
  301. data/app/views/decidim/{data_portability → download_your_data}/export.html.erb +0 -0
  302. data/app/views/decidim/{data_portability → download_your_data}/show.html.erb +2 -2
  303. data/app/views/decidim/export_mailer/download_your_data_export.html.erb +7 -0
  304. data/app/views/decidim/last_activities/index.html.erb +1 -1
  305. data/app/views/decidim/manifests/show.json.erb +31 -0
  306. data/app/views/decidim/messaging/conversations/_add_conversation_users.html.erb +5 -3
  307. data/app/views/decidim/messaging/conversations/_reply.html.erb +1 -1
  308. data/app/views/decidim/messaging/conversations/_start.html.erb +1 -3
  309. data/app/views/decidim/messaging/conversations/create.js.erb +1 -0
  310. data/app/views/decidim/notifications_digest_mailer/_email_content.html.erb +11 -0
  311. data/app/views/decidim/notifications_digest_mailer/digest_mail.erb +27 -0
  312. data/app/views/decidim/notifications_settings/show.html.erb +34 -9
  313. data/app/views/decidim/offline/show.html.erb +9 -0
  314. data/app/views/decidim/pages/_standalone.html.erb +1 -1
  315. data/app/views/decidim/reported_mailer/hide.html.erb +1 -1
  316. data/app/views/decidim/reported_mailer/report.html.erb +1 -1
  317. data/app/views/decidim/scopes/picker.html.erb +1 -1
  318. data/app/views/decidim/searches/_filters.html.erb +2 -2
  319. data/app/views/decidim/shared/participatory_space_filters/_filters.html.erb +3 -3
  320. data/app/views/decidim/user_report_mailer/notify.html.erb +10 -3
  321. data/app/views/devise/mailer/confirmation_instructions.html.erb +3 -1
  322. data/app/views/layouts/decidim/_application.html.erb +6 -3
  323. data/app/views/layouts/decidim/_cookie_warning.html.erb +8 -8
  324. data/app/views/layouts/decidim/_decidim_javascript.html.erb +12 -0
  325. data/app/views/layouts/decidim/_head.html.erb +4 -2
  326. data/app/views/layouts/decidim/_js_configuration.html.erb +5 -1
  327. data/app/views/layouts/decidim/_main_footer.html.erb +1 -0
  328. data/app/views/layouts/decidim/_offline_banner.html.erb +11 -0
  329. data/app/views/layouts/decidim/widget.html.erb +2 -2
  330. data/config/assets.rb +1 -0
  331. data/config/locales/am-ET.yml +1 -0
  332. data/config/locales/ar.yml +48 -36
  333. data/config/locales/bg.yml +15 -30
  334. data/config/locales/ca.yml +186 -35
  335. data/config/locales/cs.yml +186 -33
  336. data/config/locales/da.yml +1 -0
  337. data/config/locales/de.yml +25 -36
  338. data/config/locales/el.yml +15 -30
  339. data/config/locales/en.yml +183 -32
  340. data/config/locales/eo.yml +4 -6
  341. data/config/locales/es-MX.yml +185 -34
  342. data/config/locales/es-PY.yml +185 -34
  343. data/config/locales/es.yml +185 -34
  344. data/config/locales/et.yml +1 -0
  345. data/config/locales/eu.yml +15 -36
  346. data/config/locales/fi-plain.yml +184 -33
  347. data/config/locales/fi.yml +184 -33
  348. data/config/locales/fr-CA.yml +170 -33
  349. data/config/locales/fr.yml +170 -33
  350. data/config/locales/ga-IE.yml +5 -7
  351. data/config/locales/gl.yml +47 -30
  352. data/config/locales/hr.yml +1 -0
  353. data/config/locales/hu.yml +65 -35
  354. data/config/locales/id-ID.yml +15 -29
  355. data/config/locales/is-IS.yml +6 -15
  356. data/config/locales/it.yml +22 -38
  357. data/config/locales/ja.yml +173 -34
  358. data/config/locales/ko.yml +1 -0
  359. data/config/locales/lb.yml +16 -32
  360. data/config/locales/lt.yml +1 -0
  361. data/config/locales/lv.yml +15 -28
  362. data/config/locales/mt.yml +1 -0
  363. data/config/locales/nl.yml +25 -33
  364. data/config/locales/no.yml +24 -35
  365. data/config/locales/om-ET.yml +1 -0
  366. data/config/locales/pl.yml +113 -32
  367. data/config/locales/pt-BR.yml +17 -32
  368. data/config/locales/pt.yml +16 -32
  369. data/config/locales/ro-RO.yml +20 -36
  370. data/config/locales/ru.yml +15 -27
  371. data/config/locales/si-LK.yml +1 -0
  372. data/config/locales/sk.yml +15 -30
  373. data/config/locales/sl.yml +1 -0
  374. data/config/locales/so-SO.yml +1 -0
  375. data/config/locales/sr-CS.yml +1 -0
  376. data/config/locales/sv.yml +69 -34
  377. data/config/locales/sw-KE.yml +1 -0
  378. data/config/locales/ti-ER.yml +1 -0
  379. data/config/locales/tr-TR.yml +15 -29
  380. data/config/locales/uk.yml +15 -26
  381. data/config/locales/val-ES.yml +1 -0
  382. data/config/locales/vi.yml +1 -0
  383. data/config/locales/zh-CN.yml +15 -28
  384. data/config/locales/zh-TW.yml +1 -0
  385. data/config/routes.rb +17 -2
  386. data/db/migrate/20180508111710_add_accepted_tos_version_field_to_users.rb +1 -0
  387. data/db/migrate/20181030090144_destroy_deleted_users_follows.rb +1 -0
  388. data/db/migrate/20190412131728_fix_user_names.rb +4 -4
  389. data/db/migrate/20210831181634_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
  390. data/db/migrate/20210831181635_create_active_storage_variant_records.active_storage.rb +14 -0
  391. data/db/migrate/20211208155453_create_decidim_reminders.rb +11 -0
  392. data/db/migrate/20211209121025_create_decidim_reminder_records.rb +11 -0
  393. data/db/migrate/20211209121040_create_decidim_reminder_deliveries.rb +10 -0
  394. data/db/migrate/20220118121921_change_required_description_categories.rb +7 -0
  395. data/db/migrate/20220127113419_add_notification_settings_to_users.rb +7 -0
  396. data/db/migrate/20220203121137_add_notifications_sending_frequency_to_users.rb +7 -0
  397. data/db/migrate/20220215172439_add_digest_sent_at_to_users.rb +7 -0
  398. data/db/migrate/20220323195258_add_index_to_decidim_users_notifications_sending_frequency.rb +7 -0
  399. data/db/migrate/20220427142214_drop_emails_on_notifications_flag_from_user.rb +15 -0
  400. data/db/migrate/20220518094535_add_previous_passwords_to_users.rb +20 -0
  401. data/db/migrate/20220524195530_create_decidim_short_links.rb +23 -0
  402. data/db/seeds.rb +17 -18
  403. data/lib/decidim/acts_as_tree.rb +47 -0
  404. data/lib/decidim/api/input_sorts/component_input_sort.rb +2 -1
  405. data/lib/decidim/api/interfaces/authorable_interface.rb +6 -5
  406. data/lib/decidim/asset_router.rb +80 -0
  407. data/lib/decidim/attachment_attributes.rb +8 -8
  408. data/lib/decidim/attribute_object/form.rb +174 -0
  409. data/lib/decidim/attribute_object/model.rb +148 -0
  410. data/lib/decidim/attribute_object/nested_validator.rb +22 -0
  411. data/lib/decidim/attribute_object/type_map.rb +14 -0
  412. data/lib/decidim/attribute_object/type_resolver.rb +91 -0
  413. data/lib/decidim/attribute_object.rb +26 -0
  414. data/lib/decidim/attributes/array.rb +62 -0
  415. data/lib/decidim/attributes/blob.rb +20 -0
  416. data/lib/decidim/attributes/clean_string.rb +12 -6
  417. data/lib/decidim/attributes/hash.rb +36 -0
  418. data/lib/decidim/attributes/integer.rb +17 -0
  419. data/lib/decidim/attributes/localized_date.rb +9 -7
  420. data/lib/decidim/attributes/model.rb +24 -0
  421. data/lib/decidim/attributes/object.rb +28 -0
  422. data/lib/decidim/attributes/symbol.rb +23 -0
  423. data/lib/decidim/attributes/time_with_zone.rb +9 -7
  424. data/lib/decidim/attributes.rb +29 -0
  425. data/lib/decidim/authorable.rb +21 -6
  426. data/lib/decidim/authorization_form_builder.rb +9 -11
  427. data/lib/decidim/carrier_wave_migrator_service.rb +15 -15
  428. data/lib/decidim/coauthorable.rb +22 -4
  429. data/lib/decidim/command.rb +44 -0
  430. data/lib/decidim/common_passwords.rb +1 -1
  431. data/lib/decidim/component_manifest.rb +5 -5
  432. data/lib/decidim/component_validator.rb +2 -2
  433. data/lib/decidim/content_block_manifest.rb +1 -1
  434. data/lib/decidim/content_parsers/hashtag_parser.rb +2 -2
  435. data/lib/decidim/content_parsers/resource_parser.rb +1 -1
  436. data/lib/decidim/content_parsers/user_group_parser.rb +1 -1
  437. data/lib/decidim/content_parsers/user_parser.rb +4 -4
  438. data/lib/decidim/content_renderers/hashtag_renderer.rb +1 -1
  439. data/lib/decidim/content_renderers/link_renderer.rb +2 -2
  440. data/lib/decidim/content_renderers/user_group_renderer.rb +1 -1
  441. data/lib/decidim/content_renderers/user_renderer.rb +1 -1
  442. data/lib/decidim/controller_helpers.rb +41 -0
  443. data/lib/decidim/core/engine.rb +29 -18
  444. data/lib/decidim/core/test/factories.rb +48 -8
  445. data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +16 -4
  446. data/lib/decidim/core/test/shared_examples/amendable/amendment_form_examples.rb +1 -1
  447. data/lib/decidim/core/test/shared_examples/authorable_interface_examples.rb +15 -2
  448. data/lib/decidim/core/test/shared_examples/coauthorable_interface_examples.rb +2 -2
  449. data/lib/decidim/core/test/shared_examples/comments_examples.rb +203 -0
  450. data/lib/decidim/core/test/shared_examples/localised_email.rb +1 -1
  451. data/lib/decidim/core/test/shared_examples/logo_email.rb +1 -1
  452. data/lib/decidim/core/test/shared_examples/map_examples.rb +2 -2
  453. data/lib/decidim/core/test/shared_examples/preview_component_with_share_token_examples.rb +0 -6
  454. data/lib/decidim/core/test/shared_examples/resource_search_examples.rb +120 -40
  455. data/lib/decidim/core/test/shared_examples/resourceable.rb +0 -6
  456. data/lib/decidim/core/test/shared_examples/searchable_participatory_space_examples.rb +1 -1
  457. data/lib/decidim/core/test/shared_examples/searchable_resources_shared_context.rb +1 -1
  458. data/lib/decidim/core/test/shared_examples/system_endorse_resource_examples.rb +3 -3
  459. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +2 -2
  460. data/lib/decidim/core/version.rb +1 -1
  461. data/lib/decidim/core.rb +108 -14
  462. data/lib/decidim/{data_portability.rb → download_your_data.rb} +3 -3
  463. data/lib/decidim/{data_portability_serializers/data_portability_conversation_serializer.rb → download_your_data_serializers/download_your_data_conversation_serializer.rb} +2 -2
  464. data/lib/decidim/{data_portability_serializers/data_portability_follow_serializer.rb → download_your_data_serializers/download_your_data_follow_serializer.rb} +2 -2
  465. data/lib/decidim/{data_portability_serializers/data_portability_identity_serializer.rb → download_your_data_serializers/download_your_data_identity_serializer.rb} +2 -2
  466. data/lib/decidim/{data_portability_serializers/data_portability_notification_serializer.rb → download_your_data_serializers/download_your_data_notification_serializer.rb} +2 -2
  467. data/lib/decidim/{data_portability_serializers/data_portability_participatory_space_private_user_serializer.rb → download_your_data_serializers/download_your_data_participatory_space_private_user_serializer.rb} +2 -2
  468. data/lib/decidim/{data_portability_serializers/data_portability_report_serializer.rb → download_your_data_serializers/download_your_data_report_serializer.rb} +2 -2
  469. data/lib/decidim/{data_portability_serializers/data_portability_user_group_serializer.rb → download_your_data_serializers/download_your_data_user_group_serializer.rb} +2 -2
  470. data/lib/decidim/{data_portability_serializers/data_portability_user_serializer.rb → download_your_data_serializers/download_your_data_user_serializer.rb} +3 -3
  471. data/lib/decidim/download_your_data_serializers.rb +23 -0
  472. data/lib/decidim/engine_router.rb +7 -1
  473. data/lib/decidim/env.rb +56 -0
  474. data/lib/decidim/event_recorder.rb +25 -0
  475. data/lib/decidim/events/base_event.rb +10 -14
  476. data/lib/decidim/events/simple_event.rb +12 -4
  477. data/lib/decidim/exporters/export_data.rb +1 -1
  478. data/lib/decidim/exporters/export_manifest.rb +2 -1
  479. data/lib/decidim/file_validator_humanizer.rb +24 -1
  480. data/lib/decidim/filterable_resource.rb +55 -0
  481. data/lib/decidim/fingerprint_calculator.rb +2 -4
  482. data/lib/decidim/form_builder.rb +158 -130
  483. data/lib/decidim/gamification/badge.rb +2 -3
  484. data/lib/decidim/gamification/badge_scorer.rb +1 -0
  485. data/lib/decidim/has_area.rb +27 -0
  486. data/lib/decidim/has_attachments.rb +2 -2
  487. data/lib/decidim/has_category.rb +36 -0
  488. data/lib/decidim/importers/import_manifest.rb +3 -21
  489. data/lib/decidim/jsonb_attributes.rb +6 -4
  490. data/lib/decidim/manifest_messages.rb +23 -0
  491. data/lib/decidim/map/autocomplete.rb +6 -4
  492. data/lib/decidim/map/frontend.rb +2 -2
  493. data/lib/decidim/map/provider/geocoding/here.rb +5 -5
  494. data/lib/decidim/map/provider/here.rb +3 -0
  495. data/lib/decidim/map/provider/osm.rb +3 -0
  496. data/lib/decidim/map.rb +4 -4
  497. data/lib/decidim/menu.rb +1 -1
  498. data/lib/decidim/metric_manifest.rb +2 -2
  499. data/lib/decidim/nicknamizable.rb +1 -1
  500. data/lib/decidim/notification_setting_manifest.rb +19 -0
  501. data/lib/decidim/organization_settings.rb +8 -7
  502. data/lib/decidim/participatory_space_context_manifest.rb +2 -2
  503. data/lib/decidim/participatory_space_manifest.rb +2 -2
  504. data/lib/decidim/processes_file_locally.rb +31 -0
  505. data/lib/decidim/query.rb +84 -0
  506. data/lib/decidim/record_encryptor.rb +29 -8
  507. data/lib/decidim/reminder_manifest.rb +75 -0
  508. data/lib/decidim/reminder_registry.rb +67 -0
  509. data/lib/decidim/resource_manifest.rb +1 -1
  510. data/lib/decidim/resourceable.rb +11 -0
  511. data/lib/decidim/scopable.rb +15 -0
  512. data/lib/decidim/settings_manifest.rb +4 -4
  513. data/lib/decidim/spring.rb +16 -0
  514. data/lib/decidim/translatable_attributes.rb +12 -8
  515. data/lib/decidim/url_option_resolver.rb +50 -0
  516. data/lib/decidim/view_hooks.rb +1 -1
  517. data/lib/decidim/view_model.rb +5 -1
  518. data/lib/decidim/webpacker/thread_safe_compiler.rb +30 -0
  519. data/lib/decidim/webpacker/webpack/custom.js +15 -3
  520. data/lib/decidim/webpacker/webpacker.yml +1 -1
  521. data/lib/decidim/webpacker.rb +2 -0
  522. data/lib/devise/models/decidim_validatable.rb +1 -1
  523. data/lib/tasks/decidim_active_storage_migration_tasks.rake +1 -3
  524. data/lib/tasks/{decidim_data_portability_tasks.rake → decidim_download_your_data_tasks.rake} +9 -9
  525. data/lib/tasks/decidim_mailers_tasks.rake +23 -0
  526. data/lib/tasks/decidim_metrics_tasks.rake +1 -1
  527. data/lib/tasks/decidim_pwa_tasks.rake +18 -0
  528. data/lib/tasks/decidim_reminders_tasks.rake +17 -0
  529. data/lib/tasks/decidim_tasks.rake +6 -1
  530. data/lib/tasks/decidim_webpacker_tasks.rake +1 -1
  531. data/lib/tasks/upgrade/decidim_fix_nickname_uniqueness.rake +51 -0
  532. metadata +184 -83
  533. data/app/controllers/decidim/cookie_policy_controller.rb +0 -24
  534. data/app/helpers/decidim/cookies_helper.rb +0 -11
  535. data/app/packs/src/decidim/vizzs/renders.js +0 -9
  536. data/app/packs/src/decidim/vizzs.js +0 -1
  537. data/app/packs/stylesheets/decidim/modules/_cookie-bar.scss +0 -26
  538. data/app/services/decidim/home_activity_search.rb +0 -80
  539. data/app/services/decidim/participatory_space_search.rb +0 -54
  540. data/app/views/decidim/cookie_policy/accept.js.erb +0 -3
  541. data/app/views/decidim/export_mailer/data_portability_export.html.erb +0 -7
  542. data/lib/decidim/data_portability_serializers.rb +0 -23
  543. data/lib/decidim/middleware/rails_cookies.rb +0 -23
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # A concern that adds extra search helpers for the models for Ransack
5
+ # searches.
6
+ module FilterableResource
7
+ extend ActiveSupport::Concern
8
+
9
+ class_methods do
10
+ def ransacker_i18n(field_name, attr_name = nil)
11
+ ransacker field_name do |parent|
12
+ Arel::Nodes::InfixOperation.new("->>", parent.table[attr_name || field_name], Arel::Nodes.build_quoted(I18n.locale.to_s))
13
+ end
14
+ end
15
+
16
+ def ransacker_i18n_multi(field_name, attrs)
17
+ raise "The second argument needs to be an array" unless attrs.is_a?(Array)
18
+ raise "You need to define at least one field in the second argument" if attrs.count < 1
19
+ return ransacker_i18n(field_name, attrs.first) if attrs.count < 2
20
+
21
+ # Create an i18n ransacker search for each of the provided attributes.
22
+ attrs.each { |attr_name| ransacker_i18n(attr_name) }
23
+
24
+ # Create the field name search alias for the attributes
25
+ ransacker_text_multi(field_name, attrs)
26
+ end
27
+
28
+ def ransacker_text_multi(field_name, attrs)
29
+ raise "The second argument needs to be an array" unless attrs.is_a?(Array)
30
+ raise "You need to define at least two fields in the second argument" if attrs.count < 1
31
+
32
+ # Alias the field_name as an OR query with all the provided fields.
33
+ ransack_alias field_name, attrs.join("_or_").to_sym
34
+ end
35
+
36
+ def scope_search_multi(scope_key, possible_scopes)
37
+ scope scope_key, lambda { |*value_keys|
38
+ search_values = value_keys.compact.compact_blank
39
+
40
+ conditions = possible_scopes.map do |scope|
41
+ search_values.member?(scope.to_s) ? try(scope) : nil
42
+ end.compact
43
+ return self unless conditions.any?
44
+
45
+ scoped_query = where(id: conditions.shift)
46
+ conditions.each do |condition|
47
+ scoped_query = scoped_query.or(where(id: condition))
48
+ end
49
+
50
+ scoped_query
51
+ }
52
+ end
53
+ end
54
+ end
55
+ end
@@ -33,10 +33,8 @@ module Decidim
33
33
  def sort_hash(hash)
34
34
  return hash unless hash.is_a?(Hash)
35
35
 
36
- Hash[
37
- hash.map { |key, value| [key, sort_hash(value)] }
38
- .sort_by { |key, _value| key }
39
- ]
36
+ hash.map { |key, value| [key, sort_hash(value)] }
37
+ .sort_by { |key, _value| key }.to_h
40
38
  end
41
39
  end
42
40
  end
@@ -67,7 +67,7 @@ module Decidim
67
67
  tabs_id = sanitize_tabs_selector(options[:tabs_id] || "#{object_name}-#{name}-tabs")
68
68
 
69
69
  label_tabs = content_tag(:div, class: "label--tabs") do
70
- field_label = label_i18n(name, options[:label] || label_for(name))
70
+ field_label = label_i18n(name, options[:label] || label_for(name), required: options[:required])
71
71
 
72
72
  language_selector = "".html_safe
73
73
  language_selector = create_language_selector(locales, tabs_id, name) if options[:label] != false
@@ -94,6 +94,13 @@ module Decidim
94
94
  safe_join [label_tabs, tabs_content]
95
95
  end
96
96
 
97
+ def password_field(attribute, options = {})
98
+ field attribute, options do |opts|
99
+ opts[:autocomplete] ||= :off
100
+ method(__method__).super_method.super_method.call(attribute, opts)
101
+ end
102
+ end
103
+
97
104
  def translated_one_locale(type, name, locale, options = {})
98
105
  return hashtaggable_text_field(type, name, locale, options) if options.delete(:hashtaggable)
99
106
 
@@ -135,7 +142,7 @@ module Decidim
135
142
  tabs_id = sanitize_tabs_selector(options[:tabs_id] || "#{object_name}-#{name}-tabs")
136
143
 
137
144
  label_tabs = content_tag(:div, class: "label--tabs") do
138
- field_label = label_i18n(name, options[:label] || label_for(name))
145
+ field_label = label_i18n(name, options[:label] || label_for(name), required: options[:required])
139
146
 
140
147
  tabs_panels = "".html_safe
141
148
  if options[:label] != false
@@ -393,97 +400,117 @@ module Decidim
393
400
  template.html_safe
394
401
  end
395
402
 
403
+ # Public: Generates a file upload field for Decidim::Attachment type of attachment.
404
+ # It is similar to upload method, but it changes some options so that attachment can
405
+ # have title and different upload validations.
406
+ #
407
+ # attribute - The String name of the attribute to build the field.
408
+ # options - A Hash with options to build the field. See upload method for
409
+ # more detailed information.
410
+ def attachment(attribute, options = {})
411
+ object_attachment = object.attachment.present?
412
+ record = object_attachment ? object.attachment : object
413
+ options = {
414
+ titled: true,
415
+ resource_class: "Decidim::Attachment",
416
+ show_current: false,
417
+ max_file_size: max_file_size(record, :file),
418
+ label: I18n.t("decidim.forms.upload.labels.add_attachment"),
419
+ button_edit_label: I18n.t("decidim.forms.upload.labels.edit_image"),
420
+ extension_allowlist: Decidim.organization_settings(Decidim::Attachment).upload_allowed_file_extensions
421
+ }.merge(options)
422
+
423
+ # Upload help uses extension allowlist from the options so we need to call this AFTER setting the defaults.
424
+ options[:help] = upload_help(record, attribute, options) if options[:help].blank?
425
+
426
+ upload(attribute, options)
427
+ end
428
+
396
429
  # Public: Generates a file upload field and sets the form as multipart.
397
430
  # If the file is an image it displays the default image if present or the current one.
398
- # By default it also generates a checkbox to delete the file. This checkbox can
399
- # be hidden if `options[:optional]` is passed as `false`.
431
+ # By default it also generates a button to replace the file.
400
432
  #
401
- # attribute - The String name of the attribute to buidl the field.
433
+ # attribute - The String name of the attribute to build the field.
402
434
  # options - A Hash with options to build the field.
435
+ # * max_file_size: Maximum size for the file (If you really want to change max
436
+ # file size you should probably change it in validator).
437
+ # * resouce_name: Name of the resource (e.g. user)
438
+ # * resource_class: Attribute's resource class (e.g. Decidim::User)
439
+ # * resouce_class: Class of the resource (e.g. user)
403
440
  # * optional: Whether the file can be optional or not.
404
- # rubocop:disable Metrics/CyclomaticComplexity
405
- # rubocop:disable Metrics/PerceivedComplexity
441
+ # * titled: Whether the file can have title or not.
442
+ # * show_current: Whether the current file is displayed next to the button.
443
+ # * help: Array of help messages which are displayed inside of the upload modal.
444
+ # * dimensions_info: Hash about resize dimensions (e.g. {:medium=>{:processor=>:resize_to_fit, :dimensions=>[600, 160]}})
445
+ # produces 'Resized to fit 600 x 160 px.'
446
+ # * extension_allowlist: Array of allowed file extensions (e.g. %w(jpeg jpg png))
447
+ # * label: Label for the attribute
448
+ # * button_label: Label for the button
449
+ # * button_edit_label: Button label when file is already selected.
406
450
  def upload(attribute, options = {})
407
451
  self.multipart = true
408
- options[:optional] = options[:optional].nil? ? true : options[:optional]
409
- label_text = options[:label] || label_for(attribute)
410
- alt_text = label_text
452
+ max_file_size = options[:max_file_size] || max_file_size(object, attribute)
453
+ button_label = options[:button_label] || choose_button_label(attribute)
454
+ help_messages = options[:help] || upload_help(object, attribute, options)
411
455
 
412
- file = object.send attribute
413
- template = ""
414
- template += label(attribute, label_text + required_for_attribute(attribute))
415
- template += upload_help(attribute, options)
416
- template += @template.file_field @object_name, attribute
456
+ options = {
457
+ attribute: attribute,
458
+ resource_name: @object_name,
459
+ resource_class: options[:resource_class]&.to_s || resource_class(attribute),
460
+ optional: true,
461
+ titled: false,
462
+ show_current: true,
463
+ max_file_size: max_file_size,
464
+ help: help_messages,
465
+ label: label_for(attribute),
466
+ button_label: button_label,
467
+ button_edit_label: I18n.t("decidim.forms.upload.labels.replace")
468
+ }.merge(options)
417
469
 
418
- template += extension_allowlist_help(options[:extension_allowlist]) if options[:extension_allowlist].present?
419
- template += image_dimensions_help(options[:dimensions_info]) if options[:dimensions_info].present?
470
+ ::Decidim::ViewModel.cell(
471
+ "decidim/upload_modal",
472
+ self,
473
+ options
474
+ ).call
475
+ end
420
476
 
421
- default_image_path = uploader_default_image_path(attribute)
422
- file_path = file_attachment_path(file)
477
+ def max_file_size(record, attribute)
478
+ Decidim::FileValidatorHumanizer.new(record, attribute).max_file_size
479
+ end
423
480
 
424
- if file_path.present? && file.attachment.image? || default_image_path.present?
425
- if file_path.present?
426
- template += @template.content_tag :label, I18n.t("current_image", scope: "decidim.forms")
427
- template += @template.link_to @template.image_tag(file_path, alt: alt_text), file_path, target: "_blank", rel: "noopener"
481
+ def choose_button_label(attribute)
482
+ @choose_button_label ||= begin
483
+ if resource_class(attribute).attached_config[attribute].uploader <= Decidim::ImageUploader
484
+ I18n.t("decidim.forms.upload.labels.add_image")
428
485
  else
429
- template += @template.content_tag :label, I18n.t("default_image", scope: "decidim.forms")
430
- template += @template.link_to @template.image_tag(default_image_path, alt: alt_text), default_image_path, target: "_blank", rel: "noopener"
431
- end
432
- elsif file_path.present?
433
- template += @template.label_tag I18n.t("current_file", scope: "decidim.forms")
434
- template += @template.link_to file.filename, file_path, target: "_blank", rel: "noopener"
435
- end
436
-
437
- if file_path.present? && options[:optional]
438
- template += content_tag :div, class: "field" do
439
- safe_join([
440
- @template.check_box(@object_name, "remove_#{attribute}"),
441
- label("remove_#{attribute}", I18n.t("remove_this_file", scope: "decidim.forms"))
442
- ])
486
+ I18n.t("decidim.forms.upload.labels.add_file")
443
487
  end
488
+ rescue NoMethodError
489
+ I18n.t("decidim.forms.upload.labels.add_file")
444
490
  end
445
-
446
- if object.errors[attribute].any?
447
- template += content_tag :p, class: "is-invalid-label" do
448
- safe_join object.errors[attribute], "<br/>".html_safe
449
- end
450
- end
451
-
452
- template.html_safe
453
491
  end
454
- # rubocop:enable Metrics/CyclomaticComplexity
455
- # rubocop:enable Metrics/PerceivedComplexity
456
-
457
- def upload_help(attribute, options = {})
458
- humanizer = FileValidatorHumanizer.new(object, attribute)
459
492
 
460
- help_scope = begin
461
- if options[:help_i18n_scope].present?
462
- options[:help_i18n_scope]
463
- elsif humanizer.uploader.is_a?(Decidim::ImageUploader)
464
- "decidim.forms.file_help.image"
465
- else
466
- "decidim.forms.file_help.file"
467
- end
468
- end
493
+ def upload_help(record, attribute, options = {})
494
+ humanizer = FileValidatorHumanizer.new(record, attribute)
469
495
 
470
- help_messages = begin
471
- if options[:help_i18n_messages].present?
472
- Array(options[:help_i18n_messages])
473
- else
474
- %w(message_1 message_2)
475
- end
476
- end
496
+ help_scope = if options[:help_i18n_scope].present?
497
+ options[:help_i18n_scope]
498
+ elsif humanizer.uploader.is_a?(Decidim::ImageUploader)
499
+ "decidim.forms.file_help.image"
500
+ else
501
+ "decidim.forms.file_help.file"
502
+ end
477
503
 
478
- content_tag(:div, class: "help-text") do
479
- inner = "<p>#{I18n.t("explanation", scope: help_scope)}</p>".html_safe
480
- inner + content_tag(:ul) do
481
- messages = help_messages.each.map { |msg| I18n.t(msg, scope: help_scope) }
482
- messages += humanizer.messages
504
+ help_messages = if options[:help_i18n_messages].present?
505
+ Array(options[:help_i18n_messages])
506
+ else
507
+ %w(message_1 message_2)
508
+ end
483
509
 
484
- messages.map { |msg| content_tag(:li, msg) }.join("\n").html_safe
485
- end.html_safe
486
- end
510
+ help_messages = help_messages.each.map { |msg| I18n.t(msg, scope: help_scope) } + humanizer.messages
511
+ help_messages += extension_allowlist_help(options[:extension_allowlist]) if options[:extension_allowlist]
512
+ help_messages += image_dimensions_help(options[:dimensions_info]) if options[:dimensions_info]
513
+ help_messages
487
514
  end
488
515
 
489
516
  # Public: Returns the translated name for the given attribute.
@@ -524,15 +551,15 @@ module Decidim
524
551
  # inputs inside the label and to automatically inject validations
525
552
  # from the object.
526
553
  #
527
- # attribute - The String name of the attribute to buidl the field.
554
+ # attribute - The String name of the attribute to build the field.
528
555
  # options - A Hash with options to build the field.
529
556
  # html_options - An optional Hash with options to pass to the html element.
530
557
  #
531
558
  # Returns a String
532
559
  def field(attribute, options, html_options = nil, &block)
533
560
  label = options.delete(:label)
534
- label_options = options.delete(:label_options)
535
- custom_label(attribute, label, label_options) do
561
+ label_options = options.delete(:label_options) || {}
562
+ custom_label(attribute, label, { required: options[:required] }.merge(label_options)) do
536
563
  field_with_validations(attribute, options, html_options, &block)
537
564
  end
538
565
  end
@@ -647,7 +674,7 @@ module Decidim
647
674
  def find_validator(attribute, klass)
648
675
  return unless object.respond_to?(:_validators)
649
676
 
650
- object._validators[attribute.to_sym].find { |validator| validator.class == klass }
677
+ object._validators[attribute.to_sym].find { |validator| validator.instance_of?(klass) }
651
678
  end
652
679
 
653
680
  # Private: Override method from FoundationRailsHelper to render the text of the
@@ -663,8 +690,16 @@ module Decidim
663
690
  def custom_label(attribute, text, options, field_before_label: false, show_required: true)
664
691
  return block_given? ? yield.html_safe : "".html_safe if text == false
665
692
 
693
+ required = options.is_a?(Hash) && options.delete(:required)
666
694
  text = default_label_text(object, attribute) if text.nil? || text == true
667
- text += required_for_attribute(attribute) if show_required
695
+ if show_required
696
+ text +=
697
+ if required
698
+ required_indicator
699
+ else
700
+ required_for_attribute(attribute)
701
+ end
702
+ end
668
703
 
669
704
  text = if field_before_label && block_given?
670
705
  safe_join([yield, text.html_safe])
@@ -746,45 +781,36 @@ module Decidim
746
781
  options[:class] ||= ""
747
782
  options[:class] += " is-invalid-label"
748
783
  end
749
- text += required_for_attribute(attribute)
784
+ text +=
785
+ if options.delete(:required)
786
+ required_indicator
787
+ else
788
+ required_for_attribute(attribute)
789
+ end
750
790
 
751
791
  label(attribute, (text || "").html_safe, options)
752
792
  end
753
793
 
754
- # Private: Returns default url for attribute when uploader is an
755
- # image and has defined a default url
756
- def uploader_default_image_path(attribute)
757
- uploader = FileValidatorHumanizer.new(object, attribute).uploader
758
- return if uploader.blank?
759
- return unless uploader.is_a?(Decidim::ImageUploader)
760
-
761
- uploader.try(:default_url)
762
- end
763
-
764
- # Private: Returns blob path when file is attached
765
- def file_attachment_path(file)
766
- return unless file && file.try(:attached?)
794
+ def required_for_attribute(attribute)
795
+ return required_indicator if attribute_required?(attribute)
767
796
 
768
- Rails.application.routes.url_helpers.rails_blob_url(file.blob, only_path: true)
797
+ "".html_safe
769
798
  end
770
799
 
771
- def required_for_attribute(attribute)
772
- if attribute_required?(attribute)
773
- visible_title = content_tag(:span, "*", "aria-hidden": true)
774
- screenreader_title = content_tag(
775
- :span,
776
- I18n.t("required", scope: "forms"),
777
- class: "show-for-sr"
778
- )
779
- return content_tag(
780
- :span,
781
- visible_title + screenreader_title,
782
- title: I18n.t("required", scope: "forms"),
783
- data: { tooltip: true, disable_hover: false, keep_on_hover: true },
784
- class: "label-required"
785
- ).html_safe
786
- end
787
- "".html_safe
800
+ def required_indicator
801
+ visible_title = content_tag(:span, "*", "aria-hidden": true)
802
+ screenreader_title = content_tag(
803
+ :span,
804
+ I18n.t("required", scope: "forms"),
805
+ class: "show-for-sr"
806
+ )
807
+ content_tag(
808
+ :span,
809
+ visible_title + screenreader_title,
810
+ title: I18n.t("required", scope: "forms"),
811
+ data: { tooltip: true, disable_hover: false, keep_on_hover: true },
812
+ class: "label-required"
813
+ ).html_safe
788
814
  end
789
815
 
790
816
  # Private: Returns an array of scopes related to object attribute
@@ -818,28 +844,17 @@ module Decidim
818
844
  end
819
845
 
820
846
  def extension_allowlist_help(extension_allowlist)
821
- content_tag :p, class: "extensions-help help-text" do
822
- safe_join([
823
- content_tag(:span, I18n.t("extension_allowlist", scope: "decidim.forms.files")),
824
- " ",
825
- safe_join(extension_allowlist.map { |ext| content_tag(:b, ext) }, ", ")
826
- ])
827
- end
847
+ ["#{I18n.t("extension_allowlist", scope: "decidim.forms.files")} #{extension_allowlist.map { |ext| ext }.join(", ")}"]
828
848
  end
829
849
 
830
850
  def image_dimensions_help(dimensions_info)
831
- content_tag :p, class: "image-dimensions-help help-text" do
832
- safe_join([
833
- content_tag(:span, I18n.t("dimensions_info", scope: "decidim.forms.images")),
834
- " ",
835
- content_tag(:span) do
836
- safe_join(dimensions_info.map do |_version, info|
837
- processor = @template.content_tag(:span, I18n.t("processors.#{info[:processor]}", scope: "decidim.forms.images"))
838
- dimensions = @template.content_tag(:b, I18n.t("dimensions", scope: "decidim.forms.images", width: info[:dimensions].first, height: info[:dimensions].last))
839
- safe_join([processor, " ", dimensions, ". ".html_safe])
840
- end)
841
- end
842
- ])
851
+ dimensions_info.map do |_version, info|
852
+ dimensions = I18n.t("dimensions", scope: "decidim.forms.images", width: info[:dimensions].first, height: info[:dimensions].last)
853
+ I18n.t(
854
+ "processors.#{info[:processor]}",
855
+ scope: "decidim.forms.images",
856
+ dimensions: dimensions
857
+ ).html_safe
843
858
  end
844
859
  end
845
860
 
@@ -911,5 +926,18 @@ module Decidim
911
926
  drag_and_drop_help_text: I18n.t("drag_and_drop_help", scope: "decidim.editor_images")
912
927
  }
913
928
  end
929
+
930
+ # Private: Determines the correct resource class for validators from the
931
+ # object or its PassthruValidator.
932
+ def resource_class(attribute)
933
+ if object._validators[attribute].is_a?(Array) && object._validators[attribute].size.positive?
934
+ passthru = object._validators[attribute].find { |v| v.is_a?(PassthruValidator) }
935
+ return passthru.options[:to] if passthru && passthru.options[:to].present?
936
+ end
937
+ klass = object.send(attribute)
938
+ return object.send(attribute).record.class if klass.respond_to?(:record) && klass.record.present?
939
+
940
+ object.class
941
+ end
914
942
  end
915
943
  end
@@ -5,7 +5,7 @@ module Decidim
5
5
  # This class represents an abstract badge. Instances of this class can define
6
6
  # different badge types with different rules such as gaining new levels, etc.
7
7
  class Badge
8
- include Virtus.model
8
+ include Decidim::AttributeObject::Model
9
9
  include ActiveModel::Validations
10
10
 
11
11
  # The name of the badge.
@@ -14,7 +14,7 @@ module Decidim
14
14
  # An array of scores needed to reach a new level. For example, the array
15
15
  # [1, 5, 10] represents 1 point to get to Level 1, 5 points to get to level 2,
16
16
  # 10 points to get to level 3.
17
- attribute :levels, Array, default: []
17
+ attribute :levels, Array[Integer], default: []
18
18
 
19
19
  # An array of types for which this badge is valid for.
20
20
  attribute :valid_for, Array[Symbol], default: [:user]
@@ -27,7 +27,6 @@ module Decidim
27
27
  attribute :reset, Proc
28
28
 
29
29
  validates :name, :levels, presence: true
30
- validates :levels, empty: false
31
30
 
32
31
  validate do
33
32
  errors.add(:levels, "level thresholds should be ordered") if levels.sort != levels
@@ -74,6 +74,7 @@ module Decidim
74
74
  private
75
75
 
76
76
  class NegativeScoreException < StandardError; end
77
+
77
78
  class InvalidAmountException < StandardError; end
78
79
 
79
80
  def with_level_tracking
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ # A concern with the components needed when you want a model to belong to an
7
+ # area.
8
+ module HasArea
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ belongs_to :area,
13
+ foreign_key: "decidim_area_id",
14
+ class_name: "Decidim::Area",
15
+ optional: true
16
+
17
+ scope :with_area, ->(area_id) { where(decidim_area_id: area_id) }
18
+
19
+ scope :with_any_area, lambda { |*original_area_ids|
20
+ area_ids = original_area_ids.map { |id| id.to_s.split("_") }.flatten.uniq
21
+ return self if area_ids.include?("all")
22
+
23
+ where(decidim_area_id: area_ids)
24
+ }
25
+ end
26
+ end
27
+ end
@@ -26,14 +26,14 @@ module Decidim
26
26
  #
27
27
  # Returns an Array<Attachment>
28
28
  def photos
29
- @photos ||= attachments.select(&:photo?)
29
+ @photos ||= attachments.with_attached_file.order(:weight).select(&:photo?)
30
30
  end
31
31
 
32
32
  # All the attachments that are documents for this model.
33
33
  #
34
34
  # Returns an Array<Attachment>
35
35
  def documents
36
- @documents ||= attachments.includes(:attachment_collection).select(&:document?)
36
+ @documents ||= attachments.with_attached_file.order(:weight).includes(:attachment_collection).select(&:document?)
37
37
  end
38
38
 
39
39
  # All the attachments that are documents for this model that has a collection.
@@ -11,6 +11,42 @@ module Decidim
11
11
  has_one :categorization, as: :categorizable
12
12
  has_one :category, through: :categorization
13
13
 
14
+ scope :with_category, lambda { |category|
15
+ return includes(:category).where(decidim_categories: { id: nil }) if category == "without" || category.nil?
16
+
17
+ includes(:category).where(decidim_categories: { id: category }).or(
18
+ includes(:category).where(decidim_categories: { parent_id: category })
19
+ )
20
+ }
21
+
22
+ scope :with_any_category, lambda { |*categories|
23
+ return self if categories.include?("all")
24
+
25
+ parent_ids = categories.without("without")
26
+ cat_ids = parent_ids.dup
27
+ cat_ids.prepend(nil) if categories.include?("without")
28
+
29
+ subquery = includes(:category).where(decidim_categories: { id: cat_ids })
30
+ return subquery if parent_ids.none?
31
+
32
+ subquery.or(
33
+ includes(:category).where(decidim_categories: { parent_id: parent_ids })
34
+ )
35
+ }
36
+
37
+ scope :with_any_global_category, lambda { |*categories|
38
+ return self if categories.include?("all")
39
+
40
+ cat_ids = categories.without("without")
41
+
42
+ additional_ids = cat_ids.grep(/Decidim__/)
43
+ additional_ids = additional_ids.map { |a| a.gsub("__", "::").gsub(/(\d+)/, '.\1').split(".") }
44
+ additional_ids = additional_ids.map { |v| v.first.safe_constantize.send(:find, v.last.to_i).category_ids }
45
+ additional_ids = additional_ids.flatten
46
+
47
+ with_any_category(*(categories + additional_ids))
48
+ }
49
+
14
50
  validate :category_belongs_to_organization
15
51
 
16
52
  def previous_category
@@ -6,7 +6,7 @@ module Decidim
6
6
  # specify it's own creator, which will be responsible for producing (creating)
7
7
  # and finishing (saving) the imported resource.
8
8
  class ImportManifest
9
- include Virtus.model
9
+ include Decidim::AttributeObject::Model
10
10
 
11
11
  attr_reader :name, :manifest
12
12
 
@@ -24,7 +24,7 @@ module Decidim
24
24
  super()
25
25
  @name = name.to_sym
26
26
  @manifest = manifest
27
- @messages = Messages.new
27
+ @messages = ImportManifestMessages.new
28
28
  end
29
29
 
30
30
  # Public: Sets the creator when an argument is provided, returns the
@@ -112,25 +112,7 @@ module Decidim
112
112
  @example.present?
113
113
  end
114
114
 
115
- class Messages
116
- def initialize
117
- @store = {}
118
- end
119
-
120
- def has?(key)
121
- @store.has_key?(key)
122
- end
123
-
124
- def set(key, &block)
125
- raise ArgumentError, "You need to provide a block for the message." unless block_given?
126
-
127
- @store[key] = block
128
- end
129
-
130
- def render(key, context = nil, **extra)
131
- context.instance_exec(**extra, &@store[key]) if @store[key]
132
- end
133
- end
115
+ class ImportManifestMessages < Decidim::ManifestMessages; end
134
116
  end
135
117
  end
136
118
  end
@@ -4,13 +4,13 @@ require "active_support/concern"
4
4
 
5
5
  module Decidim
6
6
  # A set of convenient methods to generate dynamic jsonb objects in a way is
7
- # compatilbe with Virtus and ActiveModel thus making it easy to integrate
8
- # into Rails forms and similar workflows.
7
+ # compatible with AttirubteObject and ActiveModel thus making it easy to
8
+ # integrate into Rails forms and similar workflows.
9
9
  module JsonbAttributes
10
10
  extend ActiveSupport::Concern
11
11
 
12
12
  class_methods do
13
- # Public: Mirrors Virtus `attribute` interface to define attributes in
13
+ # Public: Mirrors the `attribute` interface to define attributes in
14
14
  # custom jsonb objects.
15
15
  #
16
16
  # name - Attribute's name
@@ -25,7 +25,7 @@ module Decidim
25
25
  #
26
26
  # Returns nothing.
27
27
  def jsonb_attribute(name, fields, *options)
28
- attribute name, Hash, default: {}
28
+ attribute(name, { String => Object }, default: {})
29
29
 
30
30
  fields.each do |f, type|
31
31
  attribute f, type, *options
@@ -36,6 +36,8 @@ module Decidim
36
36
 
37
37
  define_method "#{f}=" do |value|
38
38
  field = public_send(name) || {}
39
+ value_type = self.class.attribute_types[f.to_s]
40
+ value = value_type.cast(value) if value_type
39
41
  public_send("#{name}=", field.merge(f => super(value)))
40
42
  end
41
43
  end