decidim-proposals 0.13.1 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/decidim_proposals_manifest.js +1 -0
  3. data/app/assets/images/decidim/gamification/badges/accepted_proposals.svg +144 -0
  4. data/app/assets/images/decidim/gamification/badges/proposal_votes.svg +95 -0
  5. data/app/assets/images/decidim/gamification/badges/proposals.svg +145 -0
  6. data/app/assets/javascripts/decidim/proposals/add_proposal.js.es6 +1 -2
  7. data/app/cells/decidim/proposals/collaborative_draft_cell.rb +55 -0
  8. data/app/cells/decidim/proposals/collaborative_draft_link_to_proposal/show.erb +13 -0
  9. data/app/cells/decidim/proposals/collaborative_draft_link_to_proposal_cell.rb +57 -0
  10. data/app/cells/decidim/proposals/collaborative_draft_m/footer.erb +6 -0
  11. data/app/cells/decidim/proposals/collaborative_draft_m/tags.erb +1 -0
  12. data/app/cells/decidim/proposals/collaborative_draft_m_cell.rb +39 -0
  13. data/app/cells/decidim/proposals/endorsers_list/show.erb +1 -2
  14. data/app/cells/decidim/proposals/irreversible_action_modal/show.erb +27 -0
  15. data/app/cells/decidim/proposals/irreversible_action_modal_cell.rb +79 -0
  16. data/app/cells/decidim/proposals/proposal_cell.rb +1 -1
  17. data/app/cells/decidim/proposals/proposal_link_to_collaborative_draft/show.erb +9 -0
  18. data/app/cells/decidim/proposals/proposal_link_to_collaborative_draft_cell.rb +30 -0
  19. data/app/cells/decidim/proposals/proposal_m/footer.erb +1 -1
  20. data/app/cells/decidim/proposals/proposal_m_cell.rb +9 -1
  21. data/app/commands/decidim/proposals/accept_access_to_collaborative_draft.rb +70 -0
  22. data/app/commands/decidim/proposals/admin/answer_proposal.rb +9 -0
  23. data/app/commands/decidim/proposals/admin/create_proposal.rb +5 -2
  24. data/app/commands/decidim/proposals/attachment_methods.rb +43 -0
  25. data/app/commands/decidim/proposals/create_collaborative_draft.rb +73 -0
  26. data/app/commands/decidim/proposals/create_proposal.rb +13 -48
  27. data/app/commands/decidim/proposals/publish_collaborative_draft.rb +87 -0
  28. data/app/commands/decidim/proposals/publish_proposal.rb +7 -0
  29. data/app/commands/decidim/proposals/reject_access_to_collaborative_draft.rb +63 -0
  30. data/app/commands/decidim/proposals/request_access_to_collaborative_draft.rb +50 -0
  31. data/app/commands/decidim/proposals/unvote_proposal.rb +6 -7
  32. data/app/commands/decidim/proposals/update_collaborative_draft.rb +60 -0
  33. data/app/commands/decidim/proposals/update_proposal.rb +16 -3
  34. data/app/commands/decidim/proposals/vote_proposal.rb +3 -0
  35. data/app/commands/decidim/proposals/withdraw_collaborative_draft.rb +65 -0
  36. data/app/controllers/concerns/decidim/proposals/collaborative_orderable.rb +56 -0
  37. data/app/controllers/decidim/proposals/admin/application_controller.rb +1 -0
  38. data/app/controllers/decidim/proposals/collaborative_draft_collaborator_requests_controller.rb +53 -0
  39. data/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +171 -0
  40. data/app/controllers/decidim/proposals/proposals_controller.rb +38 -33
  41. data/app/controllers/decidim/proposals/versions_controller.rb +23 -0
  42. data/app/events/decidim/proposals/collaborative_draft_access_accepted_event.rb +8 -0
  43. data/app/events/decidim/proposals/collaborative_draft_access_rejected_event.rb +8 -0
  44. data/app/events/decidim/proposals/collaborative_draft_access_request_event.rb +27 -0
  45. data/app/events/decidim/proposals/collaborative_draft_access_requested_event.rb +8 -0
  46. data/app/events/decidim/proposals/collaborative_draft_access_requester_accepted_event.rb +8 -0
  47. data/app/events/decidim/proposals/collaborative_draft_access_requester_rejected_event.rb +8 -0
  48. data/app/events/decidim/proposals/collaborative_draft_withdrawn_event.rb +29 -0
  49. data/app/events/decidim/proposals/proposal_mentioned_event.rb +3 -1
  50. data/app/forms/decidim/proposals/accept_access_to_collaborative_draft_form.rb +10 -0
  51. data/app/forms/decidim/proposals/access_to_collaborative_draft_form.rb +35 -0
  52. data/app/forms/decidim/proposals/collaborative_draft_form.rb +18 -0
  53. data/app/forms/decidim/proposals/proposal_form.rb +2 -21
  54. data/app/forms/decidim/proposals/proposal_wizard_create_step_form.rb +36 -0
  55. data/app/forms/decidim/proposals/reject_access_to_collaborative_draft_form.rb +9 -0
  56. data/app/forms/decidim/proposals/request_access_to_collaborative_draft_form.rb +20 -0
  57. data/app/helpers/decidim/proposals/application_helper.rb +23 -8
  58. data/app/helpers/decidim/proposals/collaborative_draft_cells_helper.rb +48 -0
  59. data/app/helpers/decidim/proposals/collaborative_draft_helper.rb +29 -0
  60. data/app/helpers/decidim/proposals/map_helper.rb +3 -2
  61. data/app/helpers/decidim/proposals/proposal_cells_helper.rb +1 -1
  62. data/app/helpers/decidim/proposals/proposal_endorsements_helper.rb +15 -0
  63. data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +52 -4
  64. data/app/models/decidim/proposals/collaborative_draft.rb +54 -0
  65. data/app/models/decidim/proposals/collaborative_draft_collaborator_request.rb +13 -0
  66. data/app/models/decidim/proposals/proposal.rb +9 -3
  67. data/app/permissions/decidim/proposals/permissions.rb +53 -9
  68. data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +2 -2
  69. data/app/presenters/decidim/proposals/admin_log/value_types/proposal_title_body_presenter.rb +17 -0
  70. data/app/presenters/decidim/proposals/collaborative_draft_presenter.rb +27 -0
  71. data/app/presenters/decidim/proposals/proposal_presenter.rb +24 -1
  72. data/app/queries/decidim/proposals/similar_collaborative_drafts.rb +52 -0
  73. data/app/queries/decidim/proposals/similar_proposals.rb +2 -4
  74. data/app/services/decidim/proposals/collaborative_draft_search.rb +61 -0
  75. data/app/services/decidim/proposals/diff_renderer.rb +58 -0
  76. data/app/services/decidim/proposals/proposal_search.rb +1 -1
  77. data/app/views/decidim/participatory_processes/participatory_process_groups/_highlighted_proposals.html.erb +8 -3
  78. data/app/views/decidim/participatory_spaces/_highlighted_proposals.html.erb +8 -3
  79. data/app/views/decidim/proposals/admin/proposal_answers/edit.html.erb +1 -1
  80. data/app/views/decidim/proposals/admin/proposals/_form.html.erb +4 -4
  81. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +5 -2
  82. data/app/views/decidim/proposals/admin/proposals/index.html.erb +1 -1
  83. data/app/views/decidim/proposals/admin/proposals/update_category.js.erb +4 -4
  84. data/app/views/decidim/proposals/admin/shared/_info_proposal.html.erb +2 -2
  85. data/app/views/decidim/proposals/collaborative_drafts/_accept_request_access_form.html.erb +8 -0
  86. data/app/views/decidim/proposals/collaborative_drafts/_collaborative_drafts.html.erb +16 -0
  87. data/app/views/decidim/proposals/collaborative_drafts/_collaborator_requests.html.erb +20 -0
  88. data/app/views/decidim/proposals/collaborative_drafts/_count.html.erb +1 -0
  89. data/app/views/decidim/proposals/collaborative_drafts/_filters.html.erb +30 -0
  90. data/app/views/decidim/proposals/collaborative_drafts/_filters_small_view.html.erb +18 -0
  91. data/app/views/decidim/proposals/collaborative_drafts/_new_collaborative_draft_button.html.erb +11 -0
  92. data/app/views/decidim/proposals/collaborative_drafts/_reject_request_access_form.html.erb +10 -0
  93. data/app/views/decidim/proposals/collaborative_drafts/_request_access_form.html.erb +7 -0
  94. data/app/views/decidim/proposals/collaborative_drafts/compare.html.erb +19 -0
  95. data/app/views/decidim/proposals/collaborative_drafts/complete.html.erb +70 -0
  96. data/app/views/decidim/proposals/collaborative_drafts/edit.html.erb +57 -0
  97. data/app/views/decidim/proposals/collaborative_drafts/index.html.erb +23 -0
  98. data/app/views/decidim/proposals/collaborative_drafts/index.js.erb +10 -0
  99. data/app/views/decidim/proposals/collaborative_drafts/new.html.erb +28 -0
  100. data/app/views/decidim/proposals/collaborative_drafts/show.html.erb +136 -0
  101. data/app/views/decidim/proposals/proposal_endorsements/_identity.html.erb +1 -1
  102. data/app/views/decidim/proposals/proposal_endorsements/update_buttons_and_counters.js.erb +1 -1
  103. data/app/views/decidim/proposals/proposal_votes/update_buttons_and_counters.js.erb +5 -5
  104. data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +57 -0
  105. data/app/views/decidim/proposals/proposals/_endorsement_button.html.erb +3 -3
  106. data/app/views/decidim/proposals/proposals/_endorsements_card_row.html.erb +1 -7
  107. data/app/views/decidim/proposals/proposals/_linked_proposals.html.erb +1 -1
  108. data/app/views/decidim/proposals/proposals/_proposal.html.erb +1 -1
  109. data/app/views/decidim/proposals/proposals/_proposal_preview.html.erb +1 -1
  110. data/app/views/decidim/proposals/proposals/_proposal_similar.html.erb +3 -3
  111. data/app/views/decidim/proposals/proposals/_vote_button.html.erb +4 -3
  112. data/app/views/decidim/proposals/proposals/_wizard_aside.html.erb +2 -2
  113. data/app/views/decidim/proposals/proposals/compare.html.erb +5 -3
  114. data/app/views/decidim/proposals/proposals/complete.html.erb +2 -57
  115. data/app/views/decidim/proposals/proposals/edit.html.erb +1 -34
  116. data/app/views/decidim/proposals/proposals/edit_draft.html.erb +1 -34
  117. data/app/views/decidim/proposals/proposals/index.html.erb +5 -1
  118. data/app/views/decidim/proposals/proposals/new.html.erb +13 -7
  119. data/app/views/decidim/proposals/proposals/preview.html.erb +2 -2
  120. data/app/views/decidim/proposals/proposals/show.html.erb +6 -5
  121. data/app/views/decidim/proposals/versions/_version.html.erb +20 -0
  122. data/app/views/decidim/proposals/versions/index.html.erb +34 -0
  123. data/app/views/decidim/proposals/versions/show.html.erb +39 -0
  124. data/config/locales/ca.yml +222 -17
  125. data/config/locales/en.yml +208 -3
  126. data/config/locales/es-PY.yml +208 -3
  127. data/config/locales/es.yml +281 -76
  128. data/config/locales/eu.yml +208 -3
  129. data/config/locales/fi.yml +335 -131
  130. data/config/locales/fr.yml +208 -3
  131. data/config/locales/gl.yml +208 -3
  132. data/config/locales/hu.yml +622 -0
  133. data/config/locales/it.yml +208 -3
  134. data/config/locales/nl.yml +208 -3
  135. data/config/locales/pl.yml +214 -3
  136. data/config/locales/pt-BR.yml +212 -7
  137. data/config/locales/pt.yml +208 -3
  138. data/config/locales/ru.yml +20 -19
  139. data/config/locales/sv.yml +313 -108
  140. data/config/locales/uk.yml +25 -24
  141. data/db/migrate/20180326091532_create_decidim_proposals_collaborative_drafts.rb +29 -0
  142. data/db/migrate/20180613151121_create_collaborative_draft_collaborator_requests.rb +12 -0
  143. data/db/migrate/20180711074134_add_counter_cache_coauthorships_to_collaborative_drafts.rb +7 -0
  144. data/db/migrate/20180711075004_remove_index_counter_cache_coauthorships_to_proposals.rb +7 -0
  145. data/lib/decidim/proposals/admin_engine.rb +1 -0
  146. data/lib/decidim/proposals/commentable_collaborative_draft.rb +38 -0
  147. data/lib/decidim/proposals/component.rb +69 -4
  148. data/lib/decidim/proposals/engine.rb +48 -2
  149. data/lib/decidim/proposals/proposal_serializer.rb +4 -3
  150. data/lib/decidim/proposals/test/factories.rb +74 -13
  151. data/lib/decidim/proposals/version.rb +1 -1
  152. data/lib/decidim/proposals.rb +1 -0
  153. metadata +94 -24
  154. data/app/cells/decidim/proposals/coauthorships_cell.rb +0 -40
  155. data/app/views/decidim/participatory_processes/participatory_process_groups/_proposal.html.erb +0 -1
  156. data/app/views/decidim/participatory_spaces/_proposal.html.erb +0 -1
