decidim-proposals 0.20.1 → 0.21.0

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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/decidim/proposals/admin/proposals.es6 +24 -11
  3. data/app/cells/decidim/proposals/cost_report/show.erb +35 -0
  4. data/app/cells/decidim/proposals/cost_report_cell.rb +42 -0
  5. data/app/cells/decidim/proposals/proposal_m_cell.rb +9 -1
  6. data/app/cells/decidim/proposals/proposal_tags/show.erb +12 -10
  7. data/app/cells/decidim/proposals/proposal_tags_cell.rb +5 -0
  8. data/app/commands/decidim/proposals/admin/answer_proposal.rb +24 -46
  9. data/app/commands/decidim/proposals/admin/assign_proposals_to_valuator.rb +61 -0
  10. data/app/commands/decidim/proposals/admin/create_proposal.rb +5 -0
  11. data/app/commands/decidim/proposals/admin/notify_proposal_answer.rb +85 -0
  12. data/app/commands/decidim/proposals/admin/publish_answers.rb +67 -0
  13. data/app/commands/decidim/proposals/admin/unassign_proposals_from_valuator.rb +62 -0
  14. data/app/commands/decidim/proposals/admin/update_proposal_scope.rb +75 -0
  15. data/app/controllers/concerns/decidim/proposals/admin/filterable.rb +82 -0
  16. data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +16 -6
  17. data/app/controllers/decidim/proposals/admin/proposal_notes_controller.rb +8 -9
  18. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +105 -29
  19. data/app/controllers/decidim/proposals/admin/valuation_assignments_controller.rb +58 -0
  20. data/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +19 -3
  21. data/app/controllers/decidim/proposals/proposals_controller.rb +42 -7
  22. data/app/controllers/decidim/proposals/versions_controller.rb +4 -1
  23. data/app/events/decidim/proposals/admin/update_proposal_scope_event.rb +11 -0
  24. data/app/forms/decidim/proposals/admin/proposal_answer_form.rb +27 -2
  25. data/app/forms/decidim/proposals/admin/valuation_assignment_form.rb +37 -0
  26. data/app/forms/decidim/proposals/proposal_wizard_create_step_form.rb +8 -0
  27. data/app/helpers/decidim/proposals/admin/filterable_helper.rb +17 -0
  28. data/app/helpers/decidim/proposals/admin/proposal_bulk_actions_helper.rb +35 -0
  29. data/app/helpers/decidim/proposals/admin/proposal_rankings_helper.rb +63 -0
  30. data/app/helpers/decidim/proposals/admin/proposals_helper.rb +122 -0
  31. data/app/helpers/decidim/proposals/application_helper.rb +36 -25
  32. data/app/helpers/decidim/proposals/collaborative_draft_helper.rb +9 -9
  33. data/app/helpers/decidim/proposals/proposal_cells_helper.rb +1 -1
  34. data/app/helpers/decidim/proposals/proposals_helper.rb +18 -0
  35. data/app/models/decidim/proposals/proposal.rb +163 -16
  36. data/app/models/decidim/proposals/valuation_assignment.rb +24 -0
  37. data/app/permissions/decidim/proposals/admin/permissions.rb +77 -11
  38. data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +1 -1
  39. data/app/presenters/decidim/proposals/admin_log/valuation_assignment_presenter.rb +51 -0
  40. data/app/presenters/decidim/proposals/admin_log/value_types/valuator_role_user_presenter.rb +19 -0
  41. data/app/presenters/decidim/proposals/collaborative_draft_presenter.rb +2 -28
  42. data/app/presenters/decidim/proposals/log/valuation_assignment_presenter.rb +22 -0
  43. data/app/presenters/decidim/proposals/proposal_presenter.rb +26 -1
  44. data/app/services/decidim/proposals/collaborative_draft_search.rb +18 -10
  45. data/app/services/decidim/proposals/proposal_search.rb +33 -40
  46. data/app/types/decidim/proposals/proposal_input_filter.rb +29 -0
  47. data/app/types/decidim/proposals/proposal_input_sort.rb +28 -0
  48. data/app/types/decidim/proposals/proposal_type.rb +35 -4
  49. data/app/types/decidim/proposals/proposals_type.rb +14 -17
  50. data/app/views/decidim/proposals/admin/proposal_answers/_form.html.erb +35 -0
  51. data/app/views/decidim/proposals/admin/proposal_notes/_form.html.erb +1 -1
  52. data/app/views/decidim/proposals/admin/proposal_notes/_proposal_notes.html.erb +1 -1
  53. data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +8 -2
  54. data/app/views/decidim/proposals/admin/proposals/_form.html.erb +1 -1
  55. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +25 -17
  56. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_assign_to_valuator.html.erb +15 -0
  57. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_dropdown.html.erb +21 -1
  58. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_publish_answers.html.erb +14 -0
  59. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_scope-change.html.erb +25 -0
  60. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_unassign_from_valuator.html.erb +15 -0
  61. data/app/views/decidim/proposals/admin/proposals/index.html.erb +16 -7
  62. data/app/views/decidim/proposals/admin/proposals/publish_answers.js.erb +12 -0
  63. data/app/views/decidim/proposals/admin/proposals/show.html.erb +186 -0
  64. data/app/views/decidim/proposals/admin/proposals/update_category.js.erb +3 -2
  65. data/app/views/decidim/proposals/admin/proposals/update_scope.js.erb +27 -0
  66. data/app/views/decidim/proposals/collaborative_drafts/_filters.html.erb +3 -3
  67. data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +1 -1
  68. data/app/views/decidim/proposals/proposals/_filters.html.erb +12 -12
  69. data/app/views/decidim/proposals/proposals/_proposal_badge.html.erb +1 -4
  70. data/app/views/decidim/proposals/proposals/_proposal_preview.html.erb +1 -1
  71. data/app/views/decidim/proposals/proposals/_vote_button.html.erb +1 -1
  72. data/app/views/decidim/proposals/proposals/index.html.erb +1 -1
  73. data/app/views/decidim/proposals/proposals/new.html.erb +1 -1
  74. data/app/views/decidim/proposals/proposals/show.html.erb +17 -23
  75. data/config/locales/ar.yml +69 -17
  76. data/config/locales/ca.yml +113 -18
  77. data/config/locales/cs.yml +123 -31
  78. data/config/locales/de.yml +38 -18
  79. data/config/locales/el.yml +1 -0
  80. data/config/locales/en.yml +112 -17
  81. data/config/locales/es-MX.yml +112 -17
  82. data/config/locales/es-PY.yml +112 -17
  83. data/config/locales/es.yml +113 -18
  84. data/config/locales/eu.yml +38 -18
  85. data/config/locales/fi-plain.yml +113 -18
  86. data/config/locales/fi.yml +113 -18
  87. data/config/locales/fr.yml +38 -18
  88. data/config/locales/gl.yml +38 -18
  89. data/config/locales/hu.yml +112 -17
  90. data/config/locales/id-ID.yml +38 -18
  91. data/config/locales/is-IS.yml +25 -15
  92. data/config/locales/it.yml +38 -18
  93. data/config/locales/nl.yml +43 -18
  94. data/config/locales/no.yml +66 -18
  95. data/config/locales/pl.yml +38 -18
  96. data/config/locales/pt-BR.yml +39 -19
  97. data/config/locales/pt.yml +39 -19
  98. data/config/locales/ru.yml +25 -17
  99. data/config/locales/sv.yml +39 -18
  100. data/config/locales/tr-TR.yml +38 -18
  101. data/config/locales/uk.yml +25 -17
  102. data/db/migrate/20200203111239_add_proposal_valuation_assignments.rb +12 -0
  103. data/db/migrate/20200210135152_add_costs_to_proposals.rb +9 -0
  104. data/db/migrate/20200212120110_sync_proposals_state_with_amendments_state.rb +28 -0
  105. data/db/migrate/20200227175922_add_state_published_at_to_proposals.rb +7 -0
  106. data/db/migrate/20200306123652_publish_existing_proposals_state.rb +15 -0
  107. data/lib/decidim/proposals.rb +1 -0
  108. data/lib/decidim/proposals/admin_engine.rb +7 -3
  109. data/lib/decidim/proposals/component.rb +39 -19
  110. data/lib/decidim/proposals/engine.rb +1 -1
  111. data/lib/decidim/proposals/test/factories.rb +55 -0
  112. data/lib/decidim/proposals/valuatable.rb +21 -0
  113. data/lib/decidim/proposals/version.rb +1 -1
  114. metadata +53 -36
  115. data/app/views/decidim/proposals/admin/proposal_answers/edit.html.erb +0 -22
  116. data/app/views/decidim/proposals/admin/proposal_notes/index.html.erb +0 -3
  117. data/app/views/decidim/proposals/admin/shared/_info_proposal.html.erb +0 -20
  118. data/app/views/decidim/proposals/proposal_widgets/show.html.erb +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 46488da07b1fcedae339ac996a3dc7ad7630921508b2005fba0b0b63bbbfa011
