decidim-proposals 0.19.0 → 0.22.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/config/admin/decidim_proposals_manifest.js +1 -0
- data/app/assets/images/decidim/gamification/badges/accepted_proposals.svg +1 -234
- data/app/assets/images/decidim/gamification/badges/proposal_votes.svg +1 -95
- data/app/assets/images/decidim/gamification/badges/proposals.svg +1 -229
- data/app/assets/images/decidim/proposals/icon.svg +1 -3
- data/app/assets/javascripts/decidim/proposals/admin/proposals.es6 +24 -11
- data/app/assets/javascripts/decidim/proposals/admin/proposals_form.js.es6 +0 -5
- data/app/assets/javascripts/decidim/proposals/admin/proposals_picker.js.es6 +35 -0
- data/app/cells/decidim/proposals/collaborative_draft_link_to_proposal_cell.rb +1 -1
- data/app/cells/decidim/proposals/collaborative_draft_m/footer.erb +1 -1
- data/app/cells/decidim/proposals/collaborative_draft_m_cell.rb +1 -1
- data/app/cells/decidim/proposals/cost_report/show.erb +35 -0
- data/app/cells/decidim/proposals/cost_report_cell.rb +42 -0
- data/app/cells/decidim/proposals/highlighted_proposals_for_component/show.erb +3 -3
- data/app/cells/decidim/proposals/highlighted_proposals_for_component_cell.rb +1 -1
- data/app/cells/decidim/proposals/irreversible_action_modal/show.erb +2 -2
- data/app/cells/decidim/proposals/irreversible_action_modal_cell.rb +1 -1
- data/app/cells/decidim/proposals/participatory_text_proposal/buttons.erb +1 -1
- data/app/cells/decidim/proposals/participatory_text_proposal_cell.rb +1 -1
- data/app/cells/decidim/proposals/proposal_m/footer.erb +4 -1
- data/app/cells/decidim/proposals/proposal_m_cell.rb +37 -9
- data/app/cells/decidim/proposals/proposal_tags/show.erb +18 -10
- data/app/cells/decidim/proposals/proposal_tags_cell.rb +5 -0
- data/app/cells/decidim/proposals/proposals_picker/proposals.erb +12 -0
- data/app/cells/decidim/proposals/proposals_picker/show.erb +14 -0
- data/app/cells/decidim/proposals/proposals_picker_cell.rb +72 -0
- data/app/commands/decidim/proposals/admin/answer_proposal.rb +24 -46
- data/app/commands/decidim/proposals/admin/assign_proposals_to_valuator.rb +61 -0
- data/app/commands/decidim/proposals/admin/create_proposal.rb +6 -1
- data/app/commands/decidim/proposals/admin/create_proposal_note.rb +15 -0
- data/app/commands/decidim/proposals/admin/notify_proposal_answer.rb +85 -0
- data/app/commands/decidim/proposals/admin/publish_answers.rb +67 -0
- data/app/commands/decidim/proposals/admin/unassign_proposals_from_valuator.rb +62 -0
- data/app/commands/decidim/proposals/admin/update_proposal.rb +1 -1
- data/app/commands/decidim/proposals/admin/update_proposal_scope.rb +75 -0
- data/app/commands/decidim/proposals/create_collaborative_draft.rb +1 -1
- data/app/commands/decidim/proposals/create_proposal.rb +1 -1
- data/app/commands/decidim/proposals/gallery_methods.rb +2 -51
- data/app/commands/decidim/proposals/update_proposal.rb +1 -1
- data/app/controllers/concerns/decidim/proposals/admin/filterable.rb +82 -0
- data/app/controllers/concerns/decidim/proposals/admin/picker.rb +21 -0
- data/app/controllers/concerns/decidim/proposals/orderable.rb +13 -2
- data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +16 -6
- data/app/controllers/decidim/proposals/admin/proposal_notes_controller.rb +8 -9
- data/app/controllers/decidim/proposals/admin/proposals_controller.rb +105 -29
- data/app/controllers/decidim/proposals/admin/valuation_assignments_controller.rb +58 -0
- data/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +19 -3
- data/app/controllers/decidim/proposals/proposals_controller.rb +45 -11
- data/app/controllers/decidim/proposals/versions_controller.rb +9 -16
- data/app/events/decidim/proposals/admin/proposal_note_created_event.rb +27 -0
- data/app/events/decidim/proposals/admin/update_proposal_scope_event.rb +11 -0
- data/app/forms/decidim/proposals/admin/participatory_text_proposal_form.rb +13 -0
- data/app/forms/decidim/proposals/admin/preview_participatory_text_form.rb +2 -2
- data/app/forms/decidim/proposals/admin/proposal_answer_form.rb +27 -2
- data/app/forms/decidim/proposals/admin/proposal_base_form.rb +129 -0
- data/app/forms/decidim/proposals/admin/proposal_form.rb +2 -120
- data/app/forms/decidim/proposals/admin/valuation_assignment_form.rb +37 -0
- data/app/forms/decidim/proposals/proposal_form.rb +4 -0
- data/app/forms/decidim/proposals/proposal_wizard_create_step_form.rb +13 -1
- data/app/helpers/decidim/proposals/admin/filterable_helper.rb +17 -0
- data/app/helpers/decidim/proposals/admin/proposal_bulk_actions_helper.rb +35 -0
- data/app/helpers/decidim/proposals/admin/proposal_rankings_helper.rb +63 -0
- data/app/helpers/decidim/proposals/admin/proposals_helper.rb +122 -0
- data/app/helpers/decidim/proposals/admin/proposals_picker_helper.rb +30 -0
- data/app/helpers/decidim/proposals/application_helper.rb +51 -30
- data/app/helpers/decidim/proposals/collaborative_draft_helper.rb +9 -9
- data/app/helpers/decidim/proposals/control_version_helper.rb +1 -37
- data/app/helpers/decidim/proposals/proposal_cells_helper.rb +1 -1
- data/app/helpers/decidim/proposals/proposal_endorsements_helper.rb +0 -145
- data/app/helpers/decidim/proposals/proposal_votes_helper.rb +2 -2
- data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +24 -7
- data/app/helpers/decidim/proposals/proposals_helper.rb +66 -0
- data/app/models/decidim/proposals/proposal.rb +167 -29
- data/app/models/decidim/proposals/valuation_assignment.rb +24 -0
- data/app/permissions/decidim/proposals/admin/permissions.rb +77 -11
- data/app/permissions/decidim/proposals/permissions.rb +1 -22
- data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +1 -1
- data/app/presenters/decidim/proposals/admin_log/valuation_assignment_presenter.rb +51 -0
- data/app/presenters/decidim/proposals/admin_log/value_types/valuator_role_user_presenter.rb +19 -0
- data/app/presenters/decidim/proposals/collaborative_draft_presenter.rb +2 -28
- data/app/presenters/decidim/proposals/log/valuation_assignment_presenter.rb +22 -0
- data/app/presenters/decidim/proposals/proposal_presenter.rb +41 -10
- data/app/queries/decidim/proposals/metrics/accepted_proposals_metric_manage.rb +1 -2
- data/app/queries/decidim/proposals/metrics/endorsements_metric_manage.rb +15 -12
- data/app/queries/decidim/proposals/metrics/proposal_participants_metric_measure.rb +5 -4
- data/app/queries/decidim/proposals/metrics/proposals_metric_manage.rb +2 -8
- data/app/queries/decidim/proposals/metrics/votes_metric_manage.rb +3 -9
- data/app/services/decidim/proposals/collaborative_draft_search.rb +18 -10
- data/app/services/decidim/proposals/diff_renderer.rb +2 -0
- data/app/services/decidim/proposals/proposal_builder.rb +1 -1
- data/app/services/decidim/proposals/proposal_search.rb +45 -47
- data/app/types/decidim/proposals/proposal_input_filter.rb +29 -0
- data/app/types/decidim/proposals/proposal_input_sort.rb +22 -0
- data/app/types/decidim/proposals/proposal_type.rb +32 -11
- data/app/types/decidim/proposals/proposals_type.rb +22 -15
- data/app/validators/proposal_length_validator.rb +38 -0
- data/app/views/decidim/proposals/admin/participatory_texts/index.html.erb +9 -1
- data/app/views/decidim/proposals/admin/proposal_answers/_form.html.erb +35 -0
- data/app/views/decidim/proposals/admin/proposal_notes/_form.html.erb +1 -1
- data/app/views/decidim/proposals/admin/proposal_notes/_proposal_notes.html.erb +3 -3
- data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +8 -2
- data/app/views/decidim/proposals/admin/proposals/_form.html.erb +4 -24
- data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +25 -17
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_assign_to_valuator.html.erb +15 -0
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_dropdown.html.erb +21 -1
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_publish_answers.html.erb +14 -0
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_scope-change.html.erb +25 -0
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_unassign_from_valuator.html.erb +15 -0
- data/app/views/decidim/proposals/admin/proposals/index.html.erb +16 -7
- data/app/views/decidim/proposals/admin/proposals/publish_answers.js.erb +12 -0
- data/app/views/decidim/proposals/admin/proposals/show.html.erb +186 -0
- data/app/views/decidim/proposals/admin/proposals/update_category.js.erb +3 -2
- data/app/views/decidim/proposals/admin/proposals/update_scope.js.erb +27 -0
- data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +6 -4
- data/app/views/decidim/proposals/collaborative_drafts/_filters.html.erb +9 -7
- data/app/views/decidim/proposals/collaborative_drafts/_new_collaborative_draft_button.html.erb +4 -4
- data/app/views/decidim/proposals/collaborative_drafts/_reject_request_access_form.html.erb +1 -1
- data/app/views/decidim/proposals/collaborative_drafts/_wizard_aside.html.erb +4 -2
- data/app/views/decidim/proposals/collaborative_drafts/compare.html.erb +2 -0
- data/app/views/decidim/proposals/collaborative_drafts/complete.html.erb +2 -0
- data/app/views/decidim/proposals/collaborative_drafts/edit.html.erb +3 -1
- data/app/views/decidim/proposals/collaborative_drafts/index.html.erb +4 -2
- data/app/views/decidim/proposals/collaborative_drafts/new.html.erb +4 -0
- data/app/views/decidim/proposals/collaborative_drafts/show.html.erb +29 -30
- data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +6 -4
- data/app/views/decidim/proposals/proposals/_endorsements_card_row.html.erb +0 -16
- data/app/views/decidim/proposals/proposals/_filters.html.erb +19 -17
- data/app/views/decidim/proposals/proposals/_proposal_badge.html.erb +1 -4
- data/app/views/decidim/proposals/proposals/_proposal_preview.html.erb +1 -11
- data/app/views/decidim/proposals/proposals/_proposal_similar.html.erb +2 -2
- data/app/views/decidim/proposals/proposals/_proposals.html.erb +14 -0
- data/app/views/decidim/proposals/proposals/_vote_button.html.erb +14 -7
- data/app/views/decidim/proposals/proposals/_wizard_aside.html.erb +4 -2
- data/app/views/decidim/proposals/proposals/_wizard_header.html.erb +4 -3
- data/app/views/decidim/proposals/proposals/compare.html.erb +2 -0
- data/app/views/decidim/proposals/proposals/complete.html.erb +2 -0
- data/app/views/decidim/proposals/proposals/edit.html.erb +3 -1
- data/app/views/decidim/proposals/proposals/edit_draft.html.erb +2 -0
- data/app/views/decidim/proposals/proposals/index.html.erb +7 -12
- data/app/views/decidim/proposals/proposals/new.html.erb +6 -2
- data/app/views/decidim/proposals/proposals/participatory_texts/_index.html.erb +1 -1
- data/app/views/decidim/proposals/proposals/participatory_texts/_proposal_vote_button.html.erb +10 -3
- data/app/views/decidim/proposals/proposals/participatory_texts/_view_index.html.erb +1 -1
- data/app/views/decidim/proposals/proposals/preview.html.erb +7 -8
- data/app/views/decidim/proposals/proposals/show.html.erb +62 -71
- data/app/views/decidim/proposals/versions/index.html.erb +14 -32
- data/app/views/decidim/proposals/versions/show.html.erb +16 -34
- data/config/locales/ar.yml +74 -66
- data/config/locales/bg-BG.yml +237 -0
- data/config/locales/ca.yml +173 -65
- data/config/locales/cs.yml +187 -79
- data/config/locales/da-DK.yml +1 -0
- data/config/locales/de.yml +266 -162
- data/config/locales/el-GR.yml +1 -0
- data/config/locales/el.yml +876 -0
- data/config/locales/en.yml +179 -71
- data/config/locales/es-MX.yml +173 -63
- data/config/locales/es-PY.yml +173 -63
- data/config/locales/es.yml +173 -65
- data/config/locales/et-EE.yml +1 -0
- data/config/locales/eu.yml +43 -63
- data/config/locales/fi-plain.yml +173 -65
- data/config/locales/fi.yml +215 -107
- data/config/locales/fr-CA.yml +876 -0
- data/config/locales/fr.yml +151 -65
- data/config/locales/ga-IE.yml +1 -0
- data/config/locales/gl.yml +43 -63
- data/config/locales/hr-HR.yml +1 -0
- data/config/locales/hu.yml +153 -75
- data/config/locales/id-ID.yml +43 -62
- data/config/locales/is-IS.yml +274 -0
- data/config/locales/it.yml +172 -82
- data/config/locales/ja-JP.yml +886 -0
- data/config/locales/lt-LT.yml +1 -0
- data/config/locales/lv-LV.yml +858 -0
- data/config/locales/mt-MT.yml +1 -0
- data/config/locales/nl.yml +274 -188
- data/config/locales/no.yml +786 -0
- data/config/locales/pl.yml +194 -66
- data/config/locales/pt-BR.yml +44 -67
- data/config/locales/pt.yml +437 -331
- data/config/locales/ro-RO.yml +840 -0
- data/config/locales/ru.yml +14 -47
- data/config/locales/sk-SK.yml +896 -0
- data/config/locales/sk.yml +869 -0
- data/config/locales/sl.yml +26 -0
- data/config/locales/sr-CS.yml +126 -0
- data/config/locales/sv.yml +253 -162
- data/config/locales/tr-TR.yml +43 -63
- data/config/locales/uk.yml +14 -47
- data/db/migrate/20181003074440_fix_user_groups_ids_in_proposals_endorsements.rb +4 -0
- data/db/migrate/20191206154128_add_endorsements_counter_cache_to_proposals.rb +7 -0
- data/db/migrate/20200120215928_move_proposal_endorsements_to_core_endorsements.rb +52 -0
- data/db/migrate/20200203111239_add_proposal_valuation_assignments.rb +12 -0
- data/db/migrate/20200210135152_add_costs_to_proposals.rb +9 -0
- data/db/migrate/20200212120110_sync_proposals_state_with_amendments_state.rb +28 -0
- data/db/migrate/20200227175922_add_state_published_at_to_proposals.rb +7 -0
- data/db/migrate/20200306123652_publish_existing_proposals_state.rb +15 -0
- data/db/migrate/20200730131631_move_proposal_endorsed_event_notifications_to_resource_endorsed_event.rb +20 -0
- data/lib/decidim/proposals.rb +1 -0
- data/lib/decidim/proposals/admin_engine.rb +7 -3
- data/lib/decidim/proposals/component.rb +47 -23
- data/lib/decidim/proposals/engine.rb +2 -6
- data/lib/decidim/proposals/test/capybara_proposals_picker.rb +49 -0
- data/lib/decidim/proposals/test/factories.rb +56 -10
- data/lib/decidim/proposals/valuatable.rb +21 -0
- data/lib/decidim/proposals/version.rb +1 -1
- metadata +94 -53
- data/app/assets/javascripts/decidim/proposals/identity_selector_dialog.js.es6 +0 -56
- data/app/cells/decidim/proposals/endorsers_list/show.erb +0 -17
- data/app/cells/decidim/proposals/endorsers_list_cell.rb +0 -31
- data/app/commands/decidim/proposals/attachment_methods.rb +0 -43
- data/app/commands/decidim/proposals/endorse_proposal.rb +0 -59
- data/app/commands/decidim/proposals/unendorse_proposal.rb +0 -40
- data/app/controllers/decidim/proposals/proposal_endorsements_controller.rb +0 -60
- data/app/models/decidim/proposals/proposal_endorsement.rb +0 -37
- data/app/views/decidim/proposals/admin/proposal_answers/edit.html.erb +0 -22
- data/app/views/decidim/proposals/admin/proposal_notes/index.html.erb +0 -3
- data/app/views/decidim/proposals/admin/shared/_info_proposal.html.erb +0 -20
- data/app/views/decidim/proposals/proposal_endorsements/_identity.html.erb +0 -9
- data/app/views/decidim/proposals/proposal_endorsements/identities.html.erb +0 -12
- data/app/views/decidim/proposals/proposal_endorsements/update_buttons_and_counters.js.erb +0 -20
- data/app/views/decidim/proposals/proposal_widgets/show.html.erb +0 -4
- data/app/views/decidim/proposals/proposals/_endorsement_button.html.erb +0 -11
- data/app/views/decidim/proposals/proposals/_endorsement_identities_cabin.html.erb +0 -13
- data/app/views/decidim/proposals/versions/_version.html.erb +0 -20
@@ -21,9 +21,9 @@ module Decidim
|
|
21
21
|
#
|
22
22
|
# Returns a string with the value of the css classes.
|
23
23
|
def vote_button_classes(from_proposals_list)
|
24
|
-
return "card__button
|
24
|
+
return "card__button" if from_proposals_list
|
25
25
|
|
26
|
-
"expanded
|
26
|
+
"expanded"
|
27
27
|
end
|
28
28
|
|
29
29
|
# Public: Gets the vote limit for each user, if set.
|
@@ -58,7 +58,15 @@ module Decidim
|
|
58
58
|
def proposal_wizard_stepper_step(step, current_step)
|
59
59
|
return if step == :step_4 && type_of == :collaborative_drafts
|
60
60
|
|
61
|
-
|
61
|
+
attributes = { class: proposal_wizard_step_classes(step, current_step).to_s }
|
62
|
+
step_title = proposal_wizard_step_name(step)
|
63
|
+
if step.to_s.split("_").last.to_i == proposal_wizard_step_number(current_step)
|
64
|
+
current_step_title = proposal_wizard_step_name("current_step")
|
65
|
+
step_title = content_tag(:span, "#{current_step_title}: ", class: "show-for-sr") + step_title
|
66
|
+
attributes["aria-current"] = "step"
|
67
|
+
end
|
68
|
+
|
69
|
+
content_tag(:li, step_title, attributes)
|
62
70
|
end
|
63
71
|
|
64
72
|
# Returns the list with all the steps, in html
|
@@ -77,15 +85,21 @@ module Decidim
|
|
77
85
|
|
78
86
|
# Returns a string with the current step number and the total steps number
|
79
87
|
#
|
80
|
-
# step - A symbol of the target step
|
81
88
|
def proposal_wizard_current_step_of(step)
|
82
89
|
current_step_num = proposal_wizard_step_number(step)
|
83
|
-
content_tag
|
84
|
-
concat t(:"decidim.proposals.proposals.wizard_steps.step_of", current_step_num: current_step_num, total_steps: total_steps)
|
90
|
+
see_steps = content_tag(:span, class: "hide-for-large") do
|
85
91
|
concat " ("
|
86
92
|
concat content_tag :a, t(:"decidim.proposals.proposals.wizard_steps.see_steps"), "data-toggle": "steps"
|
87
93
|
concat ")"
|
88
94
|
end
|
95
|
+
content_tag :span, class: "text-small" do
|
96
|
+
concat t(:"decidim.proposals.proposals.wizard_steps.step_of", current_step_num: current_step_num, total_steps: total_steps)
|
97
|
+
concat see_steps
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def proposal_wizard_steps_title
|
102
|
+
t("title", scope: "decidim.proposals.#{type_of}.wizard_steps")
|
89
103
|
end
|
90
104
|
|
91
105
|
# Returns a boolean if the step has a help text defined
|
@@ -146,12 +160,15 @@ module Decidim
|
|
146
160
|
url
|
147
161
|
end
|
148
162
|
|
149
|
-
def wizard_aside_back_text
|
163
|
+
def wizard_aside_back_text(from = nil)
|
164
|
+
key = "back"
|
165
|
+
key = "back_from_#{from}" if from
|
166
|
+
|
150
167
|
case type_of
|
151
168
|
when :collaborative_drafts
|
152
|
-
t(
|
169
|
+
t(key, scope: "decidim.proposals.collaborative_drafts.wizard_aside").html_safe
|
153
170
|
else
|
154
|
-
t(
|
171
|
+
t(key, scope: "decidim.proposals.proposals.wizard_aside").html_safe
|
155
172
|
end
|
156
173
|
end
|
157
174
|
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
# Simple helpers to handle markup variations for proposals
|
6
|
+
module ProposalsHelper
|
7
|
+
def proposal_reason_callout_args
|
8
|
+
{
|
9
|
+
announcement: {
|
10
|
+
title: proposal_reason_callout_title,
|
11
|
+
body: decidim_sanitize(translated_attribute(@proposal.answer))
|
12
|
+
},
|
13
|
+
callout_class: proposal_reason_callout_class
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def proposal_reason_callout_class
|
18
|
+
case @proposal.state
|
19
|
+
when "accepted"
|
20
|
+
"success"
|
21
|
+
when "evaluating"
|
22
|
+
"warning"
|
23
|
+
when "rejected"
|
24
|
+
"alert"
|
25
|
+
else
|
26
|
+
""
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def proposal_reason_callout_title
|
31
|
+
i18n_key = case @proposal.state
|
32
|
+
when "evaluating"
|
33
|
+
"proposal_in_evaluation_reason"
|
34
|
+
else
|
35
|
+
"proposal_#{@proposal.state}_reason"
|
36
|
+
end
|
37
|
+
|
38
|
+
t(i18n_key, scope: "decidim.proposals.proposals.show")
|
39
|
+
end
|
40
|
+
|
41
|
+
def filter_proposals_state_values
|
42
|
+
Decidim::CheckBoxesTreeHelper::TreeNode.new(
|
43
|
+
Decidim::CheckBoxesTreeHelper::TreePoint.new("", t("decidim.proposals.application_helper.filter_state_values.all")),
|
44
|
+
[
|
45
|
+
Decidim::CheckBoxesTreeHelper::TreePoint.new("accepted", t("decidim.proposals.application_helper.filter_state_values.accepted")),
|
46
|
+
Decidim::CheckBoxesTreeHelper::TreePoint.new("evaluating", t("decidim.proposals.application_helper.filter_state_values.evaluating")),
|
47
|
+
Decidim::CheckBoxesTreeHelper::TreePoint.new("not_answered", t("decidim.proposals.application_helper.filter_state_values.not_answered")),
|
48
|
+
Decidim::CheckBoxesTreeHelper::TreePoint.new("rejected", t("decidim.proposals.application_helper.filter_state_values.rejected"))
|
49
|
+
]
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
def proposal_has_costs?
|
54
|
+
@proposal.cost.present? &&
|
55
|
+
translated_attribute(@proposal.cost_report).present? &&
|
56
|
+
translated_attribute(@proposal.execution_period).present?
|
57
|
+
end
|
58
|
+
|
59
|
+
def resource_version(resource, options = {})
|
60
|
+
return unless resource.respond_to?(:amendable?) && resource.amendable?
|
61
|
+
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -24,6 +24,10 @@ module Decidim
|
|
24
24
|
include Decidim::Amendable
|
25
25
|
include Decidim::NewsletterParticipant
|
26
26
|
include Decidim::Randomable
|
27
|
+
include Decidim::Endorsable
|
28
|
+
include Decidim::Proposals::Valuatable
|
29
|
+
|
30
|
+
POSSIBLE_STATES = %w(not_answered evaluating accepted rejected withdrawn).freeze
|
27
31
|
|
28
32
|
fingerprint fields: [:title, :body]
|
29
33
|
|
@@ -34,8 +38,6 @@ module Decidim
|
|
34
38
|
|
35
39
|
component_manifest_name "proposals"
|
36
40
|
|
37
|
-
has_many :endorsements, foreign_key: "decidim_proposal_id", class_name: "ProposalEndorsement", dependent: :destroy, counter_cache: "proposal_endorsements_count"
|
38
|
-
|
39
41
|
has_many :votes,
|
40
42
|
-> { final },
|
41
43
|
foreign_key: "decidim_proposal_id",
|
@@ -49,14 +51,56 @@ module Decidim
|
|
49
51
|
|
50
52
|
geocoded_by :address, http_headers: ->(proposal) { { "Referer" => proposal.component.organization.host } }
|
51
53
|
|
52
|
-
scope :
|
53
|
-
scope :
|
54
|
-
|
54
|
+
scope :answered, -> { where.not(answered_at: nil) }
|
55
|
+
scope :not_answered, -> { where(answered_at: nil) }
|
56
|
+
|
57
|
+
scope :state_not_published, -> { where(state_published_at: nil) }
|
58
|
+
scope :state_published, -> { where.not(state_published_at: nil).where.not(state: nil) }
|
59
|
+
|
60
|
+
scope :accepted, -> { state_published.where(state: "accepted") }
|
61
|
+
scope :rejected, -> { state_published.where(state: "rejected") }
|
62
|
+
scope :evaluating, -> { state_published.where(state: "evaluating") }
|
55
63
|
scope :withdrawn, -> { where(state: "withdrawn") }
|
56
|
-
scope :except_rejected, -> { where.not(state: "rejected").or(
|
64
|
+
scope :except_rejected, -> { where.not(state: "rejected").or(state_not_published) }
|
57
65
|
scope :except_withdrawn, -> { where.not(state: "withdrawn").or(where(state: nil)) }
|
58
66
|
scope :drafts, -> { where(published_at: nil) }
|
67
|
+
scope :except_drafts, -> { where.not(published_at: nil) }
|
59
68
|
scope :published, -> { where.not(published_at: nil) }
|
69
|
+
scope :official_origin, lambda {
|
70
|
+
where.not(coauthorships_count: 0)
|
71
|
+
.joins(:coauthorships)
|
72
|
+
.where(decidim_coauthorships: { decidim_author_type: "Decidim::Organization" })
|
73
|
+
}
|
74
|
+
scope :citizens_origin, lambda {
|
75
|
+
where.not(coauthorships_count: 0)
|
76
|
+
.joins(:coauthorships)
|
77
|
+
.where.not(decidim_coauthorships: { decidim_author_type: "Decidim::Organization" })
|
78
|
+
}
|
79
|
+
scope :user_group_origin, lambda {
|
80
|
+
where.not(coauthorships_count: 0)
|
81
|
+
.joins(:coauthorships)
|
82
|
+
.where(decidim_coauthorships: { decidim_author_type: "Decidim::UserBaseEntity" })
|
83
|
+
.where.not(decidim_coauthorships: { decidim_user_group_id: nil })
|
84
|
+
}
|
85
|
+
scope :meeting_origin, lambda {
|
86
|
+
where.not(coauthorships_count: 0)
|
87
|
+
.joins(:coauthorships)
|
88
|
+
.where(decidim_coauthorships: { decidim_author_type: "Decidim::Meetings::Meeting" })
|
89
|
+
}
|
90
|
+
scope :sort_by_valuation_assignments_count_asc, lambda {
|
91
|
+
order(sort_by_valuation_assignments_count_nulls_last_query + "ASC NULLS FIRST")
|
92
|
+
}
|
93
|
+
|
94
|
+
scope :sort_by_valuation_assignments_count_desc, lambda {
|
95
|
+
order(sort_by_valuation_assignments_count_nulls_last_query + "DESC NULLS LAST")
|
96
|
+
}
|
97
|
+
|
98
|
+
def self.with_valuation_assigned_to(user, space)
|
99
|
+
valuator_roles = space.user_roles(:valuator).where(user: user)
|
100
|
+
|
101
|
+
includes(:valuation_assignments)
|
102
|
+
.where(decidim_proposals_valuation_assignments: { valuator_role_id: valuator_roles })
|
103
|
+
end
|
60
104
|
|
61
105
|
acts_as_list scope: :decidim_component_id
|
62
106
|
|
@@ -100,10 +144,9 @@ module Decidim
|
|
100
144
|
|
101
145
|
participants_has_voted_ids = Decidim::Proposals::ProposalVote.joins(:proposal).where(proposal: proposals).joins(:author).map(&:decidim_author_id).flatten.compact.uniq
|
102
146
|
|
103
|
-
endorsements_participants_ids = Decidim::
|
104
|
-
|
105
|
-
|
106
|
-
.map(&:decidim_author_id).flatten.compact.uniq
|
147
|
+
endorsements_participants_ids = Decidim::Endorsement.where(resource: proposals)
|
148
|
+
.where(decidim_author_type: "Decidim::UserBaseEntity")
|
149
|
+
.map(&:decidim_author_id).flatten.compact.uniq
|
107
150
|
|
108
151
|
(endorsements_participants_ids + participants_has_voted_ids + coauthors_recipients_ids).flatten.compact.uniq
|
109
152
|
end
|
@@ -124,54 +167,75 @@ module Decidim
|
|
124
167
|
ProposalVote.where(proposal: self, author: user).any?
|
125
168
|
end
|
126
169
|
|
127
|
-
# Public:
|
128
|
-
# - user_group: may be nil if user is not representing any user_group.
|
170
|
+
# Public: Checks if the proposal has been published or not.
|
129
171
|
#
|
130
172
|
# Returns Boolean.
|
131
|
-
def
|
132
|
-
|
173
|
+
def published?
|
174
|
+
published_at.present?
|
133
175
|
end
|
134
176
|
|
135
|
-
# Public:
|
177
|
+
# Public: Returns the published state of the proposal.
|
136
178
|
#
|
137
179
|
# Returns Boolean.
|
138
|
-
def
|
139
|
-
|
180
|
+
def state
|
181
|
+
return amendment.state if emendation?
|
182
|
+
return nil unless published_state? || withdrawn?
|
183
|
+
|
184
|
+
super
|
185
|
+
end
|
186
|
+
|
187
|
+
# This is only used to define the setter, as the getter will be overriden below.
|
188
|
+
alias_attribute :internal_state, :state
|
189
|
+
|
190
|
+
# Public: Returns the internal state of the proposal.
|
191
|
+
#
|
192
|
+
# Returns Boolean.
|
193
|
+
def internal_state
|
194
|
+
return amendment.state if emendation?
|
195
|
+
|
196
|
+
self[:state]
|
197
|
+
end
|
198
|
+
|
199
|
+
# Public: Checks if the organization has published the state for the proposal.
|
200
|
+
#
|
201
|
+
# Returns Boolean.
|
202
|
+
def published_state?
|
203
|
+
emendation? || state_published_at.present?
|
140
204
|
end
|
141
205
|
|
142
206
|
# Public: Checks if the organization has given an answer for the proposal.
|
143
207
|
#
|
144
208
|
# Returns Boolean.
|
145
209
|
def answered?
|
146
|
-
answered_at.present?
|
210
|
+
answered_at.present?
|
211
|
+
end
|
212
|
+
|
213
|
+
# Public: Checks if the author has withdrawn the proposal.
|
214
|
+
#
|
215
|
+
# Returns Boolean.
|
216
|
+
def withdrawn?
|
217
|
+
internal_state == "withdrawn"
|
147
218
|
end
|
148
219
|
|
149
220
|
# Public: Checks if the organization has accepted a proposal.
|
150
221
|
#
|
151
222
|
# Returns Boolean.
|
152
223
|
def accepted?
|
153
|
-
|
224
|
+
state == "accepted"
|
154
225
|
end
|
155
226
|
|
156
227
|
# Public: Checks if the organization has rejected a proposal.
|
157
228
|
#
|
158
229
|
# Returns Boolean.
|
159
230
|
def rejected?
|
160
|
-
|
231
|
+
state == "rejected"
|
161
232
|
end
|
162
233
|
|
163
234
|
# Public: Checks if the organization has marked the proposal as evaluating it.
|
164
235
|
#
|
165
236
|
# Returns Boolean.
|
166
237
|
def evaluating?
|
167
|
-
|
168
|
-
end
|
169
|
-
|
170
|
-
# Public: Checks if the author has withdrawn the proposal.
|
171
|
-
#
|
172
|
-
# Returns Boolean.
|
173
|
-
def withdrawn?
|
174
|
-
state == "withdrawn"
|
238
|
+
state == "evaluating"
|
175
239
|
end
|
176
240
|
|
177
241
|
# Public: Overrides the `reported_content_url` Reportable concern method.
|
@@ -221,7 +285,7 @@ module Decidim
|
|
221
285
|
def editable_by?(user)
|
222
286
|
return true if draft?
|
223
287
|
|
224
|
-
!
|
288
|
+
!published_state? && within_edit_time_limit? && !copied_from_other_component? && created_by?(user)
|
225
289
|
end
|
226
290
|
|
227
291
|
# Checks whether the user can withdraw the given proposal.
|
@@ -249,6 +313,69 @@ module Decidim
|
|
249
313
|
Arel.sql(query)
|
250
314
|
end
|
251
315
|
|
316
|
+
# Defines the base query so that ransack can actually sort by this value
|
317
|
+
def self.sort_by_valuation_assignments_count_nulls_last_query
|
318
|
+
<<-SQL
|
319
|
+
(
|
320
|
+
SELECT COUNT(decidim_proposals_valuation_assignments.id)
|
321
|
+
FROM decidim_proposals_valuation_assignments
|
322
|
+
WHERE decidim_proposals_valuation_assignments.decidim_proposal_id = decidim_proposals_proposals.id
|
323
|
+
GROUP BY decidim_proposals_valuation_assignments.decidim_proposal_id
|
324
|
+
)
|
325
|
+
SQL
|
326
|
+
end
|
327
|
+
|
328
|
+
# method to filter by assigned valuator role ID
|
329
|
+
def self.valuator_role_ids_has(value)
|
330
|
+
query = <<-SQL
|
331
|
+
:value = any(
|
332
|
+
(SELECT decidim_proposals_valuation_assignments.valuator_role_id
|
333
|
+
FROM decidim_proposals_valuation_assignments
|
334
|
+
WHERE decidim_proposals_valuation_assignments.decidim_proposal_id = decidim_proposals_proposals.id
|
335
|
+
)
|
336
|
+
)
|
337
|
+
SQL
|
338
|
+
where(query, value: value)
|
339
|
+
end
|
340
|
+
|
341
|
+
def self.ransackable_scopes(_auth = nil)
|
342
|
+
[:valuator_role_ids_has]
|
343
|
+
end
|
344
|
+
|
345
|
+
ransacker :state_published do
|
346
|
+
Arel.sql("CASE
|
347
|
+
WHEN EXISTS (
|
348
|
+
SELECT 1 FROM decidim_amendments
|
349
|
+
WHERE decidim_amendments.decidim_emendation_type = 'Decidim::Proposals::Proposal'
|
350
|
+
AND decidim_amendments.decidim_emendation_id = decidim_proposals_proposals.id
|
351
|
+
) THEN 0
|
352
|
+
WHEN state_published_at IS NULL AND answered_at IS NOT NULL THEN 2
|
353
|
+
WHEN state_published_at IS NOT NULL THEN 1
|
354
|
+
ELSE 0 END
|
355
|
+
")
|
356
|
+
end
|
357
|
+
|
358
|
+
ransacker :state do
|
359
|
+
Arel.sql("CASE WHEN state = 'withdrawn' THEN 'withdrawn' WHEN state_published_at IS NULL THEN NULL ELSE state END")
|
360
|
+
end
|
361
|
+
|
362
|
+
ransacker :id_string do
|
363
|
+
Arel.sql(%{cast("decidim_proposals_proposals"."id" as text)})
|
364
|
+
end
|
365
|
+
|
366
|
+
ransacker :is_emendation do |_parent|
|
367
|
+
query = <<-SQL
|
368
|
+
(
|
369
|
+
SELECT EXISTS (
|
370
|
+
SELECT 1 FROM decidim_amendments
|
371
|
+
WHERE decidim_amendments.decidim_emendation_type = 'Decidim::Proposals::Proposal'
|
372
|
+
AND decidim_amendments.decidim_emendation_id = decidim_proposals_proposals.id
|
373
|
+
)
|
374
|
+
)
|
375
|
+
SQL
|
376
|
+
Arel.sql(query)
|
377
|
+
end
|
378
|
+
|
252
379
|
def self.export_serializer
|
253
380
|
Decidim::Proposals::ProposalSerializer
|
254
381
|
end
|
@@ -270,6 +397,17 @@ module Decidim
|
|
270
397
|
Time.current < limit
|
271
398
|
end
|
272
399
|
|
400
|
+
def process_amendment_state_change!
|
401
|
+
return unless %w(accepted rejected evaluating withdrawn).member?(amendment.state)
|
402
|
+
|
403
|
+
PaperTrail.request(enabled: false) do
|
404
|
+
update!(
|
405
|
+
state: amendment.state,
|
406
|
+
state_published_at: Time.current
|
407
|
+
)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
273
411
|
private
|
274
412
|
|
275
413
|
def copied_from_other_component?
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
# A valuation assignment links a proposal and a Valuator user role.
|
6
|
+
# Valuators will be users in charge of defining the monetary cost of a
|
7
|
+
# proposal.
|
8
|
+
class ValuationAssignment < ApplicationRecord
|
9
|
+
include Decidim::Traceable
|
10
|
+
include Decidim::Loggable
|
11
|
+
|
12
|
+
belongs_to :proposal, foreign_key: "decidim_proposal_id", class_name: "Decidim::Proposals::Proposal"
|
13
|
+
belongs_to :valuator_role, polymorphic: true
|
14
|
+
|
15
|
+
def self.log_presenter_class_for(_log)
|
16
|
+
Decidim::Proposals::AdminLog::ValuationAssignmentPresenter
|
17
|
+
end
|
18
|
+
|
19
|
+
def valuator
|
20
|
+
valuator_role.user
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -8,18 +8,22 @@ module Decidim
|
|
8
8
|
# The public part needs to be implemented yet
|
9
9
|
return permission_action if permission_action.scope != :admin
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
11
|
+
# Valuators can only perform these actions
|
12
|
+
if user_is_valuator?
|
13
|
+
if valuator_assigned_to_proposal?
|
14
|
+
can_create_proposal_note?
|
15
|
+
can_create_proposal_answer?
|
16
|
+
end
|
17
|
+
can_export_proposals?
|
18
|
+
valuator_can_unassign_valuator_from_proposals?
|
19
|
+
|
20
|
+
return permission_action
|
21
|
+
end
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
+
if create_permission_action?
|
24
|
+
can_create_proposal_note?
|
25
|
+
can_create_proposal_from_admin?
|
26
|
+
can_create_proposal_answer?
|
23
27
|
end
|
24
28
|
|
25
29
|
# Admins can only edit official proposals if they are within the
|
@@ -29,15 +33,30 @@ module Decidim
|
|
29
33
|
# Every user allowed by the space can update the category of the proposal
|
30
34
|
allow! if permission_action.subject == :proposal_category && permission_action.action == :update
|
31
35
|
|
36
|
+
# Every user allowed by the space can update the scope of the proposal
|
37
|
+
allow! if permission_action.subject == :proposal_scope && permission_action.action == :update
|
38
|
+
|
32
39
|
# Every user allowed by the space can import proposals from another_component
|
33
40
|
allow! if permission_action.subject == :proposals && permission_action.action == :import
|
34
41
|
|
42
|
+
# Every user allowed by the space can export proposals
|
43
|
+
can_export_proposals?
|
44
|
+
|
35
45
|
# Every user allowed by the space can merge proposals to another component
|
36
46
|
allow! if permission_action.subject == :proposals && permission_action.action == :merge
|
37
47
|
|
38
48
|
# Every user allowed by the space can split proposals to another component
|
39
49
|
allow! if permission_action.subject == :proposals && permission_action.action == :split
|
40
50
|
|
51
|
+
# Every user allowed by the space can assign proposals to a valuator
|
52
|
+
allow! if permission_action.subject == :proposals && permission_action.action == :assign_to_valuator
|
53
|
+
|
54
|
+
# Every user allowed by the space can unassign a valuator from proposals
|
55
|
+
can_unassign_valuator_from_proposals?
|
56
|
+
|
57
|
+
# Only admin users can publish many answers at once
|
58
|
+
toggle_allow(user.admin?) if permission_action.subject == :proposals && permission_action.action == :publish_answers
|
59
|
+
|
41
60
|
if permission_action.subject == :participatory_texts && participatory_texts_are_enabled?
|
42
61
|
# Every user allowed by the space can manage (import, update and publish) participatory texts to proposals
|
43
62
|
allow! if permission_action.action == :manage
|
@@ -52,6 +71,23 @@ module Decidim
|
|
52
71
|
@proposal ||= context.fetch(:proposal, nil)
|
53
72
|
end
|
54
73
|
|
74
|
+
def user_valuator_role
|
75
|
+
@user_valuator_role ||= space.user_roles(:valuator).find_by(user: user)
|
76
|
+
end
|
77
|
+
|
78
|
+
def user_is_valuator?
|
79
|
+
return if user.admin?
|
80
|
+
|
81
|
+
user_valuator_role.present?
|
82
|
+
end
|
83
|
+
|
84
|
+
def valuator_assigned_to_proposal?
|
85
|
+
@valuator_assigned_to_proposal ||=
|
86
|
+
Decidim::Proposals::ValuationAssignment
|
87
|
+
.where(proposal: proposal, valuator_role: user_valuator_role)
|
88
|
+
.any?
|
89
|
+
end
|
90
|
+
|
55
91
|
def admin_creation_is_enabled?
|
56
92
|
current_settings.try(:creation_enabled?) &&
|
57
93
|
component_settings.try(:official_proposals_enabled)
|
@@ -75,6 +111,36 @@ module Decidim
|
|
75
111
|
def participatory_texts_are_enabled?
|
76
112
|
component_settings.participatory_texts_enabled?
|
77
113
|
end
|
114
|
+
|
115
|
+
# There's no special condition to create proposal notes, only
|
116
|
+
# users with access to the admin section can do it.
|
117
|
+
def can_create_proposal_note?
|
118
|
+
allow! if permission_action.subject == :proposal_note
|
119
|
+
end
|
120
|
+
|
121
|
+
# Proposals can only be created from the admin when the
|
122
|
+
# corresponding setting is enabled.
|
123
|
+
def can_create_proposal_from_admin?
|
124
|
+
toggle_allow(admin_creation_is_enabled?) if permission_action.subject == :proposal
|
125
|
+
end
|
126
|
+
|
127
|
+
# Proposals can only be answered from the admin when the
|
128
|
+
# corresponding setting is enabled.
|
129
|
+
def can_create_proposal_answer?
|
130
|
+
toggle_allow(admin_proposal_answering_is_enabled?) if permission_action.subject == :proposal_answer
|
131
|
+
end
|
132
|
+
|
133
|
+
def can_unassign_valuator_from_proposals?
|
134
|
+
allow! if permission_action.subject == :proposals && permission_action.action == :unassign_from_valuator
|
135
|
+
end
|
136
|
+
|
137
|
+
def valuator_can_unassign_valuator_from_proposals?
|
138
|
+
can_unassign_valuator_from_proposals? if user == context.fetch(:valuator, nil)
|
139
|
+
end
|
140
|
+
|
141
|
+
def can_export_proposals?
|
142
|
+
allow! if permission_action.subject == :proposals && permission_action.action == :export
|
143
|
+
end
|
78
144
|
end
|
79
145
|
end
|
80
146
|
end
|