@@ -10,8 +10,7 @@
10
10
  endorsers,
11
11
  cell_name: "decidim/author",
12
12
  cell_options: { extra_classes: ["author-data--small"] },
13
- hidden_elements_count_i18n_key: "decidim.proposals.proposals.show.hidden_endorsers_count",
14
- size: :small
13
+ hidden_elements_count_i18n_key: "decidim.proposals.proposals.show.hidden_endorsers_count"
15
14
  ) %>
16
15
  </div>
17
16
  </div>
@@ -0,0 +1,27 @@
1
+ <%= button_reveal_modal %>
2
+
3
+ <div id="<%= modal_id %>" class="reveal" data-reveal aria-labelledby="<%= modal_title %>" aria-hidden="true" role="dialog">
4
+ <div class="reveal__header">
5
+ <h3 class="reveal__title">
6
+ <%= modal_title %>
7
+ </h3>
8
+
9
+ <button class="close-button" data-close aria-label="<%= close_label %>" type="button">
10
+ <span aria-hidden="true">&times;</span>
11
+ </button>
12
+ </div>
13
+
14
+ <div class="row">
15
+ <div>
16
+ <p>
17
+ <%= modal_body %>
18
+ </p>
19
+ </div>
20
+ </div>
21
+
22
+ <div class="row">
23
+ <%= button_cancel %>
24
+
25
+ <%= button_continue %>
26
+ </div>
27
+ </div>
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # This cell renders the button and modal for the publish/withdraw
6
+ # actions in the details of a collaborative draft
7
+ # the `cell` should be called with an :action argument, to show relative info:
8
+ # - :publish
9
+ # - :withdraw
10
+ class IrreversibleActionModalCell < Decidim::ViewModel
11
+ def show
12
+ return unless action.presence
13
+ render :show
14
+ end
15
+
16
+ private
17
+
18
+ def action
19
+ options[:action]
20
+ end
21
+
22
+ def publish?
23
+ action == :publish
24
+ end
25
+
26
+ def withdraw?
27
+ action == :withdraw
28
+ end
29
+
30
+ def modal_id
31
+ "#{action}-irreversible-action-modal"
32
+ end
33
+
34
+ def button_reveal_modal
35
+ data = { open: modal_id }
36
+ label = t(action, scope: "decidim.proposals.collaborative_drafts.show")
37
+ css = publish? ? "button expanded button--sc" : "secondary"
38
+
39
+ button_tag label, type: "button", class: css, data: data
40
+ end
41
+
42
+ def modal_title
43
+ t("title", scope: "decidim.proposals.collaborative_drafts.collaborative_draft.#{action}.irreversible_action_modal")
44
+ end
45
+
46
+ def modal_body
47
+ t("body", scope: "decidim.proposals.collaborative_drafts.collaborative_draft.#{action}.irreversible_action_modal")
48
+ end
49
+
50
+ def button_continue
51
+ label = t("ok", scope: "decidim.proposals.collaborative_drafts.collaborative_draft.#{action}.irreversible_action_modal")
52
+ path = resource_path action
53
+ css = "button expanded"
54
+ button_to label, path, class: css, form_class: "columns medium-6"
55
+ end
56
+
57
+ def close_label
58
+ t("cancel", scope: "decidim.proposals.collaborative_drafts.collaborative_draft.#{action}.irreversible_action_modal")
59
+ end
60
+
61
+ def button_cancel
62
+ content_tag :div, class: "columns medium-6" do
63
+ button_tag type: "button", class: "clear button secondary expanded", "data-close": "" do
64
+ close_label
65
+ end
66
+ end
67
+ end
68
+
69
+ def resource_path(action)
70
+ @resource_path ||= decidim_proposals.send("#{action}_collaborative_draft_path",
71
+ id: model.id)
72
+ end
73
+
74
+ def decidim_proposals
75
+ Decidim::EngineRouter.main_proxy(model.component)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -14,7 +14,7 @@ module Decidim
14
14
  delegate :user_signed_in?, to: :parent_controller
