decidim-core 0.18.1 → 0.19.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 (275) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/decidim_core_manifest.js +3 -0
  3. data/app/assets/javascripts/decidim/social_share.js +2 -0
  4. data/app/assets/stylesheets/decidim/extras/_social_share.css.scss +36 -0
  5. data/app/assets/stylesheets/decidim/modules/_input-gallery.scss +24 -0
  6. data/app/assets/stylesheets/decidim/modules/_navbar.scss +1 -1
  7. data/app/cells/decidim/activities_cell.rb +13 -8
  8. data/app/cells/decidim/activity_cell.rb +19 -5
  9. data/app/cells/decidim/address/details.erb +2 -2
  10. data/app/cells/decidim/amendable/amenders_list/show.erb +1 -1
  11. data/app/cells/decidim/amendable/amenders_list_cell.rb +5 -1
  12. data/app/cells/decidim/amendable/announcement_cell.rb +22 -9
  13. data/app/cells/decidim/amendable/wizard_step_form_cell.rb +121 -0
  14. data/app/cells/decidim/announcement_cell.rb +1 -0
  15. data/app/cells/decidim/author_cell.rb +7 -0
  16. data/app/cells/decidim/card_m_cell.rb +3 -1
  17. data/app/cells/decidim/coauthorships_cell.rb +3 -1
  18. data/app/cells/decidim/collapsible_authors_cell.rb +1 -0
  19. data/app/cells/decidim/collapsible_list_cell.rb +1 -0
  20. data/app/cells/decidim/content_blocks/highlighted_content_banner_cell.rb +1 -0
  21. data/app/cells/decidim/content_blocks/last_activity_cell.rb +3 -2
  22. data/app/cells/decidim/content_blocks/metrics_cell.rb +1 -0
  23. data/app/cells/decidim/content_blocks/stats_cell.rb +1 -0
  24. data/app/cells/decidim/content_blocks/sub_hero_cell.rb +1 -0
  25. data/app/cells/decidim/diff_cell.rb +1 -1
  26. data/app/cells/decidim/fingerprint/show.erb +1 -1
  27. data/app/cells/decidim/follow_button_cell.rb +3 -0
  28. data/app/cells/decidim/members_cell.rb +1 -0
  29. data/app/cells/decidim/notifications/show.erb +1 -1
  30. data/app/cells/decidim/profile_cell.rb +1 -0
  31. data/app/cells/decidim/profile_sidebar_cell.rb +4 -0
  32. data/app/cells/decidim/search_results_cell.rb +1 -0
  33. data/app/cells/decidim/search_results_section/show.erb +1 -1
  34. data/app/cells/decidim/tos_page_cell.rb +1 -0
  35. data/app/cells/decidim/user_group_pending_invitations_list_cell.rb +1 -0
  36. data/app/cells/decidim/user_group_pending_requests_list_cell.rb +1 -0
  37. data/app/cells/decidim/wizard_step_form/wizard_aside.erb +14 -0
  38. data/app/cells/decidim/wizard_step_form/wizard_header.erb +18 -0
  39. data/app/cells/decidim/wizard_step_form_cell.rb +112 -0
  40. data/app/commands/decidim/amendable/accept.rb +1 -1
  41. data/app/commands/decidim/amendable/create_draft.rb +70 -0
  42. data/app/commands/decidim/amendable/destroy_draft.rb +40 -0
  43. data/app/commands/decidim/amendable/promote.rb +13 -11
  44. data/app/commands/decidim/amendable/publish_draft.rb +76 -0
  45. data/app/commands/decidim/amendable/update_draft.rb +54 -0
  46. data/app/commands/decidim/amendable/withdraw.rb +31 -15
  47. data/app/commands/decidim/create_follow.rb +1 -0
  48. data/app/commands/decidim/create_omniauth_registration.rb +22 -4
  49. data/app/commands/decidim/create_registration.rb +5 -0
  50. data/app/commands/decidim/delete_follow.rb +1 -0
  51. data/app/commands/decidim/search.rb +1 -0
  52. data/app/controllers/concerns/decidim/action_authorization.rb +2 -0
  53. data/app/controllers/concerns/decidim/amendments_controller.rb +148 -28
  54. data/app/controllers/concerns/decidim/devise_controllers.rb +3 -2
  55. data/app/controllers/concerns/decidim/force_authentication.rb +38 -0
  56. data/app/controllers/concerns/decidim/impersonate_users.rb +1 -0
  57. data/app/controllers/concerns/decidim/locale_switcher.rb +44 -17
  58. data/app/controllers/concerns/decidim/needs_tos_accepted.rb +8 -0
  59. data/app/controllers/concerns/decidim/orderable.rb +36 -0
  60. data/app/controllers/concerns/decidim/participatory_space_context.rb +2 -0
  61. data/app/controllers/concerns/decidim/safe_redirect.rb +24 -0
  62. data/app/controllers/decidim/application_controller.rb +19 -2
  63. data/app/controllers/decidim/devise/confirmations_controller.rb +6 -0
  64. data/app/controllers/decidim/devise/invitations_controller.rb +8 -4
  65. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +4 -1
  66. data/app/controllers/decidim/errors_controller.rb +3 -0
  67. data/app/controllers/decidim/follows_controller.rb +2 -2
  68. data/app/controllers/decidim/messaging/conversations_controller.rb +2 -2
  69. data/app/controllers/decidim/profiles_controller.rb +4 -1
  70. data/app/controllers/decidim/scopes_controller.rb +16 -4
  71. data/app/events/decidim/amendable/amendment_base_event.rb +4 -0
  72. data/app/forms/decidim/account_form.rb +1 -1
  73. data/app/forms/decidim/amendable/create_form.rb +3 -19
  74. data/app/forms/decidim/amendable/edit_form.rb +22 -0
  75. data/app/forms/decidim/amendable/form.rb +42 -20
  76. data/app/forms/decidim/amendable/promote_form.rb +4 -7
  77. data/app/forms/decidim/amendable/publish_form.rb +21 -0
  78. data/app/forms/decidim/amendable/reject_form.rb +1 -1
  79. data/app/forms/decidim/amendable/review_form.rb +9 -4
  80. data/app/forms/decidim/invite_user_form.rb +1 -0
  81. data/app/forms/decidim/notifications_settings_form.rb +1 -0
  82. data/app/forms/decidim/registration_form.rb +4 -3
  83. data/app/forms/decidim/user_group_form.rb +1 -0
  84. data/app/forms/decidim/user_interests_form.rb +1 -0
  85. data/app/helpers/decidim/amendments_helper.rb +33 -19
  86. data/app/helpers/decidim/cells_helper.rb +2 -0
  87. data/app/helpers/decidim/layout_helper.rb +1 -0
  88. data/app/helpers/decidim/map_helper.rb +1 -1
  89. data/app/helpers/decidim/meta_tags_helper.rb +1 -0
  90. data/app/helpers/decidim/resource_reference_helper.rb +1 -0
  91. data/app/jobs/decidim/event_publisher_job.rb +60 -0
  92. data/app/jobs/decidim/metric_job.rb +1 -0
  93. data/app/models/decidim/action_log.rb +12 -0
  94. data/app/models/decidim/amendment.rb +31 -2
  95. data/app/models/decidim/attachment.rb +2 -0
  96. data/app/models/decidim/authorization.rb +1 -0
  97. data/app/models/decidim/category.rb +1 -0
  98. data/app/models/decidim/component.rb +7 -0
  99. data/app/models/decidim/content_block.rb +1 -0
  100. data/app/models/decidim/follow.rb +3 -0
  101. data/app/models/decidim/identity.rb +1 -0
  102. data/app/models/decidim/impersonation_log.rb +2 -0
  103. data/app/models/decidim/newsletter.rb +1 -0
  104. data/app/models/decidim/participatory_process_user_role.rb +1 -0
  105. data/app/models/decidim/participatory_space_private_user.rb +1 -0
  106. data/app/models/decidim/permission_action.rb +2 -0
  107. data/app/models/decidim/report.rb +1 -0
  108. data/app/models/decidim/scope.rb +1 -0
  109. data/app/models/decidim/searchable_resource.rb +1 -1
  110. data/app/models/decidim/static_page.rb +1 -0
  111. data/app/models/decidim/user.rb +2 -0
  112. data/app/permissions/decidim/permissions.rb +18 -14
  113. data/app/permissions/decidim/user_manager_permissions.rb +9 -2
  114. data/app/presenters/decidim/admin_log/organization_presenter.rb +1 -0
  115. data/app/presenters/decidim/admin_log/participatory_space_private_user_presenter.rb +1 -1
  116. data/app/presenters/decidim/admin_log/user_presenter.rb +1 -1
  117. data/app/presenters/decidim/hashtag_presenter.rb +1 -1
  118. data/app/presenters/decidim/log/base_presenter.rb +1 -0
  119. data/app/presenters/decidim/log/diff_presenter.rb +1 -1
  120. data/app/presenters/decidim/log/value_types/area_presenter.rb +1 -0
  121. data/app/presenters/decidim/log/value_types/area_type_presenter.rb +1 -0
  122. data/app/presenters/decidim/log/value_types/currency_presenter.rb +1 -0
  123. data/app/presenters/decidim/log/value_types/date_presenter.rb +1 -0
  124. data/app/presenters/decidim/log/value_types/locale_presenter.rb +1 -0
  125. data/app/presenters/decidim/log/value_types/percentage_presenter.rb +1 -0
  126. data/app/presenters/decidim/log/value_types/scope_presenter.rb +1 -0
  127. data/app/presenters/decidim/log/value_types/scope_type_presenter.rb +1 -0
  128. data/app/presenters/decidim/metric_charts_presenter.rb +1 -0
  129. data/app/presenters/decidim/metric_object_presenter.rb +4 -0
  130. data/app/queries/decidim/metric_manage.rb +3 -0
  131. data/app/queries/decidim/metric_measure.rb +1 -0
  132. data/app/queries/decidim/metrics/followers_metric_manage.rb +3 -0
  133. data/app/queries/decidim/metrics/participants_metric_manage.rb +4 -0
  134. data/app/queries/decidim/similar_emendations.rb +56 -0
  135. data/app/resolvers/decidim/core/metric_resolver.rb +1 -0
  136. data/app/services/decidim/action_authorizer.rb +1 -0
  137. data/app/services/decidim/action_logger.rb +1 -0
  138. data/app/services/decidim/activity_search.rb +1 -0
  139. data/app/services/decidim/email_notification_generator.rb +4 -0
  140. data/app/services/decidim/notification_generator.rb +2 -0
  141. data/app/services/decidim/notification_generator_for_recipient.rb +0 -1
  142. data/app/services/decidim/resource_search.rb +1 -1
  143. data/app/services/decidim/traceability.rb +1 -0
  144. data/app/uploaders/decidim/application_uploader.rb +1 -0
  145. data/app/uploaders/decidim/attachment_uploader.rb +16 -0
  146. data/app/uploaders/decidim/avatar_uploader.rb +0 -2
  147. data/app/uploaders/decidim/data_portability_uploader.rb +1 -0
  148. data/app/uploaders/decidim/homepage_image_uploader.rb +0 -2
  149. data/app/uploaders/decidim/image_uploader.rb +15 -1
  150. data/app/uploaders/decidim/oauth_application_logo_uploader.rb +0 -1
  151. data/app/uploaders/decidim/official_image_footer_uploader.rb +0 -1
  152. data/app/uploaders/decidim/official_image_header_uploader.rb +0 -1
  153. data/app/uploaders/decidim/open_data_uploader.rb +1 -0
  154. data/app/validators/etiquette_validator.rb +5 -0
  155. data/app/views/decidim/account/delete.html.erb +2 -2
  156. data/app/views/decidim/account/show.html.erb +1 -1
  157. data/app/views/decidim/amendments/_edit_form_fields.html.erb +16 -13
  158. data/app/views/decidim/amendments/_similar_emendation.html.erb +24 -0
  159. data/app/views/decidim/amendments/compare_draft.html.erb +21 -0
  160. data/app/views/decidim/amendments/edit_draft.html.erb +31 -0
  161. data/app/views/decidim/amendments/new.html.erb +5 -17
  162. data/app/views/decidim/amendments/preview_draft.html.erb +32 -0
  163. data/app/views/decidim/amendments/review.html.erb +5 -3
  164. data/app/views/decidim/application/_document.html.erb +1 -1
  165. data/app/views/decidim/application/_photos.html.erb +1 -1
  166. data/app/views/decidim/data_portability/show.html.erb +1 -1
  167. data/app/views/decidim/devise/invitations/edit.html.erb +2 -2
  168. data/app/views/decidim/devise/sessions/new.html.erb +1 -1
  169. data/app/views/decidim/doorkeeper/authorizations/new.html.erb +3 -3
  170. data/app/views/decidim/export_mailer/data_portability_export.html.erb +1 -1
  171. data/app/views/decidim/searches/index.js.erb +6 -0
  172. data/app/views/decidim/shared/_address_details.html.erb +2 -2
  173. data/app/views/decidim/shared/_embed_modal.html.erb +1 -1
  174. data/app/views/decidim/shared/_share_modal.html.erb +7 -4
  175. data/app/views/layouts/decidim/_application.html.erb +0 -1
  176. data/app/views/layouts/decidim/_head.html.erb +13 -12
  177. data/app/views/layouts/decidim/_logo.html.erb +1 -1
  178. data/app/views/layouts/decidim/_social_media_links.html.erb +5 -5
  179. data/app/views/layouts/decidim/_user_menu.html.erb +1 -1
  180. data/app/views/layouts/decidim/_wrapper.html.erb +2 -2
  181. data/app/views/layouts/decidim/mailer.html.erb +2 -2
  182. data/config/locales/ar.yml +27 -17
  183. data/config/locales/ca.yml +79 -15
  184. data/config/locales/cs.yml +73 -14
  185. data/config/locales/de.yml +62 -12
  186. data/config/locales/en.yml +80 -16
  187. data/config/locales/eo-UY.yml +16 -0
  188. data/config/locales/es-MX.yml +73 -11
  189. data/config/locales/es-PY.yml +73 -11
  190. data/config/locales/es.yml +79 -15
  191. data/config/locales/eu.yml +6 -13
  192. data/config/locales/fi-plain.yml +75 -11
  193. data/config/locales/fi.yml +80 -16
  194. data/config/locales/fr.yml +70 -16
  195. data/config/locales/gl.yml +6 -13
  196. data/config/locales/hu.yml +80 -17
  197. data/config/locales/id-ID.yml +6 -12
  198. data/config/locales/it.yml +56 -14
  199. data/config/locales/nl.yml +76 -12
  200. data/config/locales/no.yml +11 -2
  201. data/config/locales/pl.yml +6 -15
  202. data/config/locales/pt-BR.yml +6 -13
  203. data/config/locales/pt.yml +6 -13
  204. data/config/locales/ru.yml +7 -2
  205. data/config/locales/sv.yml +34 -18
  206. data/config/locales/tr-TR.yml +15 -12
  207. data/config/locales/uk.yml +7 -2
  208. data/config/routes.rb +7 -0
  209. data/db/migrate/20180226140756_add_version_to_action_logs.rb +1 -0
  210. data/db/migrate/20180305132906_rename_features_to_components.rb +1 -0
  211. data/db/migrate/20190412131728_fix_user_names.rb +1 -1
  212. data/db/migrate/20190610093742_add_force_users_to_authenticate_before_access_organization.rb +10 -0
  213. data/db/migrate/20190618075906_add_confidential_to_doorkeeper_application.rb +13 -0
  214. data/db/migrate/{20190925091507_add_uniq_index_to_decidim_metrics.rb → 20190829092826_add_uniq_index_to_decidim_metrics.rb} +0 -0
  215. data/lib/decidim/amendable.rb +87 -13
  216. data/lib/decidim/attributes/localized_date.rb +5 -0
  217. data/lib/decidim/attributes/time_with_zone.rb +5 -0
  218. data/lib/decidim/authorable.rb +3 -0
  219. data/lib/decidim/authorization_form_builder.rb +2 -2
  220. data/lib/decidim/component_manifest.rb +2 -0
  221. data/lib/decidim/content_parsers.rb +2 -0
  222. data/lib/decidim/content_parsers/hashtag_parser.rb +1 -1
  223. data/lib/decidim/content_parsers/link_parser.rb +10 -0
  224. data/lib/decidim/content_parsers/newline_parser.rb +20 -0
  225. data/lib/decidim/content_parsers/user_parser.rb +1 -1
  226. data/lib/decidim/content_processor.rb +2 -0
  227. data/lib/decidim/content_renderers.rb +1 -0
  228. data/lib/decidim/content_renderers/hashtag_renderer.rb +1 -1
  229. data/lib/decidim/content_renderers/link_renderer.rb +24 -0
  230. data/lib/decidim/content_renderers/user_renderer.rb +2 -2
  231. data/lib/decidim/core.rb +11 -0
  232. data/lib/decidim/core/engine.rb +2 -28
  233. data/lib/decidim/core/test.rb +4 -1
  234. data/lib/decidim/core/test/factories.rb +35 -8
  235. data/lib/decidim/core/test/shared_examples/amendable/create_amendment_draft_examples.rb +50 -0
  236. data/lib/decidim/core/test/shared_examples/amendable/destroy_amendment_draft_examples.rb +39 -0
  237. data/lib/decidim/core/test/shared_examples/amendable/promote_amendment_examples.rb +27 -3
  238. data/lib/decidim/core/test/shared_examples/amendable/{create_amendment_examples.rb → publish_amendment_draft_examples.rb} +26 -17
  239. data/lib/decidim/core/test/shared_examples/amendable/update_amendment_draft_examples.rb +42 -0
  240. data/lib/decidim/core/test/shared_examples/amendable/withdraw_amendment_examples.rb +19 -11
  241. data/lib/decidim/core/test/shared_examples/has_attachment_collections.rb +1 -1
  242. data/lib/decidim/core/test/shared_examples/has_attachments.rb +1 -1
  243. data/lib/decidim/core/test/shared_examples/simple_event.rb +4 -0
  244. data/lib/decidim/core/version.rb +1 -1
  245. data/lib/decidim/data_portability_file_zipper.rb +3 -0
  246. data/lib/decidim/events/author_event.rb +1 -0
  247. data/lib/decidim/events/base_event.rb +12 -22
  248. data/lib/decidim/events/coauthor_event.rb +1 -0
  249. data/lib/decidim/events/simple_event.rb +3 -0
  250. data/lib/decidim/exporters/csv.rb +1 -0
  251. data/lib/decidim/fingerprintable.rb +1 -0
  252. data/lib/decidim/followable.rb +8 -0
  253. data/lib/decidim/form_builder.rb +24 -3
  254. data/lib/decidim/gamification.rb +4 -0
  255. data/lib/decidim/gamification/badge_status.rb +1 -0
  256. data/lib/decidim/has_category.rb +2 -0
  257. data/lib/decidim/has_component.rb +2 -7
  258. data/lib/decidim/has_private_users.rb +8 -1
  259. data/lib/decidim/has_settings.rb +12 -8
  260. data/lib/decidim/hashtaggable.rb +4 -0
  261. data/lib/decidim/metric_operation_manifest.rb +1 -0
  262. data/lib/decidim/nicknamizable.rb +1 -0
  263. data/lib/decidim/participable.rb +1 -0
  264. data/lib/decidim/participatory_space_resourceable.rb +1 -0
  265. data/lib/decidim/randomable.rb +20 -0
  266. data/lib/decidim/search_resource_fields_mapper.rb +2 -0
  267. data/lib/decidim/searchable.rb +2 -0
  268. data/lib/decidim/settings_manifest.rb +10 -1
  269. data/lib/decidim/stats_registry.rb +1 -0
  270. data/lib/decidim/view_model.rb +1 -1
  271. data/lib/tasks/decidim_data_portability_tasks.rake +1 -0
  272. data/lib/tasks/decidim_metrics_tasks.rake +2 -0
  273. data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.no.js +12 -12
  274. metadata +140 -82
  275. data/app/commands/decidim/amendable/create.rb +0 -80
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Amendable
5
+ # A command with all the business logic when a user starts amending a resource.
6
+ class DestroyDraft < Rectify::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # amendment - The amendment to destroy.
10
+ # current_user - The current user.
11
+ def initialize(amendment, current_user)
12
+ @amendment = amendment
13
+ @amendable = amendment.amendable
14
+ @emendation = amendment.emendation
15
+ @amender = amendment.amender
16
+ @current_user = current_user
17
+ end
18
+
19
+ # Executes the command. Broadcasts these events:
20
+ #
21
+ # - :ok when everything is valid, together with the amendable.
22
+ # - :invalid if the amendment is not a draft.
23
+ # - :invalid if the amender is not the current user.
24
+ #
25
+ # Returns nothing.
26
+ def call
27
+ return broadcast(:invalid) unless amendment.draft? && amender == current_user
28
+
29
+ emendation.destroy!
30
+ amendment.delete
31
+
32
+ broadcast(:ok, amendable)
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :amendment, :amendable, :emendation, :amender, :current_user
38
+ end
39
+ end
40
+ end
@@ -10,8 +10,11 @@ module Decidim
10
10
  # amendable - The amendable resource.