4
- data.tar.gz: fc7d5e4b59980364fe7dd953c03f960f88d2787c9b45ef1020b6902e4cd876bd
3
+ metadata.gz: 2e2beae792f2e71369afee5770fce30f6ec7b4b2baf3e89da9cd905c2c99a1e9
4
+ data.tar.gz: b4faeabfaa6b595a48acb8fb0e320bb404c746da7fb1fe0229b8888efa39b0ad
5
5
  SHA512:
6
- metadata.gz: ae9957d68d71430799891dfd79205582cc36ee916803ec3842aa0dcae7189ba0d95a726147b731717f933447e40c203816311661201fd9fbdf6be25091a890b9
7
- data.tar.gz: cab36522bfa9fdbcd6f66439ea39b83a191f0a3a67ce2d63a5d293c0bb6af83abfa0374a65cebdcde921ac882af640c9b8950e197673e1af7db65cf2e9f74b0f
6
+ metadata.gz: 18a69a6b8e6ce11c8a91acb8f6370111140612b3e33f62d73de4424d2834691c2f84074adac3c63fa77049954c4285f66876a12748216c4e2ddba55888253a8e
7
+ data.tar.gz: 2dc55deb9e785df8f31b8b3fc940a09049688b2fa96ec38ab55687428edd2b977433e186e6cebafdf4d98205687d65c89c758a39e92d44d6cf11d30657ae7308
@@ -4,18 +4,31 @@ $(document).ready(function () {
4
4
  return $('.table-list .js-check-all-proposal:checked').length
5
5
  }
6
6
 
7
+ let selectedProposalsNotPublishedAnswerCount = function() {
8
+ return $('.table-list [data-published-state=false] .js-check-all-proposal:checked').length
9
+ }
10
+
7
11
  window.selectedProposalsCountUpdate = function() {
8
- if(selectedProposalsCount() == 0){
12
+ const selectedProposals = selectedProposalsCount();
13
+ const selectedProposalsNotPublishedAnswer = selectedProposalsNotPublishedAnswerCount();
14
+ if(selectedProposals == 0){
9
15
  $("#js-selected-proposals-count").text("")
10
16
  } else {
11
- $("#js-selected-proposals-count").text(selectedProposalsCount());
17
+ $("#js-selected-proposals-count").text(selectedProposals);
12
18
  }
13
19
 
14
- if(selectedProposalsCount() >= 2) {
20
+ if(selectedProposals >= 2) {
15
21
  $('button[data-action="merge-proposals"]').parent().show();
16
22
  } else {
17
23
  $('button[data-action="merge-proposals"]').parent().hide();
18
24
  }
25
+
26
+ if(selectedProposalsNotPublishedAnswer > 0) {
27
+ $('button[data-action="publish-answers"]').parent().show();
28
+ $('#js-form-publish-answers-number').text(selectedProposalsNotPublishedAnswer);
29
+ } else {
30
+ $('button[data-action="publish-answers"]').parent().hide();
31
+ }
19
32
  }
20
33
 
21
34
  let showBulkActionsButton = function() {
@@ -24,7 +37,7 @@ $(document).ready(function () {
24
37
  }
25
38
  }
26
39
 
27
- let hideBulkActionsButton = function(force = false) {
40
+ window.hideBulkActionsButton = function(force = false) {
28
41
  if(selectedProposalsCount() == 0 || force == true){
29
42
  $("#js-bulk-actions-button").addClass('hide');
30
43
  $("#js-bulk-actions-dropdown").removeClass('is-open');
@@ -35,12 +48,12 @@ $(document).ready(function () {
35
48
  $("#js-other-actions-wrapper").removeClass('hide');
36
49
  }
37
50
 
38
- let hideOtherActionsButtons = function() {
51
+ window.hideOtherActionsButtons = function() {
39
52
  $("#js-other-actions-wrapper").addClass('hide');
40
53
  }
41
54
 
42
55
  window.hideBulkActionForms = function() {
43
- return $(".js-bulk-action-form").addClass('hide');
56
+ $(".js-bulk-action-form").addClass('hide');
44
57
  }
45
58
 
46
59
  if ($('.js-bulk-action-form').length) {
@@ -57,8 +70,8 @@ $(document).ready(function () {
57
70
  })
58
71
 
59
72
  $(`#js-${action}-actions`).removeClass('hide');
60
- hideBulkActionsButton(true);
61
- hideOtherActionsButtons();
73
+ window.hideBulkActionsButton(true);
74
+ window.hideOtherActionsButtons();
62
75
  }
63
76
  })
64
77
 
@@ -71,7 +84,7 @@ $(document).ready(function () {
71
84
  showBulkActionsButton();
72
85
  } else {
73
86
  $(".js-check-all-proposal").closest('tr').removeClass('selected');
74
- hideBulkActionsButton();
87
+ window.hideBulkActionsButton();
75
88
  }
76
89
 
77
90
  selectedProposalsCountUpdate();
@@ -96,12 +109,12 @@ $(document).ready(function () {
96
109
  showBulkActionsButton();
97
110
  $(this).closest('tr').addClass('selected');
98
111
  } else {
99
- hideBulkActionsButton();
112
+ window.hideBulkActionsButton();
100
113
  $(this).closest('tr').removeClass('selected');
101
114
  }
102
115
 
103
116
  if ($('.js-check-all-proposal:checked').length === 0) {
104
- hideBulkActionsButton();
117
+ window.hideBulkActionsButton();
105
118
  }
106
119
 
107
120
  $('.js-bulk-action-form').find(".js-proposal-id-"+proposal_id).prop('checked', checked);
@@ -0,0 +1,35 @@
1
+ <div id="proposal-costs" class="card card--secondary" data-toggler=".expanded-text">
2
+ <div class="card__content">
3
+ <div class="mb-s">
4
+ <div class="data-title">
5
+ <h3 class="data-title__over">
6
+ <%= t("decidim.proposals.proposals.show.estimated_cost") %>
7
+ </h3>
8
+ <div>
9
+ <strong class="data-title__main">
10
+ <%= cost %>
11
+ </strong>
12
+ </div>
13
+ <div class="data-title__sub">
14
+ <%= execution_period %>
15
+ </div>
16
+ </div>
17
+ </div>
18
+ <div id="execution-cost-short" class="text-toggle__short">
19
+ <%= cost_report_short %>
20
+ <% if needs_text_toggle? %>
21
+ <button class="muted-link" data-toggle="proposal-costs">
22
+ <%= t("decidim.proposals.proposals.show.read_more") %>
23
+ </button>
24
+ <% end %>
25
+ </div>
26
+ <% if needs_text_toggle? %>
27
+ <div id="execution-cost-long" class="text-toggle__long">
28
+ <%= cost_report %>
29
+ <button class="muted-link" data-toggle="proposal-costs">
30
+ <%= t("decidim.proposals.proposals.show.read_less") %>
31
+ </button>
32
+ </div>
33
+ <% end %>
34
+ </div>
35
+ </div>
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cell/partial"
4
+
5
+ module Decidim
6
+ module Proposals
7
+ # This cell renders the cost report for a proposal.
8
+ class CostReportCell < Decidim::ViewModel
9
+ include ActionView::Helpers::NumberHelper
10
+ include Decidim::SanitizeHelper
11
+ include Decidim::LayoutHelper
12
+ include ProposalCellsHelper
13
+
14
+ private
15
+
16
+ def cost
17
+ number_to_currency(model.cost)
18
+ end
19
+
20
+ def cost_report
21
+ decidim_sanitize(translated_attribute(model.cost_report).html_safe)
22
+ end
23
+
24
+ def needs_text_toggle?
25
+ cost_report != cost_report_short
26
+ end
27
+
28
+ def cost_report_short
29
+ decidim_sanitize(
30
+ html_truncate(
31
+ translated_attribute(model.cost_report).html_safe,
32
+ length: 200
33
+ )
34
+ )
35
+ end
36
+
37
+ def execution_period
38
+ decidim_sanitize(translated_attribute(model.execution_period).html_safe)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -27,7 +27,7 @@ module Decidim
27
27
  end
28
28
 
29
29
  def has_badge?
30
- answered? || withdrawn? || emendation?
30
+ published_state? || withdrawn?
31
31
  end
32
32
 
33
33
  def has_link_to_resource?
@@ -94,6 +94,14 @@ module Decidim
94
94
  def can_be_followed?
95
95
  !model.withdrawn?
96
96
  end
97
+
98
+ def has_image?
99
+ model.attachments.first.present? && model.attachments.first.file.content_type.start_with?("image") && model.component.settings.allow_card_image
100
+ end
101
+
102
+ def resource_image_path
103
+ model.attachments.first.url if has_image?
104
+ end
97
105
  end
98
106
  end
99
107
  end
@@ -1,25 +1,27 @@
1
1
  <figure>
2
- <figcaption class="text-uppercase">
3
- <strong>
4
- <%= t("filed_as", scope: "decidim.proposals.proposals.tags") %>
5
- </strong>
6
- </figcaption>
7
-
8
- <ul>
2
+ <ul class="tags tags--proposal tags--list">
9
3
  <% if category.present? %>
10
4
  <li>
11
- <%= link_to translated_attribute(category.name), resource_locator(model).index(filter: { category_id: category.id }) %>
5
+ <%= link_to translated_attribute(category.name), resource_locator(model).index(filter: { category_id: [category.id.to_s] }) %>
12
6
  <% if previous_category.present? && show_previous_category? %>
13
7
  &nbsp;
14
8
  <small class="text-small">
15
- <%= t("changed_from", scope: "decidim.proposals.proposals.tags", previous_category: "#{previous_category.translated_name}").html_safe %>
9
+ <%= t("changed_from", scope: "decidim.proposals.proposals.tags", previous_name: "#{previous_category.translated_name}").html_safe %>
16
10
  </small>
17
11
  <% end %>
18
12
  </li>
19
13
  <% end %>
20
14
 
21
15
  <% if has_visible_scopes?(model) %>
22
- <li><%= link_to translated_attribute(scope.name), resource_locator(model).index(filter: { scope_id: [scope.id] }) %></li>
16
+ <li>
17
+ <%= link_to translated_attribute(scope.name), resource_locator(model).index(filter: { scope_id: [scope.id] }) %>
18
+ <% if previous_scope.present? && show_previous_scope? %>
19
+ &nbsp;
20
+ <small class="text-small">
21
+ <%= t("changed_from", scope: "decidim.proposals.proposals.tags", previous_name: "#{translated_attribute(previous_scope.name)}").html_safe %>
22
+ </small>
23
+ <% end %>
24
+ </li>
23
25
  <% end %>
24
26
  </ul>
25
27
  </figure>
@@ -11,6 +11,7 @@ module Decidim
11
11
  property :category
12
12
  property :previous_category
13
13
  property :scope
14
+ property :previous_scope
14
15
 
15
16
  def show
16
17
  render if has_category_or_scopes?
@@ -22,6 +23,10 @@ module Decidim
22
23
  options[:show_previous_category].to_s != "false"
23
24
  end
24
25
 
26
+ def show_previous_scope?
27
+ options[:show_previous_scope].to_s != "false"
28
+ end
29
+
25
30
  def has_category_or_scopes?
26
31
  category.present? || has_visible_scopes?(model)
27
32
  end
@@ -23,16 +23,19 @@ module Decidim
23
23
  def call
24
24
  return broadcast(:invalid) if form.invalid?
25
25
 
26
- answer_proposal
27
- notify_followers
28
- increment_score
26
+ store_initial_proposal_state
27
+
28
+ transaction do
29
+ answer_proposal
30
+ notify_proposal_answer
31
+ end
29
32
 
30
33
  broadcast(:ok)
31
34
  end
32
35
 
33
36
  private
34
37
 
35
- attr_reader :form, :proposal
38
+ attr_reader :form, :proposal, :initial_has_state_published, :initial_state
36
39
 
37
40
  def answer_proposal
38
41
  Decidim.traceability.perform_action!(
@@ -40,55 +43,30 @@ module Decidim
40
43
  proposal,
41
44
  form.current_user
42
45
  ) do
43
- proposal.update!(
44
- state: @form.state,
45
- answer: @form.answer,
46
- answered_at: Time.current
47
- )
48
- end
49
- end
46
+ attributes = {
47
+ state: form.state,
48
+ answer: form.answer,
49
+ answered_at: Time.current,
50
+ cost: form.cost,
51
+ cost_report: form.cost_report,
52
+ execution_period: form.execution_period
53
+ }
50
54
 
51
- def notify_followers
52
- return if (proposal.previous_changes.keys & %w(state)).empty?
55
+ attributes[:state_published_at] = Time.current if !initial_has_state_published && form.publish_answer?
53
56
 
54
- if proposal.accepted?
55
- publish_event(
56
- "decidim.events.proposals.proposal_accepted",
57
- Decidim::Proposals::AcceptedProposalEvent
58
- )
59
- elsif proposal.rejected?
60
- publish_event(
61
- "decidim.events.proposals.proposal_rejected",
62
- Decidim::Proposals::RejectedProposalEvent
63
- )
64
- elsif proposal.evaluating?
65
- publish_event(
66
- "decidim.events.proposals.proposal_evaluating",
67
- Decidim::Proposals::EvaluatingProposalEvent
68
- )
57
+ proposal.update!(attributes)
69
58
  end
70
59
  end
71
60
 
72
- def publish_event(event, event_class)
73
- Decidim::EventsManager.publish(
74
- event: event,
75
- event_class: event_class,
76
- resource: proposal,
77
- affected_users: proposal.notifiable_identities,
78
- followers: proposal.followers - proposal.notifiable_identities
79
- )
80
- end
61
+ def notify_proposal_answer
62
+ return if !initial_has_state_published && !form.publish_answer?
81
63
 
82
- def increment_score
83
- return unless proposal.accepted?
64
+ NotifyProposalAnswer.call(proposal, initial_state)
65
+ end
84
66
 
85
- proposal.coauthorships.find_each do |coauthorship|
86
- if coauthorship.user_group
87
- Decidim::Gamification.increment_score(coauthorship.user_group, :accepted_proposals)
88
- else
89
- Decidim::Gamification.increment_score(coauthorship.author, :accepted_proposals)
90
- end
91
- end
67
+ def store_initial_proposal_state
68
+ @initial_has_state_published = proposal.published_state?
69
+ @initial_state = proposal.state
92
70
  end
93
71
  end
94
72
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ module Admin
6
+ # A command with all the business logic to assign proposals to a given
7
+ # valuator.
8
+ class AssignProposalsToValuator < Rectify::Command
9
+ # Public: Initializes the command.
10
+ #
11
+ # form - A form object with the params.
12
+ def initialize(form)
13
+ @form = form
14
+ end
15
+
16
+ # Executes the command. Broadcasts these events:
17
+ #
18
+ # - :ok when everything is valid.
19
+ # - :invalid if the form wasn't valid and we couldn't proceed.
20
+ #
21
+ # Returns nothing.
22
+ def call
23
+ return broadcast(:invalid) unless form.valid?
24
+
25
+ assign_proposals
26
+ broadcast(:ok)
27
+ rescue ActiveRecord::RecordInvalid
28
+ broadcast(:invalid)
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :form
34
+
35
+ def assign_proposals
36
+ transaction do
37
+ form.proposals.flat_map do |proposal|
38
+ find_assignment(proposal) || assign_proposal(proposal)
39
+ end
40
+ end
41
+ end
42
+
43
+ def find_assignment(proposal)
44
+ Decidim::Proposals::ValuationAssignment.find_by(
45
+ proposal: proposal,
46
+ valuator_role: form.valuator_role
47
+ )
48
+ end
49
+
50
+ def assign_proposal(proposal)
51
+ Decidim.traceability.create!(
52
+ Decidim::Proposals::ValuationAssignment,
53
+ form.current_user,
54
+ proposal: proposal,
55
+ valuator_role: form.valuator_role
56
+ )
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -39,6 +39,7 @@ module Decidim
39
39
  create_proposal
40
40
  create_attachment if process_attachments?
41
41
  create_gallery if process_gallery?
42
+ link_author_meeeting if form.created_in_meeting?
42
43
  send_notification
43
44
  end
44
45
 
@@ -73,6 +74,10 @@ module Decidim
73
74
  }
74
75
  end
75
76
 
77
+ def link_author_meeeting
78
+ proposal.link_resources(form.author, "proposals_from_meeting")
79
+ end
80
+
76
81
  def send_notification
77
82
  Decidim::EventsManager.publish(
78
83
  event: "decidim.events.proposals.proposal_published",
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ module Admin
6
+ # A command to notify about the change of the published state for a proposal.
7
+ class NotifyProposalAnswer < Rectify::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # proposal - The proposal to write the answer for.
11
+ # initial_state - The proposal state before the current process.
12
+ def initialize(proposal, initial_state)
13
+ @proposal = proposal
14
+ @initial_state = initial_state.to_s
15
+ end
16
+
17
+ # Executes the command. Broadcasts these events:
18
+ #
19
+ # - :noop when the answer is not published or the state didn't changed.
20
+ # - :ok when everything is valid.
21
+ #
22
+ # Returns nothing.
23
+ def call
24
+ if proposal.published_state? && state_changed?
25
+ transaction do
26
+ increment_score
27
+ notify_followers
28
+ end
29
+ end
30
+
31
+ broadcast(:ok)
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :proposal, :initial_state
37
+
38
+ def state_changed?
39
+ initial_state != proposal.state.to_s
40
+ end
41
+
42
+ def notify_followers
43
+ if proposal.accepted?
44
+ publish_event(
45
+ "decidim.events.proposals.proposal_accepted",
46
+ Decidim::Proposals::AcceptedProposalEvent
47
+ )
48
+ elsif proposal.rejected?
49
+ publish_event(
50
+ "decidim.events.proposals.proposal_rejected",
51
+ Decidim::Proposals::RejectedProposalEvent
52
+ )
53
+ elsif proposal.evaluating?
54
+ publish_event(
55
+ "decidim.events.proposals.proposal_evaluating",
56
+ Decidim::Proposals::EvaluatingProposalEvent
57
+ )
58
+ end
59
+ end
60
+
61
+ def publish_event(event, event_class)
62
+ Decidim::EventsManager.publish(
63
+ event: event,
64
+ event_class: event_class,
65
+ resource: proposal,
66
+ affected_users: proposal.notifiable_identities,
67
+ followers: proposal.followers - proposal.notifiable_identities
68
+ )
69
+ end
70
+
71
+ def increment_score
72
+ if proposal.accepted?
73
+ proposal.coauthorships.find_each do |coauthorship|
74
+ Decidim::Gamification.increment_score(coauthorship.user_group || coauthorship.author, :accepted_proposals)
75
+ end
76
+ elsif initial_state == "accepted"
77
+ proposal.coauthorships.find_each do |coauthorship|
78
+ Decidim::Gamification.decrement_score(coauthorship.user_group || coauthorship.author, :accepted_proposals)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end