15
15
 
16
16
  def show
17
- cell card_size, model, @options
17
+ cell card_size, model, options
18
18
  end
19
19
 
20
20
  private
@@ -0,0 +1,9 @@
1
+ <div class="text-center mt-sm">
2
+ <%= link_to_resource %>
3
+
4
+ <div class="text-center">
5
+ <small>
6
+ <%= link_help_text %>
7
+ </small>
8
+ </div>
9
+ </div>
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cell/partial"
4
+
5
+ module Decidim
6
+ module Proposals
7
+ # This cell renders the link to the source collaborative draft of a proposal.
8
+ class ProposalLinkToCollaborativeDraftCell < Decidim::ViewModel
9
+ def show
10
+ render if collaborative_draft
11
+ end
12
+
13
+ private
14
+
15
+ def collaborative_draft
16
+ @collaborative_draft ||= model.linked_resources(:collaborative_draft, "created_from_collaborative_draft").first
17
+ end
18
+
19
+ def link_to_resource
20
+ link_to resource_locator(collaborative_draft).path, class: "link" do
21
+ t("link_to_collaborative_draft_text", scope: "decidim.proposals.proposals.show")
22
+ end
23
+ end
24
+
25
+ def link_help_text
26
+ t("link_to_collaborative_draft_help_text", scope: "decidim.proposals.proposals.show")
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,7 +1,7 @@
1
1
  <% if has_link_to_resource? %>