11
11
  def initialize(form)
12
12
  @form = form
13
+ @amendment = form.amendment
13
14
  @emendation = form.emendation
14
15
  @amendable = form.amendable
16
+ @amender = form.amender
17
+ @current_user = form.current_user
15
18
  end
16
19
 
17
20
  # Executes the command. Broadcasts these events:
@@ -21,11 +24,12 @@ module Decidim
21
24
  #
22
25
  # Returns nothing.
23
26
  def call
24
- return broadcast(:invalid) if form.invalid?
27
+ return broadcast(:invalid) unless form.valid? && amendment.rejected? && amender == current_user
25
28
 
26
29
  transaction do
27
30
  promote_emendation!
28
31
  notify_amendable_and_emendation_authors_and_followers
32
+ link_promoted_emendation_and_proposal
29
33
  end
30
34
 
31
35
  broadcast(:ok, @promoted_emendation)
@@ -33,23 +37,21 @@ module Decidim
33
37
 
34
38
  private
35
39
 
36
- attr_reader :form
40
+ attr_reader :form, :amendment, :amender, :current_user
37
41
 
38
- # The log of this action contains unique information
39
- # that is used to show/hide the promote button
40
- #
41
- # extra_log_info = { promoted_form: emendation.id }
42
+ # The log of this action contains unique information:
43
+ # extra_log_info = { promoted_from: emendation.id }
42
44
  def promote_emendation!
