decidim-proposals 0.9.3 → 0.10.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.
- checksums.yaml +4 -4
- data/README.md +18 -1
- data/app/assets/config/admin/decidim_proposals_manifest.js +1 -0
- data/app/assets/javascripts/decidim/proposals/admin/proposals.es6 +113 -0
- data/app/assets/javascripts/decidim/proposals/identity_selector_dialog.js.es6 +56 -0
- data/app/commands/decidim/proposals/admin/answer_proposal.rb +11 -5
- data/app/commands/decidim/proposals/admin/create_proposal.rb +25 -3
- data/app/commands/decidim/proposals/admin/create_proposal_note.rb +13 -8
- data/app/commands/decidim/proposals/admin/import_proposals.rb +83 -0
- data/app/commands/decidim/proposals/admin/update_proposal_category.rb +68 -0
- data/app/commands/decidim/proposals/create_proposal.rb +0 -12
- data/app/commands/decidim/proposals/endorse_proposal.rb +56 -0
- data/app/commands/decidim/proposals/publish_proposal.rb +60 -0
- data/app/commands/decidim/proposals/unendorse_proposal.rb +40 -0
- data/app/commands/decidim/proposals/update_proposal.rb +3 -3
- data/app/commands/decidim/proposals/vote_proposal.rb +1 -1
- data/app/commands/decidim/proposals/withdraw_proposal.rb +1 -1
- data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +1 -1
- data/app/controllers/decidim/proposals/admin/proposal_notes_controller.rb +2 -2
- data/app/controllers/decidim/proposals/admin/proposals_controller.rb +50 -1
- data/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb +35 -0
- data/app/controllers/decidim/proposals/proposal_endorsements_controller.rb +56 -0
- data/app/controllers/decidim/proposals/proposals_controller.rb +82 -9
- data/app/events/decidim/proposals/admin/update_proposal_category_event.rb +11 -0
- data/app/events/decidim/proposals/creation_enabled_event.rb +8 -0
- data/app/events/decidim/proposals/endorsing_enabled_event.rb +8 -0
- data/app/events/decidim/proposals/proposal_endorsed_event.rb +29 -0
- data/app/events/decidim/proposals/publish_proposal_event.rb +21 -0
- data/app/events/decidim/proposals/voting_enabled_event.rb +8 -0
- data/app/forms/decidim/proposals/admin/proposal_form.rb +9 -2
- data/app/forms/decidim/proposals/admin/proposals_import_form.rb +60 -0
- data/app/forms/decidim/proposals/proposal_form.rb +16 -5
- data/app/helpers/decidim/proposals/application_helper.rb +1 -0
- data/app/helpers/decidim/proposals/proposal_endorsements_helper.rb +117 -0
- data/app/helpers/decidim/proposals/proposal_votes_helper.rb +13 -6
- data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +105 -0
- data/app/jobs/decidim/proposals/settings_change_job.rb +48 -0
- data/app/models/decidim/proposals/abilities/current_user_ability.rb +30 -8
- data/app/models/decidim/proposals/proposal.rb +38 -38
- data/app/models/decidim/proposals/proposal_endorsement.rb +31 -0
- data/app/models/decidim/proposals/proposal_note.rb +7 -0
- data/app/presenters/decidim/proposals/admin_log/proposal_note_presenter.rb +39 -0
- data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +47 -0
- data/app/presenters/decidim/proposals/admin_log/value_types/proposal_state_presenter.rb +16 -0
- data/app/queries/decidim/proposals/similar_proposals.rb +53 -0
- data/app/types/decidim/proposals/proposal_type.rb +34 -0
- data/app/types/decidim/proposals/proposals_type.rb +34 -0
- data/app/views/decidim/participatory_processes/participatory_process_groups/_highlighted_proposals.html.erb +8 -0
- data/app/views/decidim/participatory_processes/participatory_process_groups/_proposal.html.erb +27 -0
- data/app/views/decidim/participatory_spaces/_highlighted_proposals.html.erb +10 -0
- data/app/views/decidim/participatory_spaces/_proposal.html.erb +27 -0
- data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +15 -0
- data/app/views/decidim/proposals/admin/proposals/_js-callout.html.erb +6 -0
- data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +63 -0
- data/app/views/decidim/proposals/admin/proposals/index.html.erb +12 -73
- data/app/views/decidim/proposals/admin/proposals/update_category.js.erb +25 -0
- data/app/views/decidim/proposals/admin/proposals_imports/new.html.erb +28 -0
- data/app/views/decidim/proposals/proposal_endorsements/_identity.html.erb +4 -0
- data/app/views/decidim/proposals/proposal_endorsements/identities.html.erb +12 -0
- data/app/views/decidim/proposals/proposal_endorsements/update_buttons_and_counters.js.erb +9 -0
- data/app/views/decidim/proposals/proposals/_endorsement_button.html.erb +11 -0
- data/app/views/decidim/proposals/proposals/_endorsement_identities_cabin.html.erb +13 -0
- data/app/views/decidim/proposals/proposals/_endorsement_xxs.html.erb +9 -0
- data/app/views/decidim/proposals/proposals/_endorsements_card_row.html.erb +22 -0
- data/app/views/decidim/proposals/proposals/_endorsements_count.html.erb +5 -0
- data/app/views/decidim/proposals/proposals/_endorsements_listing.html.erb +34 -0
- data/app/views/decidim/proposals/proposals/_proposal.html.erb +2 -2
- data/app/views/decidim/proposals/proposals/_proposal_preview.html.erb +36 -0
- data/app/views/decidim/proposals/proposals/_proposal_similar.html.erb +21 -0
- data/app/views/decidim/proposals/proposals/_vote_button.html.erb +8 -8
- data/app/views/decidim/proposals/proposals/_votes_count.html.erb +23 -6
- data/app/views/decidim/proposals/proposals/_voting_rules.html.erb +7 -3
- data/app/views/decidim/proposals/proposals/_wizard_aside.html.erb +16 -0
- data/app/views/decidim/proposals/proposals/_wizard_header.html.erb +31 -0
- data/app/views/decidim/proposals/proposals/compare.html.erb +19 -0
- data/app/views/decidim/proposals/proposals/edit_draft.html.erb +55 -0
- data/app/views/decidim/proposals/proposals/new.html.erb +7 -20
- data/app/views/decidim/proposals/proposals/preview.html.erb +18 -0
- data/app/views/decidim/proposals/proposals/show.html.erb +13 -4
- data/config/locales/ca.yml +156 -15
- data/config/locales/en.yml +156 -15
- data/config/locales/es.yml +157 -16
- data/config/locales/eu.yml +151 -7
- data/config/locales/fi.yml +151 -7
- data/config/locales/fr.yml +153 -9
- data/config/locales/gl.yml +151 -7
- data/config/locales/it.yml +151 -7
- data/config/locales/nl.yml +151 -7
- data/config/locales/pl.yml +148 -22
- data/config/locales/pt-BR.yml +151 -7
- data/config/locales/pt.yml +151 -7
- data/config/locales/ru.yml +0 -9
- data/config/locales/sv.yml +151 -7
- data/config/locales/uk.yml +87 -13
- data/db/migrate/20170307085300_migrate_proposal_reports_data_to_reports.rb +1 -1
- data/db/migrate/20171201115434_create_proposal_endorsements.rb +16 -0
- data/db/migrate/20171201122623_add_counter_cache_endorsements_to_proposals.rb +8 -0
- data/db/migrate/20171212102250_enable_pg_extensions.rb +7 -0
- data/db/migrate/20171220084719_add_published_at_to_proposals.rb +14 -0
- data/lib/decidim/proposals.rb +15 -0
- data/lib/decidim/proposals/admin_engine.rb +8 -0
- data/lib/decidim/proposals/commentable_proposal.rb +39 -0
- data/lib/decidim/proposals/engine.rb +69 -1
- data/lib/decidim/proposals/feature.rb +51 -6
- data/lib/decidim/proposals/test/factories.rb +78 -2
- data/lib/decidim/proposals/version.rb +1 -1
- metadata +76 -20
- data/app/events/decidim/proposals/create_proposal_event.rb +0 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9f936f41817cbb42ca4bdb52d9501300941433847adf1dbcda717d67a31c8892
|
|
4
|
+
data.tar.gz: 9671316b0995837019afe72384b2dae2c4bc514c785c2d4011cc0341303cf7ee
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4e0e027c43986db153e3a0dea73d24b951d9b766650f4eae49f35826c870bacc63cf42476650014be7158840b043cb7dbc0329d42c1d28c393d181e7f525d51f
|
|
7
|
+
data.tar.gz: c2dab6b2845c246cc9b8254222e584fd1bd37ca16b2d7d3f77f4a4ac7453a7fa294044cb8c997f9770523c50bce6ac3452b2a12f3d2090b7576a2ec0d027a046
|
data/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Proposals will be available as a Feature for a Participatory Process.
|
|
|
11
11
|
Add this line to your application's Gemfile:
|
|
12
12
|
|
|
13
13
|
```ruby
|
|
14
|
-
gem 'decidim-proposals
|
|
14
|
+
gem 'decidim-proposals'
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
And then execute:
|
|
@@ -20,6 +20,23 @@ And then execute:
|
|
|
20
20
|
bundle
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
### Configuring Similarity
|
|
24
|
+
|
|
25
|
+
`pg_trgm` is a PostgreSQL extension providing simple fuzzy string matching used in the Proposal wizard to find similar published proposals (title and the body).
|
|
26
|
+
|
|
27
|
+
Create config variables in your app's `/config/initializers/decidim-proposals.rb`:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
Decidim::Proposals.configure do |config|
|
|
31
|
+
config.similarity_threshold = 0.25 # default value
|
|
32
|
+
config.similarity_limit = 10 # default value
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`similarity_threshold`(real): Sets the current similarity threshold that is used by the % operator. The threshold must be between 0 and 1 (default is 0.3).
|
|
37
|
+
|
|
38
|
+
`similarity_limit`: number of maximum results.
|
|
39
|
+
|
|
23
40
|
## Contributing
|
|
24
41
|
|
|
25
42
|
See [Decidim](https://github.com/decidim/decidim).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//= link decidim/proposals/admin/proposals.js
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// = require_self
|
|
2
|
+
$(document).ready(function () {
|
|
3
|
+
let selectedProposalsCount = function() {
|
|
4
|
+
return $('.table-list .js-check-all-proposal:checked').length
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
let selectedProposalsCountUpdate = function() {
|
|
8
|
+
if(selectedProposalsCount() == 0){
|
|
9
|
+
$("#js-recategorize-proposals-count").text("")
|
|
10
|
+
} else {
|
|
11
|
+
$("#js-recategorize-proposals-count").text(selectedProposalsCount());
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let showBulkActionsButton = function() {
|
|
16
|
+
if(selectedProposalsCount() > 0){
|
|
17
|
+
$("#js-bulk-actions-button").removeClass('hide');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let hideBulkActionsButton = function(force = false) {
|
|
22
|
+
if(selectedProposalsCount() == 0 || force == true){
|
|
23
|
+
$("#js-bulk-actions-button").addClass('hide');
|
|
24
|
+
$("#js-bulk-actions-dropdown").removeClass('is-open');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let showOtherActionsButtons = function() {
|
|
29
|
+
$("#js-other-actions-wrapper").removeClass('hide');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let hideOtherActionsButtons = function() {
|
|
33
|
+
$("#js-other-actions-wrapper").addClass('hide');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let showRecategorizeProposalActions = function() {
|
|
37
|
+
$("#js-recategorize-proposals-actions").removeClass('hide');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let hideRecategorizeProposalActions = function() {
|
|
41
|
+
$("#js-recategorize-proposals-actions").addClass('hide');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
if ($('#js-form-recategorize-proposals').length) {
|
|
46
|
+
hideRecategorizeProposalActions();
|
|
47
|
+
$("#js-bulk-actions-button").addClass('hide');
|
|
48
|
+
|
|
49
|
+
$("#js-bulk-actions-recategorize").click(function(e){
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
|
|
52
|
+
$('#js-form-recategorize-proposals').submit(function(){
|
|
53
|
+
$('.layout-content > .callout-wrapper').html("");
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
showRecategorizeProposalActions();
|
|
57
|
+
hideBulkActionsButton(true);
|
|
58
|
+
hideOtherActionsButtons();
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
// select all checkboxes
|
|
62
|
+
$(".js-check-all").change(function() {
|
|
63
|
+
$(".js-check-all-proposal").prop('checked', $(this).prop("checked"));
|
|
64
|
+
|
|
65
|
+
if ($(this).prop("checked")) {
|
|
66
|
+
$(".js-check-all-proposal").closest('tr').addClass('selected');
|
|
67
|
+
showBulkActionsButton();
|
|
68
|
+
} else {
|
|
69
|
+
$(".js-check-all-proposal").closest('tr').removeClass('selected');
|
|
70
|
+
hideBulkActionsButton();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
selectedProposalsCountUpdate();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// proposal checkbox change
|
|
77
|
+
$('.table-list').on('change', '.js-check-all-proposal', function (e) {
|
|
78
|
+
let proposal_id = $(this).val()
|
|
79
|
+
let checked = $(this).prop("checked")
|
|
80
|
+
|
|
81
|
+
// uncheck "select all", if one of the listed checkbox item is unchecked
|
|
82
|
+
if ($(this).prop("checked") === false) {
|
|
83
|
+
$(".js-check-all").prop('checked', false);
|
|
84
|
+
}
|
|
85
|
+
// check "select all" if all checkbox proposals are checked
|
|
86
|
+
if ($('.js-check-all-proposal:checked').length === $('.js-check-all-proposal').length) {
|
|
87
|
+
$(".js-check-all").prop('checked', true);
|
|
88
|
+
showBulkActionsButton();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if ($(this).prop("checked")) {
|
|
92
|
+
showBulkActionsButton();
|
|
93
|
+
$(this).closest('tr').addClass('selected');
|
|
94
|
+
} else {
|
|
95
|
+
hideBulkActionsButton();
|
|
96
|
+
$(this).closest('tr').removeClass('selected');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if ($('.js-check-all-proposal:checked').length === 0) {
|
|
100
|
+
hideBulkActionsButton();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
$('#js-form-recategorize-proposals').find(".js-proposal-id-"+proposal_id).prop('checked', checked);
|
|
104
|
+
selectedProposalsCountUpdate();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
$('#js-cancel-edit-category').on('click', function (e) {
|
|
108
|
+
hideRecategorizeProposalActions();
|
|
109
|
+
showBulkActionsButton();
|
|
110
|
+
showOtherActionsButtons();
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Makes the #select-identity-button to open a popup for the user to
|
|
3
|
+
* select with which identity he wants to perform an action.
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
$(document).ready(function () {
|
|
7
|
+
|
|
8
|
+
let button = $('#select-identity-button'),
|
|
9
|
+
refreshUrl = null,
|
|
10
|
+
userIdentitiesDialog = $('#user-identities');
|
|
11
|
+
|
|
12
|
+
if (userIdentitiesDialog.length) {
|
|
13
|
+
refreshUrl = userIdentitiesDialog.data('refresh-url');
|
|
14
|
+
|
|
15
|
+
button.click(function () {
|
|
16
|
+
$.ajax(refreshUrl).done(function(response) {
|
|
17
|
+
userIdentitiesDialog.html(response).foundation('open');
|
|
18
|
+
button.trigger('ajax:success')
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Manage the identity selector for endorsements.
|
|
27
|
+
*
|
|
28
|
+
*/
|
|
29
|
+
$(document).ready(function () {
|
|
30
|
+
$("#select-identity-button").on('ajax:success', function() {
|
|
31
|
+
// once reveal popup has been rendered register event callbacks
|
|
32
|
+
$("#user-identities ul.reveal__list li").each(function(index, elem) {
|
|
33
|
+
let liTag = $(elem)
|
|
34
|
+
liTag.on('click', function() {
|
|
35
|
+
let method = liTag.data('method')
|
|
36
|
+
let url = liTag.data('url')
|
|
37
|
+
$.ajax({
|
|
38
|
+
url: url,
|
|
39
|
+
method: method,
|
|
40
|
+
dataType: 'script',
|
|
41
|
+
success: function() {
|
|
42
|
+
if (liTag.hasClass('selected')) {
|
|
43
|
+
liTag.removeClass('selected')
|
|
44
|
+
liTag.find('.icon--circle-check').addClass('invisible')
|
|
45
|
+
liTag.data('method', 'post')
|
|
46
|
+
} else {
|
|
47
|
+
liTag.addClass('selected')
|
|
48
|
+
liTag.find('.icon--circle-check').removeClass('invisible')
|
|
49
|
+
liTag.data('method', 'delete')
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
})
|
|
@@ -34,11 +34,17 @@ module Decidim
|
|
|
34
34
|
attr_reader :form, :proposal
|
|
35
35
|
|
|
36
36
|
def answer_proposal
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
)
|
|
37
|
+
Decidim.traceability.perform_action!(
|
|
38
|
+
"answer",
|
|
39
|
+
proposal,
|
|
40
|
+
form.current_user
|
|
41
|
+
) do
|
|
42
|
+
proposal.update!(
|
|
43
|
+
state: @form.state,
|
|
44
|
+
answer: @form.answer,
|
|
45
|
+
answered_at: Time.current
|
|
46
|
+
)
|
|
47
|
+
end
|
|
42
48
|
end
|
|
43
49
|
|
|
44
50
|
def notify_followers
|
|
@@ -29,6 +29,7 @@ module Decidim
|
|
|
29
29
|
transaction do
|
|
30
30
|
create_proposal
|
|
31
31
|
create_attachment if process_attachments?
|
|
32
|
+
send_notification
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
broadcast(:ok, proposal)
|
|
@@ -39,7 +40,15 @@ module Decidim
|
|
|
39
40
|
attr_reader :form, :proposal, :attachment
|
|
40
41
|
|
|
41
42
|
def create_proposal
|
|
42
|
-
@proposal =
|
|
43
|
+
@proposal = Decidim.traceability.create!(
|
|
44
|
+
Proposal,
|
|
45
|
+
form.current_user,
|
|
46
|
+
attributes
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def attributes
|
|
51
|
+
{
|
|
43
52
|
title: form.title,
|
|
44
53
|
body: form.body,
|
|
45
54
|
category: form.category,
|
|
@@ -47,8 +56,9 @@ module Decidim
|
|
|
47
56
|
feature: form.feature,
|
|
48
57
|
address: form.address,
|
|
49
58
|
latitude: form.latitude,
|
|
50
|
-
longitude: form.longitude
|
|
51
|
-
|
|
59
|
+
longitude: form.longitude,
|
|
60
|
+
published_at: Time.current
|
|
61
|
+
}
|
|
52
62
|
end
|
|
53
63
|
|
|
54
64
|
def build_attachment
|
|
@@ -82,6 +92,18 @@ module Decidim
|
|
|
82
92
|
def process_attachments?
|
|
83
93
|
attachments_allowed? && attachment_present?
|
|
84
94
|
end
|
|
95
|
+
|
|
96
|
+
def send_notification
|
|
97
|
+
Decidim::EventsManager.publish(
|
|
98
|
+
event: "decidim.events.proposals.proposal_published",
|
|
99
|
+
event_class: Decidim::Proposals::PublishProposalEvent,
|
|
100
|
+
resource: proposal,
|
|
101
|
+
recipient_ids: @proposal.participatory_space.followers.pluck(:id),
|
|
102
|
+
extra: {
|
|
103
|
+
participatory_space: true
|
|
104
|
+
}
|
|
105
|
+
)
|
|
106
|
+
end
|
|
85
107
|
end
|
|
86
108
|
end
|
|
87
109
|
end
|
|
@@ -8,12 +8,10 @@ module Decidim
|
|
|
8
8
|
# Public: Initializes the command.
|
|
9
9
|
#
|
|
10
10
|
# form - A form object with the params.
|
|
11
|
-
# current_user - The current user.
|
|
12
11
|
# proposal - the proposal to relate.
|
|
13
|
-
def initialize(form, proposal
|
|
12
|
+
def initialize(form, proposal)
|
|
14
13
|
@form = form
|
|
15
14
|
@proposal = proposal
|
|
16
|
-
@current_user = current_user
|
|
17
15
|
end
|
|
18
16
|
|
|
19
17
|
# Executes the command. Broadcasts these events:
|
|
@@ -32,13 +30,20 @@ module Decidim
|
|
|
32
30
|
|
|
33
31
|
private
|
|
34
32
|
|
|
35
|
-
attr_reader :form, :proposal_note
|
|
33
|
+
attr_reader :form, :proposal_note, :proposal
|
|
36
34
|
|
|
37
35
|
def create_proposal_note
|
|
38
|
-
@proposal_note =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
@proposal_note = Decidim.traceability.create!(
|
|
37
|
+
ProposalNote,
|
|
38
|
+
form.current_user,
|
|
39
|
+
{
|
|
40
|
+
body: form.body,
|
|
41
|
+
proposal: proposal,
|
|
42
|
+
author: form.current_user
|
|
43
|
+
},
|
|
44
|
+
resource: {
|
|
45
|
+
title: proposal.title
|
|
46
|
+
}
|
|
42
47
|
)
|
|
43
48
|
end
|
|
44
49
|
end
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
# one component to another.
|
|
8
|
+
class ImportProposals < 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, import_proposals)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
attr_reader :form
|
|
31
|
+
|
|
32
|
+
def import_proposals
|
|
33
|
+
proposals.map do |original_proposal|
|
|
34
|
+
origin_attributes = original_proposal.attributes.except(
|
|
35
|
+
"id",
|
|
36
|
+
"created_at",
|
|
37
|
+
"updated_at",
|
|
38
|
+
"state",
|
|
39
|
+
"answer",
|
|
40
|
+
"answered_at",
|
|
41
|
+
"decidim_feature_id",
|
|
42
|
+
"reference",
|
|
43
|
+
"proposal_votes_count",
|
|
44
|
+
"proposal_notes_count"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
proposal = Decidim::Proposals::Proposal.new(origin_attributes)
|
|
48
|
+
proposal.category = original_proposal.category
|
|
49
|
+
proposal.feature = target_feature
|
|
50
|
+
proposal.save!
|
|
51
|
+
|
|
52
|
+
proposal.link_resources([original_proposal], "copied_from_component")
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def proposals
|
|
57
|
+
Decidim::Proposals::Proposal
|
|
58
|
+
.where(feature: origin_feature)
|
|
59
|
+
.where(state: proposal_states)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def proposal_states
|
|
63
|
+
@proposal_states = @form.states
|
|
64
|
+
|
|
65
|
+
if @form.states.include?("not_answered")
|
|
66
|
+
@proposal_states.delete("not_answered")
|
|
67
|
+
@proposal_states.push(nil)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
@proposal_states
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def origin_feature
|
|
74
|
+
@form.origin_feature
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def target_feature
|
|
78
|
+
@form.current_feature
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -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 batch updates proposals category.
|
|
7
|
+
class UpdateProposalCategory < Rectify::Command
|
|
8
|
+
# Public: Initializes the command.
|
|
9
|
+
#
|
|
10
|
+
# category_id - the category id to update
|
|
11
|
+
# proposal_ids - the proposals ids to update.
|
|
12
|
+
def initialize(category_id, proposal_ids)
|
|
13
|
+
@category = Decidim::Category.find_by id: category_id
|
|
14
|
+
@proposal_ids = proposal_ids
|
|
15
|
+
@response = { category_name: "", successful: [], errored: [] }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Executes the command. Broadcasts these events:
|
|
19
|
+
#
|
|
20
|
+
# - :update_proposals_category - when everything is ok, returns @response.
|
|
21
|
+
# - :invalid_category - if the category is blank.
|
|
22
|
+
# - :invalid_proposal_ids - if the proposal_ids is blank.
|
|
23
|
+
#
|
|
24
|
+
# Returns @response hash:
|
|
25
|
+
#
|
|
26
|
+
# - :category_name - the translated_name of the category assigned
|
|
27
|
+
# - :successful - Array of names of the updated proposals
|
|
28
|
+
# - :errored - Array of names of the proposals not updated because they already had the category assigned
|
|
29
|
+
def call
|
|
30
|
+
return broadcast(:invalid_category) if @category.blank?
|
|
31
|
+
return broadcast(:invalid_proposal_ids) if @proposal_ids.blank?
|
|
32
|
+
|
|
33
|
+
@response[:category_name] = @category.translated_name
|
|
34
|
+
Proposal.where(id: @proposal_ids).find_each do |proposal|
|
|
35
|
+
if @category == proposal.category
|
|
36
|
+
@response[:errored] << proposal.title
|
|
37
|
+
else
|
|
38
|
+
transaction do
|
|
39
|
+
update_proposal_category proposal
|
|
40
|
+
notify_author proposal if proposal.author.present?
|
|
41
|
+
end
|
|
42
|
+
@response[:successful] << proposal.title
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
broadcast(:update_proposals_category, @response)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def update_proposal_category(proposal)
|
|
52
|
+
proposal.update!(
|
|
53
|
+
category: @category
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def notify_author(proposal)
|
|
58
|
+
Decidim::EventsManager.publish(
|
|
59
|
+
event: "decidim.events.proposals.proposal_update_category",
|
|
60
|
+
event_class: Decidim::Proposals::Admin::UpdateProposalCategoryEvent,
|
|
61
|
+
resource: proposal,
|
|
62
|
+
recipient_ids: [proposal.decidim_author_id]
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|