2
2
  <div class="card__footer">
3
3
  <div class="card__support">
4
- <% if actionable? %>
4
+ <% if has_actions? %>
5
5
  <% if !current_settings.votes_hidden? %>
6
6
  <%= cell(
7
7
  "decidim/progress_bar",
@@ -14,6 +14,14 @@ module Decidim
14
14
 
15
15
  private
16
16
 
17
+ def title
18
+ present(model).title
19
+ end
20
+
21
+ def body
22
+ present(model).body
23
+ end
24
+
17
25
  def has_state?
18
26
  model.published?
19
27
  end
@@ -27,7 +35,7 @@ module Decidim
27
35
  end
28
36
 
29
37
  def description
30
- truncate(model.body, length: 100)
38
+ truncate(present(model).body, length: 100)
31
39
  end
32
40
 
33
41
  def badge_classes
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # A command with all the business logic to accept a user request to
6
+ # contribute to a collaborative draft.
7
+ class AcceptAccessToCollaborativeDraft < Rectify::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # form - A form object with the params.
11
+ # collaborative_draft - A Decidim::Proposals::CollaborativeDraft object.
12
+ # current_user - The current user.
13
+ # requester_user - The user that requested to collaborate.
14
+ def initialize(form, current_user)
15
+ @form = form
16
+ @collaborative_draft = form.collaborative_draft
17
+ @current_user = current_user
18
+ @requester_user = form.requester_user
19
+ end
20
+
21
+ # Executes the command. Broadcasts these events:
22
+ #
23
+ # - :ok when everything is valid.
24
+ # - :invalid if it wasn't valid and we couldn't proceed.
25
+ #
26
+ # Returns nothing.
27
+ def call
28
+ return broadcast(:invalid) if @form.invalid?
29
+ return broadcast(:invalid) if @current_user.nil?
30
+
31
+ transaction do
32
+ @collaborative_draft.requesters.delete @requester_user
33
+
34
+ Decidim::Coauthorship.create(
35
+ coauthorable: @collaborative_draft,
36
+ author: @requester_user
37
+ )
38
+ end
39
+
40
+ notify_collaborative_draft_requester
41
+ notify_collaborative_draft_authors
42
+ broadcast(:ok, @requester_user)
43
+ end
44
+
45
+ private
46
+
47
+ def notify_collaborative_draft_authors
48
+ recipient_ids = @collaborative_draft.authors.pluck(:id) - [@requester_user.id]
49
+ Decidim::EventsManager.publish(
50
+ event: "decidim.events.proposals.collaborative_draft_access_accepted",
51
+ event_class: Decidim::Proposals::CollaborativeDraftAccessAcceptedEvent,
52
+ resource: @collaborative_draft,
53
+ recipient_ids: recipient_ids.uniq,
54
+ extra: {
55
+ requester_id: @requester_user.id
56
+ }
57
+ )
58
+ end
59
+
60
+ def notify_collaborative_draft_requester
61
+ Decidim::EventsManager.publish(
62
+ event: "decidim.events.proposals.collaborative_draft_access_requester_accepted",
63
+ event_class: Decidim::Proposals::CollaborativeDraftAccessRequesterAcceptedEvent,
64
+ resource: @collaborative_draft,
65
+ recipient_ids: [@requester_user.id]
66
+ )
67
+ end
68
+ end
69
+ end
70
+ end
@@ -25,6 +25,7 @@ module Decidim
25
25
 
26
26
  answer_proposal
27
27
  notify_followers
28
+ increment_score
28
29
 
29
30
  broadcast(:ok)
30
31
  end
@@ -76,6 +77,14 @@ module Decidim
76
77
  recipient_ids: proposal.followers.pluck(:id)
77
78
  )