43
45
  @promoted_emendation = Decidim.traceability.perform_action!(
44
46
  "promote",
45
- @emendation.amendable_type.constantize,
47
+ @emendation.class,
46
48
  @emendation.creator_author,
47
49
  visibility: "public-only",
48
50
  promoted_from: @emendation.id
49
51
  ) do
50
- promoted_emendation = @emendation.amendable_type.constantize.new(form.emendation_params)
52
+ promoted_emendation = @emendation.class.new(form.emendation_params)
51
53
  promoted_emendation.component = @emendation.component
52
- promoted_emendation.published_at = Time.current if proposal?
54
+ promoted_emendation&.published_at = Time.current
53
55
  promoted_emendation.add_coauthor(@emendation.creator_author)
54
56
  promoted_emendation.save!
55
57
  promoted_emendation
@@ -69,8 +71,8 @@ module Decidim
69
71
  )
70
72
  end
71
73
 
72
- def proposal?
73
- @amendable.amendable_type == "Decidim::Proposals::Proposal"
74
+ def link_promoted_emendation_and_proposal
75
+ @promoted_emendation.link_resources(@emendation, "created_from_rejected_emendation")
74
76
  end
75
77
  end
76
78
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Amendable
5
+ # A command with all the business logic when a user publishes an amendment draft.
6
+ class PublishDraft < Rectify::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # form - A form object with the params.
10
+ def initialize(form)
11
+ @form = form
12
+ @amendment = form.amendment
13
+ @amendable = form.amendable
14
+ @emendation = form.emendation
15
+ @amender = form.amender
16
+ @current_user = form.current_user
17
+ end
18
+
19
+ # Executes the command. Broadcasts these events:
20
+ #
21
+ # - :ok when everything is valid, together with the amend.
22
+ # - :invalid if the amendment is not a draft.
23
+ # - :invalid if the form isn't valid or the amender is not the current user.
24
+ #
25
+ # Returns nothing.
26
+ def call
27
+ return broadcast(:invalid) unless form.valid? && amendment.draft? && amender == current_user
28
+
29
+ transaction do
30
+ set_first_emendation_version
31
+ publish_emendation
32
+ change_amendment_state_to_evaluating
33
+ notify_amendable_authors_and_followers
34
+ end
35
+
36
+ broadcast(:ok, emendation)
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :form, :amendment, :amendable, :emendation, :amender, :current_user
42
+
43
+ # To be able to diff amendments we store the original attributes being amended
44
+ # in the first PaperTrail::Version.
45
+ def set_first_emendation_version
46
+ emendation.update(form.amendable_params)
47
+ end
48
+
49
+ # This will be the PaperTrail version that gets compared to the amended proposal.
50
+ def publish_emendation
51
+ Decidim.traceability.perform_action!(
52
+ "publish",
53
+ emendation,
54
+ current_user,
55
+ visibility: "public-only"
56
+ ) do
57
+ emendation.update(form.emendation_params.merge(published_at: Time.current))
58
+ end
59
+ end
60
+
61
+ def change_amendment_state_to_evaluating
62
+ emendation.amendment.update(state: "evaluating")
63
+ end
64
+
65
+ def notify_amendable_authors_and_followers
66
+ Decidim::EventsManager.publish(
67
+ event: "decidim.events.amendments.amendment_created",
68
+ event_class: Decidim::Amendable::AmendmentCreatedEvent,
69
+ resource: amendable,
70
+ affected_users: amendable.notifiable_identities,
71
+ followers: amendable.followers - amendable.notifiable_identities
72
+ )
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Amendable
5
+ # A command with all the business logic when a user updates and amendment draft.
6
+ class UpdateDraft < Rectify::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # form - A form object with the params.
10
+ def initialize(form)
11
+ @form = form
12
+ @amendment = form.amendment
13
+ @amender = form.amender
14
+ @emendation = form.emendation
15
+ @current_user = form.current_user
16
+ @user_group = Decidim::UserGroup.find_by(id: form.user_group_id)
17
+ end
18
+
19
+ # Executes the command. Broadcasts these events:
20
+ #
21
+ # - :ok when everything is valid, together with the amend.
22
+ # - :invalid if the amendment is not a draft.
23
+ # - :invalid if the form isn't valid or the amender is not the current user.
24
+ #
25
+ # Returns nothing.
26
+ def call
27
+ return broadcast(:invalid) unless form.valid? && amendment.draft? && amender == current_user
28
+
29
+ transaction do
30
+ update_draft
31
+ end
32
+
33
+ broadcast(:ok, @amendment)
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :form, :amendment, :amender, :emendation, :current_user, :user_group
39
+
40
+ # Prevent PaperTrail from creating an additional version
41
+ # in the amendment multi-step creation process (step 3: complete)
42
+ #
43
+ # A first version will be created in step 4: publish
44
+ # for diff rendering in the amendment control version
45
+ def update_draft
46
+ PaperTrail.request(enabled: false) do
47
+ emendation.assign_attributes(form.emendation_params)
48
+ emendation.add_author(current_user, user_group)
49
+ emendation.save!
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -2,15 +2,17 @@
2
2
 
