decidim-proposals 0.14.4 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -0
- data/app/assets/images/decidim/gamification/badges/accepted_proposals.svg +194 -104
- data/app/assets/images/decidim/gamification/badges/proposals.svg +192 -108
- data/app/assets/javascripts/decidim/proposals/admin/proposals.es6 +25 -20
- data/app/cells/decidim/proposals/proposal_activity_cell.rb +19 -0
- data/app/commands/decidim/proposals/admin/answer_proposal.rb +6 -2
- data/app/commands/decidim/proposals/admin/create_proposal.rb +4 -4
- data/app/commands/decidim/proposals/admin/import_participatory_text.rb +49 -0
- data/app/commands/decidim/proposals/admin/import_proposals.rb +7 -21
- data/app/commands/decidim/proposals/admin/merge_proposals.rb +68 -0
- data/app/commands/decidim/proposals/admin/publish_participatory_text.rb +65 -0
- data/app/commands/decidim/proposals/admin/split_proposals.rb +67 -0
- data/app/commands/decidim/proposals/admin/update_proposal.rb +67 -0
- data/app/commands/decidim/proposals/create_collaborative_draft.rb +19 -14
- data/app/commands/decidim/proposals/create_proposal.rb +4 -2
- data/app/commands/decidim/proposals/endorse_proposal.rb +5 -1
- data/app/commands/decidim/proposals/publish_proposal.rb +15 -3
- data/app/commands/decidim/proposals/unvote_proposal.rb +34 -3
- data/app/commands/decidim/proposals/vote_proposal.rb +32 -2
- data/app/controllers/decidim/proposals/admin/participatory_texts_controller.rb +62 -0
- data/app/controllers/decidim/proposals/admin/proposals_controller.rb +28 -1
- data/app/controllers/decidim/proposals/admin/proposals_merges_controller.rb +27 -0
- data/app/controllers/decidim/proposals/admin/proposals_splits_controller.rb +27 -0
- data/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +0 -1
- data/app/controllers/decidim/proposals/proposal_endorsements_controller.rb +6 -2
- data/app/controllers/decidim/proposals/proposal_votes_controller.rb +15 -0
- data/app/controllers/decidim/proposals/proposals_controller.rb +1 -1
- data/app/forms/decidim/proposals/admin/import_participatory_text_form.rb +28 -0
- data/app/forms/decidim/proposals/admin/preview_participatory_text_form.rb +21 -0
- data/app/forms/decidim/proposals/admin/proposal_form.rb +4 -1
- data/app/forms/decidim/proposals/admin/proposals_fork_form.rb +57 -0
- data/app/forms/decidim/proposals/admin/proposals_merge_form.rb +13 -0
- data/app/forms/decidim/proposals/admin/proposals_split_form.rb +12 -0
- data/app/helpers/decidim/proposals/application_helper.rb +23 -0
- data/app/helpers/decidim/proposals/map_helper.rb +1 -1
- data/app/helpers/decidim/proposals/participatory_texts_helper.rb +18 -0
- data/app/helpers/decidim/proposals/proposal_endorsements_helper.rb +1 -1
- data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +2 -1
- data/app/jobs/decidim/proposals/notify_proposals_mentioned_job.rb +3 -4
- data/app/models/decidim/proposals/participatory_text.rb +13 -0
- data/app/models/decidim/proposals/proposal.rb +31 -9
- data/app/models/decidim/proposals/proposal_vote.rb +21 -1
- data/app/permissions/decidim/proposals/admin/permissions.rb +30 -0
- data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +5 -1
- data/app/presenters/decidim/proposals/log/resource_presenter.rb +18 -0
- data/app/presenters/decidim/proposals/official_author_presenter.rb +4 -0
- data/app/queries/decidim/proposals/metrics/accepted_proposals_metric_manage.rb +29 -0
- data/app/queries/decidim/proposals/metrics/proposals_metric_manage.rb +53 -0
- data/app/queries/decidim/proposals/metrics/votes_metric_manage.rb +57 -0
- data/app/services/decidim/proposals/proposal_builder.rb +72 -0
- data/app/services/decidim/proposals/proposal_search.rb +2 -2
- data/app/views/decidim/proposals/admin/participatory_texts/_article-preview.html.erb +13 -0
- data/app/views/decidim/proposals/admin/participatory_texts/_bulk-actions.html.erb +1 -0
- data/app/views/decidim/proposals/admin/participatory_texts/index.html.erb +43 -0
- data/app/views/decidim/proposals/admin/participatory_texts/new_import.html.erb +39 -0
- data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +7 -2
- data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +4 -0
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_dropdown.html.erb +36 -0
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_merge.html.erb +15 -0
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_recategorize.html.erb +15 -0
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_split.html.erb +15 -0
- data/app/views/decidim/proposals/admin/proposals/edit.html.erb +7 -0
- data/app/views/decidim/proposals/admin/proposals/index.html.erb +2 -2
- data/app/views/decidim/proposals/collaborative_drafts/compare.html.erb +2 -2
- data/app/views/decidim/proposals/collaborative_drafts/complete.html.erb +1 -1
- data/app/views/decidim/proposals/collaborative_drafts/show.html.erb +1 -1
- data/app/views/decidim/proposals/proposal_endorsements/_identity.html.erb +5 -1
- data/app/views/decidim/proposals/proposal_endorsements/update_buttons_and_counters.js.erb +1 -1
- data/app/views/decidim/proposals/proposal_votes/update_buttons_and_counters.js.erb +13 -4
- data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +2 -2
- data/app/views/decidim/proposals/proposals/_endorsement_identities_cabin.html.erb +1 -1
- data/app/views/decidim/proposals/proposals/_proposal_similar.html.erb +1 -1
- data/app/views/decidim/proposals/proposals/_voting_rules.html.erb +15 -4
- data/app/views/decidim/proposals/proposals/new.html.erb +1 -1
- data/config/locales/ca.yml +72 -4
- data/config/locales/de.yml +71 -3
- data/config/locales/en.yml +71 -3
- data/config/locales/es-PY.yml +71 -3
- data/config/locales/es.yml +73 -5
- data/config/locales/eu.yml +71 -3
- data/config/locales/fi.yml +81 -13
- data/config/locales/fr.yml +71 -3
- data/config/locales/gl.yml +71 -3
- data/config/locales/hu.yml +71 -3
- data/config/locales/it.yml +71 -3
- data/config/locales/nl.yml +71 -3
- data/config/locales/pl.yml +71 -3
- data/config/locales/pt-BR.yml +72 -4
- data/config/locales/pt.yml +71 -3
- data/config/locales/sv.yml +71 -3
- data/db/migrate/20180927111721_create_participatory_texts.rb +13 -0
- data/db/migrate/20180930125321_add_participatory_text_level_to_proposals.rb +7 -0
- data/db/migrate/20180930125321_add_position_to_proposals.rb +7 -0
- data/db/migrate/20181003074440_fix_user_groups_ids_in_proposals_endorsements.rb +16 -0
- data/db/migrate/20181010114622_add_temporary_votes.rb +9 -0
- data/db/migrate/20181016132225_add_organization_as_author.rb +13 -0
- data/db/migrate/20181017084221_make_author_polymorhpic_for_proposal_endorsements.rb +31 -0
- data/lib/decidim/content_parsers/proposal_parser.rb +9 -3
- data/lib/decidim/proposals.rb +3 -1
- data/lib/decidim/proposals/admin_engine.rb +12 -1
- data/lib/decidim/proposals/component.rb +60 -23
- data/lib/decidim/proposals/engine.rb +55 -12
- data/lib/decidim/proposals/markdown_to_proposals.rb +90 -0
- data/lib/decidim/proposals/participatory_text_section.rb +21 -0
- data/lib/decidim/proposals/test/factories.rb +35 -7
- data/lib/decidim/proposals/version.rb +1 -1
- metadata +86 -19
@@ -6,9 +6,15 @@ $(document).ready(function () {
|
|
6
6
|
|
7
7
|
window.selectedProposalsCountUpdate = function() {
|
8
8
|
if(selectedProposalsCount() == 0){
|
9
|
-
$("#js-
|
9
|
+
$("#js-selected-proposals-count").text("")
|
10
10
|
} else {
|
11
|
-
$("#js-
|
11
|
+
$("#js-selected-proposals-count").text(selectedProposalsCount());
|
12
|
+
}
|
13
|
+
|
14
|
+
if(selectedProposalsCount() >= 2) {
|
15
|
+
$('button[data-action="merge-proposals"]').parent().show();
|
16
|
+
} else {
|
17
|
+
$('button[data-action="merge-proposals"]').parent().hide();
|
12
18
|
}
|
13
19
|
}
|
14
20
|
|
@@ -33,28 +39,27 @@ $(document).ready(function () {
|
|
33
39
|
$("#js-other-actions-wrapper").addClass('hide');
|
34
40
|
}
|
35
41
|
|
36
|
-
|
37
|
-
$("
|
42
|
+
window.hideBulkActionForms = function() {
|
43
|
+
return $(".js-bulk-action-form").addClass('hide');
|
38
44
|
}
|
39
45
|
|
40
|
-
|
41
|
-
|
42
|
-
}
|
43
|
-
|
44
|
-
if ($('#js-form-recategorize-proposals').length) {
|
45
|
-
window.hideRecategorizeProposalActions();
|
46
|
+
if ($('.js-bulk-action-form').length) {
|
47
|
+
window.hideBulkActionForms();
|
46
48
|
$("#js-bulk-actions-button").addClass('hide');
|
47
49
|
|
48
|
-
$("#js-bulk-actions-
|
50
|
+
$("#js-bulk-actions-dropdown ul li button").click(function(e){
|
49
51
|
e.preventDefault();
|
52
|
+
let action = $(e.target).data("action");
|
50
53
|
|
51
|
-
|
52
|
-
$(
|
53
|
-
|
54
|
+
if(action) {
|
55
|
+
$(`#js-form-${action}`).submit(function(){
|
56
|
+
$('.layout-content > .callout-wrapper').html("");
|
57
|
+
})
|
54
58
|
|
55
|
-
|
56
|
-
|
57
|
-
|
59
|
+
$(`#js-${action}-actions`).removeClass('hide');
|
60
|
+
hideBulkActionsButton(true);
|
61
|
+
hideOtherActionsButtons();
|
62
|
+
}
|
58
63
|
})
|
59
64
|
|
60
65
|
// select all checkboxes
|
@@ -99,12 +104,12 @@ $(document).ready(function () {
|
|
99
104
|
hideBulkActionsButton();
|
100
105
|
}
|
101
106
|
|
102
|
-
$('
|
107
|
+
$('.js-bulk-action-form').find(".js-proposal-id-"+proposal_id).prop('checked', checked);
|
103
108
|
selectedProposalsCountUpdate();
|
104
109
|
});
|
105
110
|
|
106
|
-
$('
|
107
|
-
window.
|
111
|
+
$('.js-cancel-bulk-action').on('click', function (e) {
|
112
|
+
window.hideBulkActionForms()
|
108
113
|
showBulkActionsButton();
|
109
114
|
showOtherActionsButtons();
|
110
115
|
});
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
# A cell to display when a proposal has been published.
|
6
|
+
class ProposalActivityCell < ActivityCell
|
7
|
+
def title
|
8
|
+
I18n.t(
|
9
|
+
"decidim.proposals.last_activity.new_proposal_at_html",
|
10
|
+
link: participatory_space_link
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def resource_link_text
|
15
|
+
Decidim::Proposals::ProposalPresenter.new(resource).title
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -81,8 +81,12 @@ module Decidim
|
|
81
81
|
def increment_score
|
82
82
|
return unless proposal.accepted?
|
83
83
|
|
84
|
-
proposal.
|
85
|
-
|
84
|
+
proposal.coauthorships.find_each do |coauthorship|
|
85
|
+
if coauthorship.user_group
|
86
|
+
Decidim::Gamification.increment_score(coauthorship.user_group, :accepted_proposals)
|
87
|
+
else
|
88
|
+
Decidim::Gamification.increment_score(coauthorship.author, :accepted_proposals)
|
89
|
+
end
|
86
90
|
end
|
87
91
|
end
|
88
92
|
end
|
@@ -40,10 +40,10 @@ module Decidim
|
|
40
40
|
attr_reader :form, :proposal, :attachment
|
41
41
|
|
42
42
|
def create_proposal
|
43
|
-
@proposal = Decidim.
|
44
|
-
|
45
|
-
form.
|
46
|
-
|
43
|
+
@proposal = Decidim::Proposals::ProposalBuilder.create(
|
44
|
+
attributes: attributes,
|
45
|
+
author: form.current_organization,
|
46
|
+
action_user: form.current_user
|
47
47
|
)
|
48
48
|
end
|
49
49
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
module Admin
|
6
|
+
# A command with all the business logic when an admin imports proposals from
|
7
|
+
# a participatory text.
|
8
|
+
class ImportParticipatoryText < 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
|
+
transaction do
|
26
|
+
save_participatory_text(form)
|
27
|
+
parse_participatory_text_doc(form.document_text)
|
28
|
+
end
|
29
|
+
|
30
|
+
broadcast(:ok)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :form
|
36
|
+
|
37
|
+
def save_participatory_text(form)
|
38
|
+
document = ParticipatoryText.find_or_initialize_by(component: form.current_component)
|
39
|
+
document.update!(title: form.title, description: form.description)
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse_participatory_text_doc(document)
|
43
|
+
parser = MarkdownToProposals.new(form.current_component, form.current_user)
|
44
|
+
parser.parse(document)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -33,28 +33,14 @@ module Decidim
|
|
33
33
|
proposals.map do |original_proposal|
|
34
34
|
next if proposal_already_copied?(original_proposal, target_component)
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
"decidim_component_id",
|
44
|
-
"reference",
|
45
|
-
"proposal_votes_count",
|
46
|
-
"proposal_notes_count"
|
36
|
+
Decidim::Proposals::ProposalBuilder.copy(
|
37
|
+
original_proposal,
|
38
|
+
author: form.current_organization,
|
39
|
+
action_user: form.current_user,
|
40
|
+
extra_attributes: {
|
41
|
+
"component" => target_component
|
42
|
+
}
|
47
43
|
)
|
48
|
-
|
49
|
-
proposal = Decidim::Proposals::Proposal.new(origin_attributes)
|
50
|
-
proposal.category = original_proposal.category
|
51
|
-
proposal.component = target_component
|
52
|
-
proposal.save!
|
53
|
-
|
54
|
-
proposal.link_resources([original_proposal], "copied_from_component")
|
55
|
-
original_proposal.coauthorships.each do |coauthorship|
|
56
|
-
Decidim::Coauthorship.create(author: coauthorship.author, user_group: coauthorship.user_group, coauthorable: proposal)
|
57
|
-
end
|
58
44
|
end.compact
|
59
45
|
end
|
60
46
|
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
module Admin
|
6
|
+
# A command with all the business logic when an admin merges proposals from
|
7
|
+
# one component to another.
|
8
|
+
class MergeProposals < 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
|
+
broadcast(:ok, merge_proposals)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :form
|
31
|
+
|
32
|
+
def merge_proposals
|
33
|
+
transaction do
|
34
|
+
merged_proposal = create_new_proposal
|
35
|
+
merged_proposal.link_resources(proposals_to_link, "copied_from_component")
|
36
|
+
form.proposals.each(&:destroy!) if form.same_component?
|
37
|
+
merged_proposal
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def proposals_to_link
|
42
|
+
return previous_links if form.same_component?
|
43
|
+
form.proposals
|
44
|
+
end
|
45
|
+
|
46
|
+
def previous_links
|
47
|
+
@previous_links ||= form.proposals.flat_map do |proposal|
|
48
|
+
proposal.linked_resources(:proposals, "copied_from_component")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_new_proposal
|
53
|
+
original_proposal = form.proposals.first
|
54
|
+
|
55
|
+
Decidim::Proposals::ProposalBuilder.copy(
|
56
|
+
original_proposal,
|
57
|
+
author: form.current_organization,
|
58
|
+
action_user: form.current_user,
|
59
|
+
extra_attributes: {
|
60
|
+
component: form.target_component
|
61
|
+
},
|
62
|
+
skip_link: true
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
module Admin
|
6
|
+
# A command with all the business logic when an admin imports proposals from
|
7
|
+
# a participatory text.
|
8
|
+
class PublishParticipatoryText < Rectify::Command
|
9
|
+
# Public: Initializes the command.
|
10
|
+
#
|
11
|
+
# form - A PreviewParticipatoryTextForm 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
|
+
transaction do
|
24
|
+
@publish_failures = {}
|
25
|
+
update_contents_and_resort_proposals(form)
|
26
|
+
publish_drafts
|
27
|
+
end
|
28
|
+
|
29
|
+
if @publish_failures.any?
|
30
|
+
broadcast(:invalid, @publish_failures)
|
31
|
+
else
|
32
|
+
broadcast(:ok)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
attr_reader :form
|
39
|
+
|
40
|
+
def update_contents_and_resort_proposals(form)
|
41
|
+
form.proposals.each do |prop_form|
|
42
|
+
proposal = Decidim::Proposals::Proposal.where(component: form.current_component).find(prop_form.id)
|
43
|
+
proposal.set_list_position(prop_form.position) if proposal.position != prop_form.position
|
44
|
+
proposal.title = prop_form.title
|
45
|
+
proposal.body = prop_form.body if proposal.participatory_text_level == Decidim::Proposals::ParticipatoryTextSection::LEVELS[:article]
|
46
|
+
|
47
|
+
add_failure(proposal) unless proposal.save
|
48
|
+
end
|
49
|
+
raise ActiveRecord::Rollback if @publish_failures.any?
|
50
|
+
end
|
51
|
+
|
52
|
+
def publish_drafts
|
53
|
+
Decidim::Proposals::Proposal.where(component: form.current_component).drafts.find_each do |proposal|
|
54
|
+
add_failure(proposal) unless proposal.update(published_at: Time.current)
|
55
|
+
end
|
56
|
+
raise ActiveRecord::Rollback if @publish_failures.any?
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_failure(proposal)
|
60
|
+
@publish_failures[proposal.id] = proposal.errors.full_messages
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
module Admin
|
6
|
+
# A command with all the business logic when an admin splits proposals from
|
7
|
+
# one component to another.
|
8
|
+
class SplitProposals < 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
|
+
broadcast(:ok, split_proposals)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :form
|
31
|
+
|
32
|
+
def split_proposals
|
33
|
+
transaction do
|
34
|
+
form.proposals.flat_map do |original_proposal|
|
35
|
+
# If copying to the same component we only need one copy
|
36
|
+
# but linking to the original proposal links, not the
|
37
|
+
# original proposal.
|
38
|
+
create_proposal(original_proposal)
|
39
|
+
create_proposal(original_proposal) unless form.same_component?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_proposal(original_proposal)
|
45
|
+
split_proposal = Decidim::Proposals::ProposalBuilder.copy(
|
46
|
+
original_proposal,
|
47
|
+
author: form.current_organization,
|
48
|
+
action_user: form.current_user,
|
49
|
+
extra_attributes: {
|
50
|
+
component: form.target_component
|
51
|
+
},
|
52
|
+
skip_link: true
|
53
|
+
)
|
54
|
+
|
55
|
+
proposals_to_link = links_for(original_proposal)
|
56
|
+
split_proposal.link_resources(proposals_to_link, "copied_from_component")
|
57
|
+
end
|
58
|
+
|
59
|
+
def links_for(proposal)
|
60
|
+
return proposal unless form.same_component?
|
61
|
+
|
62
|
+
proposal.linked_resources(:proposals, "copied_from_component")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
module Admin
|
6
|
+
# A command with all the business logic when a user updates a proposal.
|
7
|
+
class UpdateProposal < Rectify::Command
|
8
|
+
include AttachmentMethods
|
9
|
+
|
10
|
+
# Public: Initializes the command.
|
11
|
+
#
|
12
|
+
# form - A form object with the params.
|
13
|
+
# proposal - the proposal to update.
|
14
|
+
def initialize(form, proposal)
|
15
|
+
@form = form
|
16
|
+
@proposal = proposal
|
17
|
+
@attached_to = proposal
|
18
|
+
end
|
19
|
+
|
20
|
+
# Executes the command. Broadcasts these events:
|
21
|
+
#
|
22
|
+
# - :ok when everything is valid, together with the proposal.
|
23
|
+
# - :invalid if the form wasn't valid and we couldn't proceed.
|
24
|
+
#
|
25
|
+
# Returns nothing.
|
26
|
+
def call
|
27
|
+
return broadcast(:invalid) if form.invalid?
|
28
|
+
|
29
|
+
if process_attachments?
|
30
|
+
@proposal.attachments.destroy_all
|
31
|
+
|
32
|
+
build_attachment
|
33
|
+
return broadcast(:invalid) if attachment_invalid?
|
34
|
+
end
|
35
|
+
|
36
|
+
transaction do
|
37
|
+
update_proposal
|
38
|
+
create_attachment if process_attachments?
|
39
|
+
end
|
40
|
+
|
41
|
+
broadcast(:ok, proposal)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
attr_reader :form, :proposal, :attachment
|
47
|
+
|
48
|
+
def update_proposal
|
49
|
+
parsed_title = Decidim::ContentProcessor.parse_with_processor(:hashtag, form.title, current_organization: form.current_organization).rewrite
|
50
|
+
parsed_body = Decidim::ContentProcessor.parse_with_processor(:hashtag, form.body, current_organization: form.current_organization).rewrite
|
51
|
+
|
52
|
+
Decidim.traceability.update!(
|
53
|
+
proposal,
|
54
|
+
form.current_user,
|
55
|
+
title: parsed_title,
|
56
|
+
body: parsed_body,
|
57
|
+
category: form.category,
|
58
|
+
scope: form.scope,
|
59
|
+
address: form.address,
|
60
|
+
latitude: form.latitude,
|
61
|
+
longitude: form.longitude
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|