decidim-proposals 0.9.3 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -1
  3. data/app/assets/config/admin/decidim_proposals_manifest.js +1 -0
  4. data/app/assets/javascripts/decidim/proposals/admin/proposals.es6 +113 -0
  5. data/app/assets/javascripts/decidim/proposals/identity_selector_dialog.js.es6 +56 -0
  6. data/app/commands/decidim/proposals/admin/answer_proposal.rb +11 -5
  7. data/app/commands/decidim/proposals/admin/create_proposal.rb +25 -3
  8. data/app/commands/decidim/proposals/admin/create_proposal_note.rb +13 -8
  9. data/app/commands/decidim/proposals/admin/import_proposals.rb +83 -0
  10. data/app/commands/decidim/proposals/admin/update_proposal_category.rb +68 -0
  11. data/app/commands/decidim/proposals/create_proposal.rb +0 -12
  12. data/app/commands/decidim/proposals/endorse_proposal.rb +56 -0
  13. data/app/commands/decidim/proposals/publish_proposal.rb +60 -0
  14. data/app/commands/decidim/proposals/unendorse_proposal.rb +40 -0
  15. data/app/commands/decidim/proposals/update_proposal.rb +3 -3
  16. data/app/commands/decidim/proposals/vote_proposal.rb +1 -1
  17. data/app/commands/decidim/proposals/withdraw_proposal.rb +1 -1
  18. data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +1 -1
  19. data/app/controllers/decidim/proposals/admin/proposal_notes_controller.rb +2 -2
  20. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +50 -1
  21. data/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb +35 -0
  22. data/app/controllers/decidim/proposals/proposal_endorsements_controller.rb +56 -0
  23. data/app/controllers/decidim/proposals/proposals_controller.rb +82 -9
  24. data/app/events/decidim/proposals/admin/update_proposal_category_event.rb +11 -0
  25. data/app/events/decidim/proposals/creation_enabled_event.rb +8 -0
  26. data/app/events/decidim/proposals/endorsing_enabled_event.rb +8 -0
  27. data/app/events/decidim/proposals/proposal_endorsed_event.rb +29 -0
  28. data/app/events/decidim/proposals/publish_proposal_event.rb +21 -0
  29. data/app/events/decidim/proposals/voting_enabled_event.rb +8 -0
  30. data/app/forms/decidim/proposals/admin/proposal_form.rb +9 -2
  31. data/app/forms/decidim/proposals/admin/proposals_import_form.rb +60 -0
  32. data/app/forms/decidim/proposals/proposal_form.rb +16 -5
  33. data/app/helpers/decidim/proposals/application_helper.rb +1 -0
  34. data/app/helpers/decidim/proposals/proposal_endorsements_helper.rb +117 -0
  35. data/app/helpers/decidim/proposals/proposal_votes_helper.rb +13 -6
  36. data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +105 -0
  37. data/app/jobs/decidim/proposals/settings_change_job.rb +48 -0
  38. data/app/models/decidim/proposals/abilities/current_user_ability.rb +30 -8
  39. data/app/models/decidim/proposals/proposal.rb +38 -38
  40. data/app/models/decidim/proposals/proposal_endorsement.rb +31 -0
  41. data/app/models/decidim/proposals/proposal_note.rb +7 -0
  42. data/app/presenters/decidim/proposals/admin_log/proposal_note_presenter.rb +39 -0
  43. data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +47 -0
  44. data/app/presenters/decidim/proposals/admin_log/value_types/proposal_state_presenter.rb +16 -0
  45. data/app/queries/decidim/proposals/similar_proposals.rb +53 -0
  46. data/app/types/decidim/proposals/proposal_type.rb +34 -0
  47. data/app/types/decidim/proposals/proposals_type.rb +34 -0
  48. data/app/views/decidim/participatory_processes/participatory_process_groups/_highlighted_proposals.html.erb +8 -0
  49. data/app/views/decidim/participatory_processes/participatory_process_groups/_proposal.html.erb +27 -0
  50. data/app/views/decidim/participatory_spaces/_highlighted_proposals.html.erb +10 -0
  51. data/app/views/decidim/participatory_spaces/_proposal.html.erb +27 -0
  52. data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +15 -0
  53. data/app/views/decidim/proposals/admin/proposals/_js-callout.html.erb +6 -0
  54. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +63 -0
  55. data/app/views/decidim/proposals/admin/proposals/index.html.erb +12 -73
  56. data/app/views/decidim/proposals/admin/proposals/update_category.js.erb +25 -0
  57. data/app/views/decidim/proposals/admin/proposals_imports/new.html.erb +28 -0
  58. data/app/views/decidim/proposals/proposal_endorsements/_identity.html.erb +4 -0
  59. data/app/views/decidim/proposals/proposal_endorsements/identities.html.erb +12 -0
  60. data/app/views/decidim/proposals/proposal_endorsements/update_buttons_and_counters.js.erb +9 -0
  61. data/app/views/decidim/proposals/proposals/_endorsement_button.html.erb +11 -0
  62. data/app/views/decidim/proposals/proposals/_endorsement_identities_cabin.html.erb +13 -0
  63. data/app/views/decidim/proposals/proposals/_endorsement_xxs.html.erb +9 -0
  64. data/app/views/decidim/proposals/proposals/_endorsements_card_row.html.erb +22 -0
  65. data/app/views/decidim/proposals/proposals/_endorsements_count.html.erb +5 -0
  66. data/app/views/decidim/proposals/proposals/_endorsements_listing.html.erb +34 -0
  67. data/app/views/decidim/proposals/proposals/_proposal.html.erb +2 -2
  68. data/app/views/decidim/proposals/proposals/_proposal_preview.html.erb +36 -0
  69. data/app/views/decidim/proposals/proposals/_proposal_similar.html.erb +21 -0
  70. data/app/views/decidim/proposals/proposals/_vote_button.html.erb +8 -8
  71. data/app/views/decidim/proposals/proposals/_votes_count.html.erb +23 -6
  72. data/app/views/decidim/proposals/proposals/_voting_rules.html.erb +7 -3
  73. data/app/views/decidim/proposals/proposals/_wizard_aside.html.erb +16 -0
  74. data/app/views/decidim/proposals/proposals/_wizard_header.html.erb +31 -0
  75. data/app/views/decidim/proposals/proposals/compare.html.erb +19 -0
  76. data/app/views/decidim/proposals/proposals/edit_draft.html.erb +55 -0
  77. data/app/views/decidim/proposals/proposals/new.html.erb +7 -20
  78. data/app/views/decidim/proposals/proposals/preview.html.erb +18 -0
  79. data/app/views/decidim/proposals/proposals/show.html.erb +13 -4
  80. data/config/locales/ca.yml +156 -15
  81. data/config/locales/en.yml +156 -15
  82. data/config/locales/es.yml +157 -16
  83. data/config/locales/eu.yml +151 -7
  84. data/config/locales/fi.yml +151 -7
  85. data/config/locales/fr.yml +153 -9
  86. data/config/locales/gl.yml +151 -7
  87. data/config/locales/it.yml +151 -7
  88. data/config/locales/nl.yml +151 -7
  89. data/config/locales/pl.yml +148 -22
  90. data/config/locales/pt-BR.yml +151 -7
  91. data/config/locales/pt.yml +151 -7
  92. data/config/locales/ru.yml +0 -9
  93. data/config/locales/sv.yml +151 -7
  94. data/config/locales/uk.yml +87 -13
  95. data/db/migrate/20170307085300_migrate_proposal_reports_data_to_reports.rb +1 -1
  96. data/db/migrate/20171201115434_create_proposal_endorsements.rb +16 -0
  97. data/db/migrate/20171201122623_add_counter_cache_endorsements_to_proposals.rb +8 -0
  98. data/db/migrate/20171212102250_enable_pg_extensions.rb +7 -0
  99. data/db/migrate/20171220084719_add_published_at_to_proposals.rb +14 -0
  100. data/lib/decidim/proposals.rb +15 -0
  101. data/lib/decidim/proposals/admin_engine.rb +8 -0
  102. data/lib/decidim/proposals/commentable_proposal.rb +39 -0
  103. data/lib/decidim/proposals/engine.rb +69 -1
  104. data/lib/decidim/proposals/feature.rb +51 -6
  105. data/lib/decidim/proposals/test/factories.rb +78 -2
  106. data/lib/decidim/proposals/version.rb +1 -1
  107. metadata +76 -20
  108. data/app/events/decidim/proposals/create_proposal_event.rb +0 -9