3
3
  module Decidim
4
4
  module Amendable
5
- # A command with all the business logic when a user starts amending a resource.
5
+ # A command with all the business logic to withdraw an amendment.
6
6
  class Withdraw < Rectify::Command
7
7
  # Public: Initializes the command.
8
8
  #
9
- # emendation - The resource to withdraw.
10
- # current_user - The current user.
11
- def initialize(emendation, current_user)
12
- @emendation = emendation
9
+ # amendment - The amendment to withdraw.
10
+ # current_user - The current user.
11
+ def initialize(amendment, current_user)
12
+ @amendment = amendment
13
+ @amender = amendment.amender
13
14
  @current_user = current_user
15
+ @emendation = amendment.emendation
14
16
  end
15
17
 
16
18
  # Executes the command. Broadcasts these events:
@@ -20,26 +22,40 @@ module Decidim
20
22
  #
21
23
  # Returns nothing.
22
24
  def call
23
- return broadcast(:invalid) if @emendation.votes.any?
25
+ return broadcast(:invalid) unless emendation.votes.empty? && amender == current_user
24
26
 
25
27
  transaction do
26
- change_amendment_state_to_withdrawn
27
- change_emendation_state_to_withdrawn
28
+ withdraw_amendment!
29
+ withdraw_emendation!
28
30
  end