78
79
  end
80
+
81
+ def increment_score
82
+ return unless proposal.accepted?
83
+
84
+ proposal.authors.find_each do |author|
85
+ Decidim::Gamification.increment_score(author, :accepted_proposals)
86
+ end
87
+ end
79
88
  end
80
89
  end
81
90
  end
@@ -48,9 +48,12 @@ module Decidim
48
48
  end
49
49
 
50
50
  def attributes
51
+ parsed_title = Decidim::ContentProcessor.parse_with_processor(:hashtag, form.title, current_organization: form.current_organization).rewrite
52
+ parsed_body = Decidim::ContentProcessor.parse_with_processor(:hashtag, form.body, current_organization: form.current_organization).rewrite
53
+
51
54
  {
52
- title: form.title,
53
- body: form.body,
55
+ title: parsed_title,
56
+ body: parsed_body,
54
57
  category: form.category,
55
58
  scope: form.scope,
56
59
  component: form.component,
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # A module with all the attachment common methods for proposals
6
+ # and collaborative draft commands.
7
+ module AttachmentMethods
8
+ private
9
+
10
+ def build_attachment
11
+ @attachment = Attachment.new(
12
+ title: @form.attachment.title,
13
+ file: @form.attachment.file,
14
+ attached_to: @attached_to
15
+ )
16
+ end
17
+
18
+ def attachment_invalid?
19
+ if attachment.invalid? && attachment.errors.has_key?(:file)
20
+ @form.attachment.errors.add :file, attachment.errors[:file]
21
+ true
22
+ end
23
+ end
24
+
25
+ def attachment_present?
26
+ @form.attachment.file.present?
27
+ end
28
+
29
+ def create_attachment
30
+ attachment.attached_to = @attached_to
31
+ attachment.save!
32
+ end
33
+
34
+ def attachments_allowed?
35
+ @form.current_component.settings.attachments_allowed?
36
+ end
37
+
38
+ def process_attachments?
39
+ attachments_allowed? && attachment_present?
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # A command with all the business logic when a user creates a new collaborative draft.
6
+ class CreateCollaborativeDraft < Rectify::Command
7
+ include AttachmentMethods
8
+ # Public: Initializes the command.
9
+ #
10
+ # form - A form object with the params.
11
+ # current_user - The current user.
12
+ def initialize(form, current_user)
13
+ @form = form
14
+ @current_user = current_user
15
+ @attached_to = nil
16
+ end
17
+
18
+ # Executes the command. Broadcasts these events:
19
+ #
20
+ # - :ok when everything is valid, together with the collaborative draft.
21
+ # - :invalid if the form wasn't valid and we couldn't proceed.
22
+ #
23
+ # Returns nothing.
24
+ def call
25
+ return broadcast(:invalid) if form.invalid?
26
+
27
+ if process_attachments?
28
+ build_attachment
29
+ return broadcast(:invalid) if attachment_invalid?
30
+ end
31
+
32
+ transaction do
33
+ create_collaborative_draft
34
+ create_attachment if process_attachments?
35
+ end
36
+
37
+ broadcast(:ok, collaborative_draft)
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :form, :collaborative_draft, :attachment
43
+
44
+ def create_collaborative_draft
45
+ @collaborative_draft = Decidim.traceability.create!(
46
+ CollaborativeDraft,
47
+ @form.current_user,
48
+ title: form.title,
49
+ body: form.body,
50
+ category: form.category,
51
+ scope: form.scope,
52
+ component: form.component,
53
+ address: form.address,
54
+ latitude: form.latitude,
55
+ longitude: form.longitude,
56
+ state: "open"
57
+ )
58
+
59
+ @attached_to = @collaborative_draft
60
+
61
+ @collaborative_draft.add_coauthor(@current_user, user_group: @form.user_group)
62
+ end
63
+
64
+ def user_group
65
+ @user_group ||= Decidim::UserGroup.find_by(organization: organization, id: form.user_group_id)
66
+ end
67
+
68
+ def organization
69
+ @organization ||= @current_user.organization
70
+ end
71
+ end
72
+ end
73
+ end
@@ -4,13 +4,16 @@ module Decidim
4
4
  module Proposals
5
5
  # A command with all the business logic when a user creates a new proposal.
6
6
  class CreateProposal < Rectify::Command
7
+ include AttachmentMethods
7
8
  # Public: Initializes the command.
8
9
  #
9
10
  # form - A form object with the params.
10
11
  # current_user - The current user.
11
- def initialize(form, current_user)
12
+ # coauthorships - The coauthorships of the proposal.
13
+ def initialize(form, current_user, coauthorships = nil)
12
14
  @form = form
13
15
  @current_user = current_user
16
+ @coauthorships = coauthorships
14
17
  end
15
18
 
16
19
  # Executes the command. Broadcasts these events:
@@ -27,14 +30,8 @@ module Decidim
27
30
  return broadcast(:invalid)
28
31
  end
29
32
 
30
- if process_attachments?
31
- build_attachment
32
- return broadcast(:invalid) if attachment_invalid?
33
- end
34
-
35
33
  transaction do
36
34
  create_proposal
37
- create_attachment if process_attachments?
38
35
  end
39
36
 
40
37
  broadcast(:ok, proposal)
@@ -45,52 +42,20 @@ module Decidim
45
42
  attr_reader :form, :proposal, :attachment
46
43
 
47
44
  def create_proposal
48
- @proposal = Proposal.create!(
49
- title: form.title,
50
- body: form.body,
51
- category: form.category,
52
- scope: form.scope,
53
- component: form.component,
54
- address: form.address,
55
- latitude: form.latitude,
56
- longitude: form.longitude
57
- )
58
- proposal.add_coauthor(@current_user, decidim_user_group_id: form.user_group_id)
59
- end
45
+ parsed_title = Decidim::ContentProcessor.parse_with_processor(:hashtag, form.title, current_organization: form.current_organization).rewrite
46
+ parsed_body = Decidim::ContentProcessor.parse_with_processor(:hashtag, form.body, current_organization: form.current_organization).rewrite
60
47
 
61
- def build_attachment
62
- @attachment = Attachment.new(
63
- title: form.attachment.title,
64
- file: form.attachment.file,
65
- attached_to: @proposal
48
+ @proposal = Proposal.create!(
49
+ title: parsed_title,
50
+ body: parsed_body,
51
+ component: form.component
66
52
  )
67
- end
68
-
69
- def attachment_invalid?
70
- if attachment.invalid? && attachment.errors.has_key?(:file)
71
- form.attachment.errors.add :file, attachment.errors[:file]
72
- true
73
- end
74
- end
75
-
76
- def attachment_present?
77
- form.attachment.file.present?
78
- end
79
-
80
- def create_attachment
81
- attachment.attached_to = proposal
82
- attachment.save!
83
- end
84
-
85
- def attachments_allowed?
86
- form.current_component.settings.attachments_allowed?
87
- end
88
-
89
- def process_attachments?
90
- attachments_allowed? && attachment_present?
53
+ proposal.add_coauthor(@current_user, user_group: user_group)
91
54
  end
92
55
 
93
56
  def proposal_limit_reached?
57
+ return false if @coauthorships.present?
58
+
94
59
  proposal_limit = form.current_component.settings.proposal_limit
95
60
 
96
61
  return false if proposal_limit.zero?
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # A command with all the business logic when a user publishes a collaborative_draft.
6
+ class PublishCollaborativeDraft < Rectify::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # collaborative_draft - The collaborative_draft to publish.
10
+ # current_user - The current user.
11
+ # proposal_form - the form object of the new proposal
12
+ def initialize(collaborative_draft, current_user)
13
+ @collaborative_draft = collaborative_draft
14
+ @current_user = current_user
15
+ end
16
+
17
+ # Executes the command. Broadcasts these events:
18
+ #
19
+ # - :ok when everything is valid and the collaborative_draft is published.
20
+ # - :invalid if the collaborative_draft's author is not the current user.
21
+ #
22
+ # Returns nothing.
23
+ def call
24
+ return broadcast(:invalid) unless @collaborative_draft.open?
25
+ return broadcast(:invalid) unless @collaborative_draft.authored_by? @current_user
26
+
27
+ transaction do
28
+ @collaborative_draft.requesters.each do |requester_user|
29
+ RejectAccessToCollaborativeDraft.call(@collaborative_draft, current_user, requester_user)
30
+ end
31
+
32
+ @new_proposal = publish_collaborative_draft
33
+ broadcast(:invalid) unless @new_proposal
34
+ end
35
+
36
+ broadcast(:ok, @new_proposal)
37
+ end
38
+
39
+ attr_accessor :new_proposal
40
+
41
+ private
42
+
43
+ def publish_collaborative_draft
44
+ Decidim.traceability.update!(
45
+ @collaborative_draft,
46
+ @current_user,
47
+ state: "published",
48
+ published_at: Time.current
49
+ )
50
+ create_proposal
51
+ end
52
+
53
+ def create_proposal
54
+ proposal_form_params = ActionController::Parameters.new(
55
+ proposal: @collaborative_draft.as_json
56
+ )
57
+ proposal_form_params[:proposal][:category_id] = @collaborative_draft.category.id if @collaborative_draft.category
58
+ proposal_form_params[:proposal][:scope_id] = @collaborative_draft.scope.id if @collaborative_draft.scope
59
+ proposal_form = Decidim::Proposals::ProposalForm.from_params(
60
+ proposal_form_params
61
+ ).with_context(
62
+ current_user: @current_user,
63
+ current_organization: @current_user.organization,
64
+ current_component: @collaborative_draft.component,
65
+ current_participatory_space: @collaborative_draft.participatory_space
66
+ )
67
+
68
+ result = CreateProposal.call(proposal_form, @current_user, @collaborative_draft.coauthorships)
69
+ return publish_proposal(result[:ok]) if result[:ok]
70
+
71
+ false
72
+ end
73
+
74
+ def publish_proposal(new_proposal)
75
+ result = PublishProposal.call(new_proposal, @current_user)
76
+ return link_collaborative_draft_and_proposal(result[:ok]) if result[:ok]
77
+
78
+ false
79
+ end
80
+
81
+ def link_collaborative_draft_and_proposal(new_proposal)
82
+ @collaborative_draft.link_resources(new_proposal, "created_from_collaborative_draft")
83
+ new_proposal
84
+ end
85
+ end
86
+ end
87
+ end
@@ -24,6 +24,7 @@ module Decidim
24
24
 
25
25
  transaction do
26
26
  @proposal.update published_at: Time.current
27
+ increment_scores
27
28
  send_notification
28
29
  send_notification_to_participatory_space
29
30
  end
@@ -63,6 +64,12 @@ module Decidim
63
64
  end
64
65
  followers_ids
65
66
  end
67
+
68
+ def increment_scores
69
+ @proposal.authors.each do |author|
70
+ Decidim::Gamification.increment_score(author, :proposals)
71
+ end
72
+ end
66
73
  end
67
74
  end
68
75
  end