@@ -35,7 +35,6 @@ module Decidim
35
35
  transaction do
36
36
  create_proposal
37
37
  create_attachment if process_attachments?
38
- send_notification
39
38
  end
40
39
 
41
40
  broadcast(:ok, proposal)
@@ -43,17 +42,6 @@ module Decidim
43
42
 
44
43
  private
45
44
 
46
- def send_notification
47
- return if proposal.author.blank?
48
-
49
- Decidim::EventsManager.publish(
50
- event: "decidim.events.proposals.proposal_created",
51
- event_class: Decidim::Proposals::CreateProposalEvent,
52
- resource: proposal,
53
- recipient_ids: proposal.author.followers.pluck(:id)
54
- )
55
- end
56
-
57
45
  attr_reader :form, :proposal, :attachment
58
46
 
59
47
  def create_proposal
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # A command with all the business logic when a user endorses a proposal.
6
+ class EndorseProposal < Rectify::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # proposal - A Decidim::Proposals::Proposal object.
10
+ # current_user - The current user.
11
+ # current_group_id- (optional) The current_grup that is endorsing the Proposal.
12
+ def initialize(proposal, current_user, current_group_id = nil)
13
+ @proposal = proposal
14
+ @current_user = current_user
15
+ @current_group_id = current_group_id
16
+ end
17
+
18
+ # Executes the command. Broadcasts these events:
19
+ #
20
+ # - :ok when everything is valid, together with the proposal vote.
21
+ # - :invalid if the form wasn't valid and we couldn't proceed.
22
+ #
23
+ # Returns nothing.
24
+ def call
25
+ endorsement = build_proposal_endorsement
26
+ if endorsement.save
27
+ notify_endorser_followers
28
+ broadcast(:ok, endorsement)
29
+ else
30
+ broadcast(:invalid)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def build_proposal_endorsement
37
+ endorsement = @proposal.endorsements.build(author: @current_user)
38
+ endorsement.user_group = @current_user.user_groups.verified.find(@current_group_id) if @current_group_id.present?
39
+ endorsement
40
+ end
41
+
42
+ def notify_endorser_followers
43
+ recipient_ids = @current_user.followers.pluck(:id)
44
+ Decidim::EventsManager.publish(
45
+ event: "decidim.events.proposals.proposal_endorsed",
46
+ event_class: Decidim::Proposals::ProposalEndorsedEvent,
47
+ resource: @proposal,
48
+ recipient_ids: recipient_ids.uniq,
49
+ extra: {
50
+ endorser_id: @current_user.id
51
+ }
52
+ )
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,60 @@
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 draft proposal.
6
+ class PublishProposal < Rectify::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # proposal - The proposal to publish.
10
+ # current_user - The current user.
11
+ def initialize(proposal, current_user)
12
+ @proposal = proposal
13
+ @current_user = current_user
14
+ end
15
+
16
+ # Executes the command. Broadcasts these events:
17
+ #
18
+ # - :ok when everything is valid and the proposal is published.
19
+ # - :invalid if the proposal's author is not the current user.
20
+ #
21
+ # Returns nothing.
22
+ def call
23
+ return broadcast(:invalid) if @proposal.author != @current_user
24
+
25
+ transaction do
26
+ @proposal.update published_at: Time.current
27
+ send_notification
28
+ send_notification_to_participatory_space
29
+ end
30
+
31
+ broadcast(:ok, @proposal)
32
+ end
33
+
34
+ private
35
+
36
+ def send_notification
37
+ return if @proposal.author.blank?
38
+
39
+ Decidim::EventsManager.publish(
40
+ event: "decidim.events.proposals.proposal_published",
41
+ event_class: Decidim::Proposals::PublishProposalEvent,
42
+ resource: @proposal,
43
+ recipient_ids: @proposal.author.followers.pluck(:id)
44
+ )
45
+ end
46
+
47
+ def send_notification_to_participatory_space
48
+ Decidim::EventsManager.publish(
49
+ event: "decidim.events.proposals.proposal_published",
50
+ event_class: Decidim::Proposals::PublishProposalEvent,
51
+ resource: @proposal,
52
+ recipient_ids: @proposal.participatory_space.followers.pluck(:id) - @proposal.author.followers.pluck(:id),
53
+ extra: {
54
+ participatory_space: true
55
+ }
56
+ )
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # A command with all the business logic when a user or organization unendorses a proposal.
6
+ class UnendorseProposal < Rectify::Command
7
+ # Public: Initializes the command.
8
+ #
9
+ # proposal - A Decidim::Proposals::Proposal object.
10
+ # current_user - The current user.
11
+ # current_group- (optional) The current_group that is unendorsing from the Proposal.
12
+ def initialize(proposal, current_user, current_group = nil)
13
+ @proposal = proposal
14
+ @current_user = current_user
15
+ @current_group = current_group
16
+ end
17
+
18
+ # Executes the command. Broadcasts these events:
19
+ #
20
+ # - :ok when everything is valid, together with the proposal.
21
+ # - :invalid if the form wasn't valid and we couldn't proceed.
22
+ #
23
+ # Returns nothing.
24
+ def call
25
+ destroy_proposal_endorsement
26
+ broadcast(:ok, @proposal)
27
+ end
28
+
29
+ private
30
+
31
+ def destroy_proposal_endorsement
32
+ query = @proposal.endorsements.where(
33
+ author: @current_user,
34
+ decidim_user_group_id: @current_group&.id
35
+ )
36
+ query.destroy_all
37
+ end
38
+ end
39
+ end
40
+ end
@@ -38,7 +38,7 @@ module Decidim
38
38
  attr_reader :form, :proposal, :current_user