29
31
 
30
- broadcast(:ok, @emendation)
32
+ broadcast(:ok, emendation)
31
33
  end
32
34
 
33
35
  private
34
36
 
35
- def change_amendment_state_to_withdrawn
36
- @emendation.amendment.update state: "withdrawn"
37
+ attr_reader :amendment, :amender, :current_user, :emendation
38
+
39
+ def withdraw_amendment!
40
+ @amendment = Decidim.traceability.update!(
41
+ amendment,
42
+ current_user,
43
+ { state: "withdrawn" },
44
+ visibility: "public-only"
45
+ )
37
46
  end
38
47
 
39
- def change_emendation_state_to_withdrawn
40
- # rubocop:disable Rails/SkipsModelValidations
41
- @emendation.update_attribute :state, "withdrawn"
42
- # rubocop:enable Rails/SkipsModelValidations
48
+ # Unlike other Amendable commands, we need to update the state of the
49
+ # emendation for the scope Decidim::Proposals::Proposal::expect_withdrawn
50
+ # to be able to retrieve rejected emendations.
51
+ #
52
+ # Because we are modifying the emendation itself, we need to prevent
53
+ # PaperTrail from creating an additional version to ensure that this
54
+ # change does not appear in the diff renderer of the emendation page.
55
+ def withdraw_emendation!
56
+ PaperTrail.request(enabled: false) do
57
+ emendation.update!(state: "withdrawn")
58
+ end
43
59
  end
44
60
  end
45
61
  end
@@ -40,6 +40,7 @@ module Decidim
40
40
 
41
41
  def increment_score
42
42
  return unless form.followable.is_a? Decidim::User
43
+
43
44
  Decidim::Gamification.increment_score(form.followable, :followers)
44
45
  end
45
46
  end
@@ -21,7 +21,12 @@ module Decidim
21
21
  verify_oauth_signature!
22
22
 
23
23
  begin
24
- return broadcast(:ok, existing_identity.user) if existing_identity
24
+ if existing_identity
25
+ user = existing_identity.user
26
+ verify_user_confirmed(user)
27
+
28
+ return broadcast(:ok, user)
29
+ end
25
30
  return broadcast(:invalid) if form.invalid?
26
31
 
27
32
  transaction do
@@ -31,8 +36,8 @@ module Decidim
31
36
  trigger_omniauth_registration
32
37
 
33
38
  broadcast(:ok, @user)
34
- rescue ActiveRecord::RecordInvalid => error
35
- broadcast(:error, error.record)
39
+ rescue ActiveRecord::RecordInvalid => e
40
+ broadcast(:error, e.record)
36
41
  end
37
42
  end
38
43
 
@@ -48,7 +53,12 @@ module Decidim
48
53
  organization: organization
49
54
  )
50
55
 
51
- unless @user.persisted?
56
+ if @user.persisted?
57
+ # If user has left the account unconfirmed and later on decides to sign
58
+ # in with omniauth with an already verified account, the account needs
59
+ # to be marked confirmed.
60
+ @user.skip_confirmation! if !@user.confirmed? && @user.email == verified_email
61
+ else
52
62
  @user.email = (verified_email || form.email)
53
63
  @user.name = form.name
54
64
  @user.nickname = form.normalized_nickname
@@ -84,6 +94,14 @@ module Decidim
84
94
  )
85
95
  end
86
96
 
97
+ def verify_user_confirmed(user)
98
+ return true if user.confirmed?
99
+ return false if user.email != verified_email
100
+
101
+ user.skip_confirmation!
102
+ user.save!
103
+ end
104
+
87
105
  def verify_oauth_signature!
88
106
  raise InvalidOauthSignature, "Invalid oauth signature: #{form.oauth_signature}" unless signature_valid?
89
107
  end
@@ -19,6 +19,7 @@ module Decidim
19
19
  def call
20
20
  return broadcast(:invalid) if form.invalid?
21
21
 
22
+ delete_pending_invited_user
22
23
  create_user
23
24
 
24
25
  broadcast(:ok, @user)
@@ -30,6 +31,10 @@ module Decidim
30
31
 
31
32
  attr_reader :form
32
33
 
34
+ def delete_pending_invited_user
35
+ User.invitation_not_accepted.where(email: form.email).delete_all
36
+ end
37
+
33
38
  def create_user