39
39
 
40
40
  def update_proposal
41
- @proposal.update_attributes!(
41
+ @proposal.update!(
42
42
  title: form.title,
43
43
  body: form.body,
44
44
  category: form.category,
@@ -72,11 +72,11 @@ module Decidim
72
72
  end
73
73
 
74
74
  def current_user_proposals
75
- Proposal.where(author: current_user, feature: form.current_feature).where.not(id: proposal.id)
75
+ Proposal.where(author: current_user, feature: form.current_feature).published.where.not(id: proposal.id)
76
76
  end
77
77
 
78
78
  def user_group_proposals
79
- Proposal.where(user_group: user_group, feature: form.current_feature).where.not(id: proposal.id)
79
+ Proposal.where(user_group: user_group, feature: form.current_feature).published.where.not(id: proposal.id)
80
80
  end
81
81
  end
82
82
  end
@@ -20,7 +20,7 @@ module Decidim
20
20
  #
21
21
  # Returns nothing.
22
22
  def call
23
- return broadcast(:invalid) if @proposal.maximum_votes_reached?
23
+ return broadcast(:invalid) if @proposal.maximum_votes_reached? && !@proposal.can_accumulate_supports_beyond_threshold
24
24
 
25
25
  build_proposal_vote
26
26
  return broadcast(:invalid) unless vote.valid?
@@ -30,7 +30,7 @@ module Decidim
30
30
  private
31
31
 
32
32
  def change_proposal_state_to_withdrawn
33
- @proposal.update_attributes state: "withdrawn"
33
+ @proposal.update state: "withdrawn"
34
34
  end
35
35
  end
36
36
  end
@@ -32,7 +32,7 @@ module Decidim
32
32
  private
33
33
 
34
34
  def proposal
35
- @proposals ||= Proposal.where(feature: current_feature).find(params[:id])
35
+ @proposal ||= Proposal.where(feature: current_feature).find(params[:id])
36
36
  end
37
37
  end
38
38
  end
@@ -16,7 +16,7 @@ module Decidim
16
16
  authorize! :create, ProposalNote
17
17
  @form = form(ProposalNoteForm).from_params(params)
18
18
 
19
- CreateProposalNote.call(@form, proposal, current_user) do
19
+ CreateProposalNote.call(@form, proposal) do
20
20
  on(:ok) do
21
21
  flash[:notice] = I18n.t("proposal_notes.create.success", scope: "decidim.proposals.admin")
22
22
  redirect_to proposal_proposal_notes_path(proposal_id: proposal.id)
@@ -32,7 +32,7 @@ module Decidim
32
32
  private
33
33
 
34
34
  def proposal
35
- @proposals ||= Proposal.where(feature: current_feature).find(params[:proposal_id])
35
+ @proposal ||= Proposal.where(feature: current_feature).find(params[:proposal_id])
36
36
  end
37
37
  end
38
38
  end
@@ -32,10 +32,39 @@ module Decidim
32
32
  end
33
33
  end
34
34
 
35
+ def update_category
36
+ authorize! :update, Proposal
37
+ @proposal_ids = params[:proposal_ids]
38
+
39
+ Admin::UpdateProposalCategory.call(params[:category][:id], params[:proposal_ids]) do
40
+ on(:invalid_category) do
41
+ flash.now[:error] = I18n.t(
42
+ "proposals.update_category.select_a_category",
43
+ scope: "decidim.proposals.admin"
44
+ )
45
+ end
46
+
47
+ on(:invalid_proposal_ids) do
48
+ flash.now[:alert] = I18n.t(
49
+ "proposals.update_category.select_a_proposal",
50
+ scope: "decidim.proposals.admin"
51
+ )
52
+ end
53
+
54
+ on(:update_proposals_category) do
55
+ flash.now[:notice] = update_proposals_category_response_successful @response
56
+ flash.now[:alert] = update_proposals_category_response_errored @response
57
+ end
58
+ respond_to do |format|
59
+ format.js
60
+ end
61
+ end
62
+ end
63
+
35
64
  private
36
65
 
37
66
  def query
38
- @query ||= Proposal.where(feature: current_feature).ransack(params[:q])
67
+ @query ||= Proposal.where(feature: current_feature).published.ransack(params[:q])
39
68
  end
40
69
 
41
70
  def proposals
@@ -45,6 +74,26 @@ module Decidim
45
74
  def proposal
46
75
  @proposal ||= Proposal.where(feature: current_feature).find(params[:id])
47
76
  end
77
+
78
+ def update_proposals_category_response_successful(response)
79
+ return if response[:successful].blank?
80
+ I18n.t(
81
+ "proposals.update_category.success",
82
+ category: response[:category_name],
83
+ proposals: response[:successful].to_sentence,
84
+ scope: "decidim.proposals.admin"
85
+ )
86
+ end
87
+
88
+ def update_proposals_category_response_errored(response)
89
+ return if response[:errored].blank?
90
+ I18n.t(
91
+ "proposals.update_category.invalid",
92
+ category: response[:category_name],
93
+ proposals: response[:errored].to_sentence,
94
+ scope: "decidim.proposals.admin"
95
+ )
96
+ end
48
97
  end
49
98
  end
50
99
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ module Admin
6
+ class ProposalsImportsController < Admin::ApplicationController
7
+ def new
8
+ authorize! :manage, current_feature
9
+
10
+ @form = form(Admin::ProposalsImportForm).instance
11
+ end
12
+
13
+ def create
14
+ authorize! :manage, current_feature
15
+
16
+ @form = form(Admin::ProposalsImportForm).from_params(params)
17
+
18
+ authorize! :manage, @form.origin_feature
19
+
20
+ Admin::ImportProposals.call(@form) do
21
+ on(:ok) do |proposals|
22
+ flash[:notice] = I18n.t("proposals_imports.create.success", scope: "decidim.proposals.admin", number: proposals.length)
23
+ redirect_to EngineRouter.admin_proxy(current_feature).root_path
24
+ end
25
+
26
+ on(:invalid) do
27
+ flash.now[:alert] = I18n.t("proposals_imports.create.invalid", scope: "decidim.proposals.admin")
28
+ render action: "new"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # Exposes the proposal endorsement resource so that users can endorse proposals.
6
+ class ProposalEndorsementsController < Decidim::Proposals::ApplicationController
7
+ helper_method :proposal
8
+
9
+ before_action :authenticate_user!
10
+
11
+ def create
12
+ authorize! :endorse, proposal
13
+ @from_proposals_list = params[:from_proposals_list] == "true"
14
+ user_group_id = params[:user_group_id]
15
+
16
+ EndorseProposal.call(proposal, current_user, user_group_id) do
17
+ on(:ok) do
18
+ proposal.reload
19
+ render :update_buttons_and_counters
20
+ end
21
+
22
+ on(:invalid) do
23
+ render json: { error: I18n.t("proposal_endorsements.create.error", scope: "decidim.proposals") }, status: 422
24
+ end
25
+ end
26
+ end
27
+
28
+ def destroy
29
+ authorize! :unendorse, proposal
30
+ @from_proposals_list = params[:from_proposals_list] == "true"
31
+ user_group_id = params[:user_group_id]
32
+ user_group = current_user.user_groups.verified.find(user_group_id) if user_group_id
33
+
34
+ UnendorseProposal.call(proposal, current_user, user_group) do
35
+ on(:ok) do
36
+ proposal.reload
37
+ render :update_buttons_and_counters
38
+ end
39
+ end
40
+ end
41
+
42
+ def identities
43
+ authorize! :endorse, proposal
44
+
45
+ @user_verified_groups = current_user.user_groups.verified
46
+ render :identities, layout: false
47
+ end
48
+
49
+ private
50
+
51
+ def proposal
52
+ @proposal ||= Proposal.where(feature: current_feature).find(params[:proposal_id])
53
+ end
54
+ end
55
+ end
56
+ end
@@ -5,6 +5,7 @@ module Decidim
5
5
  # Exposes the proposal resource so users can view and create them.
6
6
  class ProposalsController < Decidim::Proposals::ApplicationController
7
7
  helper Decidim::WidgetUrlsHelper
8
+ helper ProposalWizardHelper
8
9
  include FormFactory
9
10
  include FilterResource
10
11
  include Orderable
@@ -12,10 +13,12 @@ module Decidim
12
13
 
13
14
  helper_method :geocoded_proposals
14
15
  before_action :authenticate_user!, only: [:new, :create]
16
+ before_action :ensure_is_draft, only: [:compare, :preview, :publish, :edit_draft, :update_draft]
15
17
 
16
18
  def index
17
19
  @proposals = search
18
20
  .results
21
+ .published
19
22
  .not_hidden
20
23
  .includes(:author)
21
24
  .includes(:category)
@@ -35,27 +38,32 @@ module Decidim
35
38
  end
36
39
 
37
40
  def show
38
- @proposal = Proposal.not_hidden.where(feature: current_feature).find(params[:id])
41
+ @proposal = Proposal.published.not_hidden.where(feature: current_feature).find(params[:id])
39
42
  @report_form = form(Decidim::ReportForm).from_params(reason: "spam")
40
43
  end
41
44
 
42
45
  def new
43
46
  authorize! :create, Proposal
44
-
45
- @form = form(ProposalForm).from_params(
46
- attachment: form(AttachmentForm).from_params({})
47
- )
47
+ @step = :step_1
48
+ if proposal_draft.present?
49
+ redirect_to edit_draft_proposal_path proposal_draft.id
50
+ else
51
+ @form = form(ProposalForm).from_params(
52
+ attachment: form(AttachmentForm).from_params({})
53
+ )
54
+ end
48
55
  end
49
56
 
50
57
  def create
51
58
  authorize! :create, Proposal
52
-
59
+ @step = :step_1
53
60
  @form = form(ProposalForm).from_params(params)
54
61
 
55
62
  CreateProposal.call(@form, current_user) do
56
63
  on(:ok) do |proposal|
57
64
  flash[:notice] = I18n.t("proposals.create.success", scope: "decidim")
58
- redirect_to Decidim::ResourceLocatorPresenter.new(proposal).path
65
+ compare_path = Decidim::ResourceLocatorPresenter.new(proposal).path + "/compare"
66
+ redirect_to compare_path
59
67
  end
60
68
 
61
69
  on(:invalid) do
@@ -65,8 +73,64 @@ module Decidim
65
73
  end
66
74
  end
67
75
 
76
+ def compare
77
+ @step = :step_2
78
+ @similar_proposals ||= Decidim::Proposals::SimilarProposals
79
+ .for(current_feature, @proposal)
80
+ .all
81
+
82
+ if @similar_proposals.blank?
83
+ flash[:notice] = I18n.t("proposals.proposals.compare.no_similars_found", scope: "decidim")
84
+ redirect_to preview_proposal_path(@proposal)
85
+ end
86
+ end
87
+
88
+ def preview
89
+ @step = :step_3
90
+ end
91
+
92
+ def publish
93
+ @step = :step_3
94
+ PublishProposal.call(@proposal, current_user) do
95
+ on(:ok) do |proposal|
96
+ flash[:notice] = I18n.t("proposals.publish.success", scope: "decidim")
97
+ redirect_to proposal_path(proposal)
98
+ end
99
+
100
+ on(:invalid) do
101
+ flash.now[:alert] = I18n.t("proposals.publish.error", scope: "decidim")
102
+ render :edit_draft
103
+ end
104
+ end
105
+ end
106
+
107
+ def edit_draft
108
+ @step = :step_1
109
+ authorize! :edit, Proposal
110
+
111
+ @form = form(ProposalForm).from_model(@proposal)
112
+ end
113
+
114
+ def update_draft
115
+ @step = :step_1
116
+ authorize! :edit, @proposal
117
+
118
+ @form = form(ProposalForm).from_params(params)
119
+ UpdateProposal.call(@form, current_user, @proposal) do
120
+ on(:ok) do |proposal|
121
+ flash[:notice] = I18n.t("proposals.update_draft.success", scope: "decidim")
122
+ redirect_to preview_proposal_path(proposal)
123
+ end
124
+
125
+ on(:invalid) do
126
+ flash.now[:alert] = I18n.t("proposals.update_draft.error", scope: "decidim")
127
+ render :edit_draft
128
+ end
129
+ end
130
+ end
131
+
68
132
  def edit
69
- @proposal = Proposal.not_hidden.where(feature: current_feature).find(params[:id])
133
+ @proposal = Proposal.published.not_hidden.where(feature: current_feature).find(params[:id])
70
134
  authorize! :edit, @proposal
71
135
 
72
136
  @form = form(ProposalForm).from_model(@proposal)
@@ -91,7 +155,7 @@ module Decidim
91
155
  end
92
156
 
93
157
  def withdraw
94
- @proposal = Proposal.not_hidden.where(feature: current_feature).find(params[:id])
158
+ @proposal = Proposal.published.not_hidden.where(feature: current_feature).find(params[:id])
95
159
  authorize! :withdraw, @proposal
96
160
 
97
161
  WithdrawProposal.call(@proposal, current_user) do
@@ -127,6 +191,15 @@ module Decidim
127
191
  related_to: ""
128
192
  }
129
193
  end
194
+
195
+ def proposal_draft
196
+ Proposal.not_hidden.where(feature: current_feature).find_by(published_at: nil)
197
+ end
198
+
199
+ def ensure_is_draft
200
+ @proposal = Proposal.not_hidden.where(feature: current_feature).find(params[:id])
201
+ redirect_to Decidim::ResourceLocatorPresenter.new(@proposal).path unless @proposal.draft?
202
+ end
130
203
  end
131
204
  end
132
205
  end