34
39
  @user = User.create!(
35
40
  email: form.email,
@@ -38,6 +38,7 @@ module Decidim
38
38
  def decrement_score
39
39
  followable = form.follow.followable
40
40
  return unless followable.is_a? Decidim::User
41
+
41
42
  Decidim::Gamification.decrement_score(followable, :followers)
42
43
  end
43
44
  end
@@ -52,6 +52,7 @@ module Decidim
52
52
 
53
53
  def paginate(collection)
54
54
  return collection if page_params.blank?
55
+
55
56
  collection.page(page_params[:page]).per(page_params[:per_page])
56
57
  end
57
58
 
@@ -26,6 +26,8 @@ module Decidim
26
26
  "#{action}-#{resource.component.id}-#{resource.resource_manifest.name}-#{resource.id}"
27
27
  elsif resource && permissions_holder
28
28
  "#{action}-#{permissions_holder.class.name}-#{permissions_holder.id}-#{resource.resource_manifest.name}-#{resource.id}"
29
+ elsif permissions_holder
30
+ "#{action}-#{permissions_holder.class.name}-#{permissions_holder.id}"
29
31
  else
30
32
  "#{action}-#{current_component.id}"
31
33
  end
@@ -4,34 +4,119 @@ module Decidim
4
4
  class AmendmentsController < Decidim::ApplicationController
5
5
  include Decidim::ApplicationHelper
6
6
  include FormFactory
7
+ helper Decidim::ResourceReferenceHelper
7
8
 
8
9
  before_action :authenticate_user!
9
- helper_method :amendable, :emendation
10
+ helper_method :amendment, :amendable, :emendation, :similar_emendations
11
+ before_action :ensure_is_draft_from_user, only: [:compare_draft, :edit_draft, :update_draft, :destroy_draft, :preview_draft, :publish_draft]
10
12
 
11
13
  def new
12
- @form = Decidim::Amendable::CreateForm.from_params(params)
14
+ raise ActionController::RoutingError, "Not Found" unless amendable
15
+
16
+ enforce_permission_to :create, :amendment, current_component: amendable.component
17
+
18
+ amendment_draft = amendable.amendments.find_by(amender: current_user.id, state: "draft")
19
+
20
+ if amendment_draft
21
+ redirect_to edit_draft_amend_path(amendment_draft)
22
+ else
23
+ @form = form(Decidim::Amendable::CreateForm).from_params(params)
24
+ end
13
25
  end
14
26
 
15
27
  def create
28
+ enforce_permission_to :create, :amendment, current_component: amendable.component
29
+
16
30
  @form = form(Decidim::Amendable::CreateForm).from_params(params)
17
- enforce_permission_to :create, :amendment
18
31
 
19
- Decidim::Amendable::Create.call(@form) do
20
- on(:ok) do
32
+ Decidim::Amendable::CreateDraft.call(@form) do
33
+ on(:ok) do |amendment|
21
34
  flash[:notice] = t("created.success", scope: "decidim.amendments")
22
- redirect_to Decidim::ResourceLocatorPresenter.new(@amendable).path
35
+ redirect_to compare_draft_amend_path(amendment)
23
36
  end
24
37
 
25
38
  on(:invalid) do
26
- flash[:alert] = t("created.error", scope: "decidim.amendments")
39
+ flash.now[:alert] = t("created.error", scope: "decidim.amendments")
27
40
  render :new
28
41
  end
29
42
  end
30
43
  end
31
44
 
45
+ def compare_draft
46
+ enforce_permission_to :create, :amendment, current_component: amendable.component
47
+
48
+ if similar_emendations.empty?
49
+ flash[:notice] = t("no_similars_found", scope: "decidim.amendments.compare_draft")
50
+ redirect_to edit_draft_amend_path(amendment)
51
+ end
52
+ end
53
+
54
+ def edit_draft
55
+ enforce_permission_to :create, :amendment, current_component: amendable.component
56
+
57
+ @form = form(Decidim::Amendable::EditForm).from_model(amendment)
58
+ end
59
+
60
+ def update_draft
61
+ enforce_permission_to :create, :amendment, current_component: amendable.component
62
+
63
+ @form = form(Decidim::Amendable::EditForm).from_params(params)
64
+
65
+ Decidim::Amendable::UpdateDraft.call(@form) do
66
+ on(:ok) do |amendment|
67
+ flash[:notice] = t("success", scope: "decidim.amendments.update_draft")
68
+ redirect_to preview_draft_amend_path(amendment)
69
+ end
70
+
71
+ on(:invalid) do
72
+ flash.now[:alert] = t("error", scope: "decidim.amendments.update_draft")
73
+ render :edit_draft
74
+ end
75
+ end
76
+ end
77
+
78
+ def destroy_draft
79
+ enforce_permission_to :create, :amendment, current_component: amendable.component
80
+
81
+ Decidim::Amendable::DestroyDraft.call(amendment, current_user) do
82
+ on(:ok) do |amendable|
83
+ flash[:notice] = t("success", scope: "decidim.amendments.destroy_draft")
84
+ redirect_to new_amend_path(amendable_gid: amendable.to_sgid.to_s)
85
+ end
86
+
87
+ on(:invalid) do
88
+ flash[:alert] = t("error", scope: "decidim.amendments.destroy_draft")
89
+ redirect_to edit_draft_amend_path(amendment)
90
+ end
91
+ end
92
+ end
93
+
94
+ def preview_draft
95
+ enforce_permission_to :create, :amendment, current_component: amendable.component
96
+ end
97
+
98
+ def publish_draft
99
+ enforce_permission_to :create, :amendment, current_component: amendable.component
100
+
101
+ @form = form(Decidim::Amendable::PublishForm).from_model(amendment)
102
+
103
+ Decidim::Amendable::PublishDraft.call(@form) do
104
+ on(:ok) do |emendation|
105
+ flash[:notice] = t("success", scope: "decidim.amendments.publish_draft")
106
+ redirect_to Decidim::ResourceLocatorPresenter.new(emendation).path
107
+ end
108
+
109
+ on(:invalid) do
110
+ flash.now[:alert] = t("error", scope: "decidim.amendments.publish_draft")
111
+ render :edit_draft
112
+ end
113
+ end
114
+ end
115
+
32
116
  def reject
33
- @form = form(Decidim::Amendable::RejectForm).from_params(params)
34
- enforce_permission_to :reject, :amendment, amendment: @form.amendable
117
+ enforce_permission_to :reject, :amendment, current_component: amendable.component
118
+
119
+ @form = form(Decidim::Amendable::RejectForm).from_model(amendment)
35
120
 
36
121
  Decidim::Amendable::Reject.call(@form) do
37
122
  on(:ok) do
@@ -41,64 +126,99 @@ module Decidim
41
126
  on(:invalid) do
42
127
  flash[:alert] = t("rejected.error", scope: "decidim.amendments")
43
128
  end
44
- redirect_to Decidim::ResourceLocatorPresenter.new(@emendation).path
129
+
130
+ redirect_to Decidim::ResourceLocatorPresenter.new(emendation).path
45
131
  end
46
132
  end
47
133
 
48
134
  def promote
49
- @form = Decidim::Amendable::PromoteForm.from_params(params)
50
- enforce_permission_to :promote, :amendment, amendment: @form.emendation
135
+ enforce_permission_to :promote, :amendment, current_component: amendable.component
136
+
137
+ @form = form(Decidim::Amendable::PromoteForm).from_model(amendment)
51
138
 
52
139
  Decidim::Amendable::Promote.call(@form) do
53
- on(:ok) do |proposal|
140
+ on(:ok) do |promoted_resource|
54
141
  flash[:notice] = I18n.t("promoted.success", scope: "decidim.amendments")
55
- redirect_to Decidim::ResourceLocatorPresenter.new(proposal).path
142
+ redirect_to Decidim::ResourceLocatorPresenter.new(promoted_resource).path
56
143
  end
57
144
 
58
145
  on(:invalid) do
59
146
  flash.now[:alert] = t("promoted.error", scope: "decidim.amendments")
60
- redirect_to Decidim::ResourceLocatorPresenter.new(@emendation).path
147
+ redirect_to Decidim::ResourceLocatorPresenter.new(emendation).path
61
148
  end
62
149
  end
63
150
  end
64
151
 
65
152
  def review
66
- @form = Decidim::Amendable::ReviewForm.from_params(params)
153
+ enforce_permission_to :accept, :amendment, current_component: amendable.component
154
+
155
+ @form = form(Decidim::Amendable::ReviewForm).from_params(params)
67
156
  end
68
157
 
69
158
  def accept
70
- @form = Decidim::Amendable::ReviewForm.from_params(params)
71
- enforce_permission_to :accept, :amendment, amendment: @form.amendable
159
+ enforce_permission_to :accept, :amendment, current_component: amendable.component
160
+
161
+ @form = form(Decidim::Amendable::ReviewForm).from_params(params)
72
162
 
73
163
  Decidim::Amendable::Accept.call(@form) do
74
- on(:ok) do
164
+ on(:ok) do |emendation|
75
165
  flash[:notice] = t("accepted.success", scope: "decidim.amendments")
76
- redirect_to Decidim::ResourceLocatorPresenter.new(@emendation).path
166
+ redirect_to Decidim::ResourceLocatorPresenter.new(emendation).path
77
167
  end
78
168
 
79
169
  on(:invalid) do
80
- flash[:alert] = t("accepted.error", scope: "decidim.amendments")
170
+ flash.now[:alert] = t("accepted.error", scope: "decidim.amendments")
81
171
  render :review
82
172
  end
83
173
  end
84
174
  end
85
175
 
176
+ def withdraw
177
+ enforce_permission_to :withdraw, :amendment, amendment: amendment, current_component: amendable.component
178
+
179
+ Decidim::Amendable::Withdraw.call(amendment, current_user) do
180
+ on(:ok) do |withdrawn_emendation|
181
+ flash[:notice] = t("success", scope: "decidim.amendments.withdraw")
182
+ redirect_to Decidim::ResourceLocatorPresenter.new(withdrawn_emendation).path
183
+ end
184
+
185
+ on(:invalid) do
186
+ flash[:alert] = t("error", scope: "decidim.amendments.withdraw")
187
+ redirect_to Decidim::ResourceLocatorPresenter.new(emendation).path
188
+ end
189
+ end
190
+ end
191
+
86
192
  private
87
193
 
194
+ # GlobalID::SignedGlobalID parameter to locate the amendable resource.
195
+ # Needed for actions :new and :create, when there is no amendment yet.
88
196
  def amendable_gid
89
- params[:amendable_gid] || params[:amendment][:amendable_gid]
197
+ params[:amendable_gid] || params.dig(:amendment, :amendable_gid)
198
+ end
199
+
200
+ def amendment
201
+ @amendment ||= Decidim::Amendment.find_by(id: params[:id])
90
202
  end
91
203
 
92
204
  def amendable
93
- @amendable ||= if amendable_gid
94
- present(GlobalID::Locator.locate_signed(amendable_gid))
95
- else
96
- Decidim::Amendment.find_by(decidim_emendation_id: params[:id]).amendable
97
- end
205
+ @amendable ||= GlobalID::Locator.locate_signed(amendable_gid) || amendment&.amendable
98
206
  end
99
207
 
100
208
  def emendation
101
- @emendation ||= present(Decidim::Amendment.find(params[:id]).emendation)
209
+ @emendation ||= amendment&.emendation
210
+ end
211
+
212
+ def amender
213
+ @amender ||= amendment&.amender
214
+ end
215
+
216
+ def ensure_is_draft_from_user
217
+ raise ActionController::RoutingError, "Not Found" unless amendment.draft? && amender == current_user
218
+ end
219
+
220
+ def similar_emendations
221
+ @similar_emendations ||= Decidim::SimilarEmendations.for(amendment)
102
222
  end
103
223
  end
104
224
  end