decidim-proposals 0.28.5 → 0.29.0.rc1
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 +1 -18
- data/app/cells/decidim/proposals/cost_report_cell.rb +0 -3
- data/app/cells/decidim/proposals/highlighted_proposals_for_component/show.erb +11 -11
- data/app/cells/decidim/proposals/highlighted_proposals_for_component_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 +2 -3
- data/app/cells/decidim/proposals/proposal_cell.rb +2 -0
- data/app/cells/decidim/proposals/proposal_g/show.erb +23 -0
- data/app/cells/decidim/proposals/proposal_g_cell.rb +48 -0
- data/app/cells/decidim/proposals/proposal_l_cell.rb +18 -19
- data/app/cells/decidim/proposals/proposal_metadata_cell.rb +23 -15
- data/app/commands/decidim/proposals/admin/answer_proposal.rb +2 -1
- data/app/commands/decidim/proposals/admin/assign_proposals_to_valuator.rb +7 -5
- data/app/commands/decidim/proposals/admin/create_proposal.rb +4 -6
- data/app/commands/decidim/proposals/admin/create_proposal_state.rb +15 -0
- data/app/commands/decidim/proposals/admin/destroy_proposal_state.rb +10 -0
- data/app/commands/decidim/proposals/admin/import_proposals.rb +10 -2
- data/app/commands/decidim/proposals/admin/notify_proposal_answer.rb +4 -21
- data/app/commands/decidim/proposals/admin/unassign_proposals_from_valuator.rb +6 -4
- data/app/commands/decidim/proposals/admin/update_proposal_state.rb +13 -0
- data/app/commands/decidim/proposals/create_proposal.rb +21 -2
- data/app/commands/decidim/proposals/update_proposal.rb +2 -2
- data/app/commands/decidim/proposals/vote_proposal.rb +1 -1
- data/app/commands/decidim/proposals/withdraw_proposal.rb +3 -7
- data/app/controllers/concerns/decidim/proposals/admin/filterable.rb +10 -22
- data/app/controllers/decidim/proposals/admin/proposal_states_controller.rb +86 -0
- data/app/controllers/decidim/proposals/admin/proposals_controller.rb +4 -0
- data/app/controllers/decidim/proposals/admin/valuation_assignments_controller.rb +8 -11
- data/app/controllers/decidim/proposals/proposals_controller.rb +38 -39
- data/app/events/decidim/proposals/proposal_state_changed_event.rb +37 -0
- data/app/forms/decidim/proposals/admin/proposal_answer_form.rb +8 -4
- data/app/forms/decidim/proposals/admin/proposal_form.rb +1 -1
- data/app/forms/decidim/proposals/admin/proposal_state_form.rb +22 -0
- data/app/forms/decidim/proposals/admin/proposals_fork_form.rb +1 -1
- data/app/forms/decidim/proposals/admin/proposals_import_form.rb +1 -1
- data/app/forms/decidim/proposals/admin/valuation_assignment_form.rb +12 -14
- data/app/forms/decidim/proposals/proposal_form.rb +25 -4
- data/app/forms/decidim/proposals/reject_access_to_collaborative_draft_form.rb +1 -1
- data/app/forms/decidim/proposals/request_access_to_collaborative_draft_form.rb +1 -1
- data/app/helpers/decidim/proposals/admin/proposal_bulk_actions_helper.rb +7 -17
- data/app/helpers/decidim/proposals/admin/proposals_helper.rb +13 -89
- data/app/helpers/decidim/proposals/application_helper.rb +16 -10
- data/app/helpers/decidim/proposals/map_helper.rb +1 -1
- data/app/helpers/decidim/proposals/proposal_cells_helper.rb +6 -2
- data/app/helpers/decidim/proposals/proposal_votes_helper.rb +3 -3
- data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +5 -8
- data/app/helpers/decidim/proposals/proposals_helper.rb +18 -24
- data/app/models/decidim/proposals/proposal.rb +83 -29
- data/app/models/decidim/proposals/proposal_state.rb +58 -0
- data/app/packs/documents/decidim/proposals/participatory_texts/participatory_text.md +1 -3
- data/app/packs/images/decidim/proposals/proposal-placeholder-card-g.svg +15 -0
- data/app/packs/src/decidim/proposals/add_proposal.js +2 -0
- data/app/packs/src/decidim/proposals/admin/proposals.js +43 -8
- data/app/packs/stylesheets/decidim/proposals/proposals.scss +39 -1
- data/app/permissions/decidim/proposals/admin/permissions.rb +16 -4
- data/app/permissions/decidim/proposals/permissions.rb +3 -4
- data/app/presenters/decidim/proposals/admin_log/proposal_state_presenter.rb +21 -0
- data/app/presenters/decidim/proposals/proposal_presenter.rb +12 -3
- data/app/queries/decidim/proposals/metrics/endorsements_metric_manage.rb +1 -1
- data/app/queries/decidim/proposals/metrics/proposal_followers_metric_measure.rb +1 -1
- data/app/queries/decidim/proposals/metrics/proposal_participants_metric_measure.rb +4 -4
- data/app/queries/decidim/proposals/metrics/proposals_metric_manage.rb +1 -1
- data/app/queries/decidim/proposals/metrics/votes_metric_manage.rb +1 -1
- data/app/services/decidim/proposals/diff_renderer.rb +1 -3
- data/app/services/decidim/proposals/proposal_builder.rb +1 -1
- data/app/views/decidim/proposals/admin/imports/_proposals_fields.html.erb +1 -1
- data/app/views/decidim/proposals/admin/participatory_texts/index.html.erb +3 -2
- data/app/views/decidim/proposals/admin/proposal_answers/_form.html.erb +2 -2
- data/app/views/decidim/proposals/admin/proposal_notes/_proposal_notes.html.erb +3 -3
- data/app/views/decidim/proposals/admin/proposal_states/_form.html.erb +67 -0
- data/app/views/decidim/proposals/admin/proposal_states/edit.html.erb +18 -0
- data/app/views/decidim/proposals/admin/proposal_states/index.html.erb +50 -0
- data/app/views/decidim/proposals/admin/proposal_states/new.html.erb +18 -0
- data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +6 -12
- data/app/views/decidim/proposals/admin/proposals/_form.html.erb +6 -6
- data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +2 -2
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_assign_to_valuator.html.erb +11 -7
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_dropdown.html.erb +7 -5
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_merge.html.erb +2 -2
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_publish_answers.html.erb +2 -2
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_recategorize.html.erb +2 -2
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_scope-change.html.erb +2 -2
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_split.html.erb +2 -2
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_unassign_from_valuator.html.erb +11 -7
- data/app/views/decidim/proposals/admin/proposals/bulk_actions/_valuators_picker.html.erb +12 -0
- data/app/views/decidim/proposals/admin/proposals/index.html.erb +11 -7
- data/app/views/decidim/proposals/admin/proposals/publish_answers.js.erb +1 -1
- data/app/views/decidim/proposals/admin/proposals/show.html.erb +3 -2
- data/app/views/decidim/proposals/admin/proposals/update_attribute.js.erb +3 -3
- data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +12 -5
- data/app/views/decidim/proposals/proposals/_proposal.html.erb +1 -1
- data/app/views/decidim/proposals/proposals/_proposal_aside.html.erb +1 -1
- data/app/views/decidim/proposals/proposals/_proposals.html.erb +9 -3
- data/app/views/decidim/proposals/proposals/_vote_button.html.erb +1 -1
- data/app/views/decidim/proposals/proposals/_voting_rules.html.erb +3 -3
- data/app/views/decidim/proposals/proposals/_wizard_header.html.erb +0 -1
- data/app/views/decidim/proposals/proposals/index.html.erb +1 -1
- data/app/views/decidim/proposals/proposals/index.js.erb +0 -12
- data/app/views/decidim/proposals/proposals/new.html.erb +2 -7
- data/app/views/decidim/proposals/proposals/participatory_texts/_proposal_vote_button.html.erb +4 -4
- data/app/views/decidim/proposals/proposals/participatory_texts/_proposal_votes_count.html.erb +8 -8
- data/app/views/decidim/proposals/proposals/preview.html.erb +1 -1
- data/app/views/decidim/proposals/proposals/show.html.erb +3 -3
- data/config/locales/ar.yml +9 -115
- data/config/locales/bg.yml +117 -111
- data/config/locales/ca.yml +86 -83
- data/config/locales/cs.yml +65 -127
- data/config/locales/de.yml +128 -125
- data/config/locales/el.yml +8 -121
- data/config/locales/en.yml +110 -107
- data/config/locales/es-MX.yml +85 -82
- data/config/locales/es-PY.yml +88 -85
- data/config/locales/es.yml +83 -80
- data/config/locales/eu.yml +166 -170
- data/config/locales/fi-plain.yml +90 -87
- data/config/locales/fi.yml +139 -136
- data/config/locales/fr-CA.yml +92 -87
- data/config/locales/fr.yml +83 -78
- data/config/locales/ga-IE.yml +1 -27
- data/config/locales/gl.yml +11 -107
- data/config/locales/he-IL.yml +0 -17
- data/config/locales/hu.yml +18 -90
- data/config/locales/id-ID.yml +6 -106
- data/config/locales/is-IS.yml +8 -33
- data/config/locales/it.yml +14 -103
- data/config/locales/ja.yml +117 -112
- data/config/locales/lb.yml +1 -0
- data/config/locales/lt.yml +6 -123
- data/config/locales/lv.yml +4 -101
- data/config/locales/nl.yml +11 -102
- data/config/locales/no.yml +7 -108
- data/config/locales/pl.yml +110 -115
- data/config/locales/pt-BR.yml +10 -84
- data/config/locales/pt.yml +9 -109
- data/config/locales/ro-RO.yml +15 -117
- data/config/locales/ru.yml +9 -53
- data/config/locales/sk.yml +5 -109
- data/config/locales/sl.yml +4 -0
- data/config/locales/sv.yml +142 -337
- data/config/locales/tr-TR.yml +64 -108
- data/config/locales/uk.yml +11 -55
- data/config/locales/zh-CN.yml +5 -100
- data/config/locales/zh-TW.yml +8 -119
- data/db/migrate/20240110203500_add_withdrawn_at_field_to_proposals.rb +27 -0
- data/db/migrate/20240110203501_create_decidim_proposals_proposal_state.rb +14 -0
- data/db/migrate/20240110203502_add_state_id_to_decidim_proposals_proposals.rb +13 -0
- data/db/migrate/20240110203503_remove_state_from_decidim_proposals_proposals.rb +11 -0
- data/db/migrate/20240110203504_create_default_proposal_states.rb +31 -0
- data/db/migrate/20240209092404_change_color_fields_on_proposals_states.rb +54 -0
- data/decidim-proposals.gemspec +3 -3
- data/lib/decidim/api/proposal_type.rb +4 -13
- data/lib/decidim/api/proposals_type.rb +3 -1
- data/lib/decidim/proposals/admin_engine.rb +8 -0
- data/lib/decidim/proposals/admin_filter.rb +37 -0
- data/lib/decidim/proposals/component.rb +8 -5
- data/lib/decidim/proposals/engine.rb +1 -15
- data/lib/decidim/proposals/import/proposal_answer_creator.rb +6 -6
- data/lib/decidim/proposals/import/proposal_creator.rb +1 -1
- data/lib/decidim/proposals/markdown_to_proposals.rb +2 -8
- data/lib/decidim/proposals/proposal_serializer.rb +8 -9
- data/lib/decidim/proposals/seeds.rb +60 -51
- data/lib/decidim/proposals/test/factories.rb +69 -14
- data/lib/decidim/proposals/version.rb +1 -1
- data/lib/decidim/proposals.rb +84 -12
- data/lib/tasks/proposals/upgrade/{decdim_proposals_upgrade_tasks.rake → decidim_proposals_upgrade_tasks.rake} +0 -13
- metadata +51 -40
- data/app/events/decidim/proposals/accepted_proposal_event.rb +0 -17
- data/app/events/decidim/proposals/evaluating_proposal_event.rb +0 -11
- data/app/events/decidim/proposals/rejected_proposal_event.rb +0 -17
- data/app/forms/decidim/proposals/proposal_wizard_create_step_form.rb +0 -44
- data/app/queries/decidim/proposals/similar_proposals.rb +0 -67
- data/app/services/decidim/proposals/collaborative_draft_diff_renderer.rb +0 -22
- data/app/views/decidim/proposals/proposals/_endorsements_card_row.html.erb +0 -0
- data/app/views/decidim/proposals/proposals/_proposal_badge.html.erb +0 -3
- data/app/views/decidim/proposals/proposals/compare.html.erb +0 -24
- data/app/views/decidim/proposals/proposals/complete.html.erb +0 -31
- data/config/locales/bn-BD.yml +0 -1
- data/config/locales/bs-BA.yml +0 -100
@@ -13,6 +13,8 @@ module Decidim
|
|
13
13
|
|
14
14
|
private
|
15
15
|
|
16
|
+
delegate :filters, :dynamically_translated_filters, :filters_with_values, to: :filter_config
|
17
|
+
|
16
18
|
# Comment about participatory_texts_enabled.
|
17
19
|
def base_query
|
18
20
|
return collection.order(:position) if current_component.settings.participatory_texts_enabled?
|
@@ -30,32 +32,18 @@ module Decidim
|
|
30
32
|
:id_string_or_title_cont
|
31
33
|
end
|
32
34
|
|
33
|
-
def
|
34
|
-
|
35
|
-
:is_emendation_true,
|
36
|
-
:with_any_state,
|
37
|
-
:state_eq,
|
38
|
-
:scope_id_eq,
|
39
|
-
:category_id_eq,
|
40
|
-
:valuator_role_ids_has
|
41
|
-
]
|
35
|
+
def filter_config
|
36
|
+
@filter_config ||= Decidim::AdminFilter.new(:proposals).build_for(self)
|
42
37
|
end
|
43
38
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
with_any_state: %w(state_published state_not_published),
|
49
|
-
scope_id_eq: scope_ids_hash(scopes.top_level),
|
50
|
-
category_id_eq: category_ids_hash(categories.first_class),
|
51
|
-
valuator_role_ids_has: valuator_role_ids
|
52
|
-
}
|
39
|
+
def translated_state_eq(state)
|
40
|
+
return t("decidim.admin.filters.proposals.state_eq.values.withdrawn") if state == "withdrawn"
|
41
|
+
|
42
|
+
translated_attribute(ProposalState.where(component: current_component, token: state).first&.title)
|
53
43
|
end
|
54
44
|
|
55
|
-
|
56
|
-
|
57
|
-
def dynamically_translated_filters
|
58
|
-
[:scope_id_eq, :category_id_eq, :valuator_role_ids_has]
|
45
|
+
def state_eq_values
|
46
|
+
ProposalState.where(component: current_component).pluck(:token) + ["withdrawn"]
|
59
47
|
end
|
60
48
|
|
61
49
|
def valuator_role_ids
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
module Admin
|
6
|
+
class ProposalStatesController < Admin::ApplicationController
|
7
|
+
include Decidim::Admin::Paginable
|
8
|
+
|
9
|
+
helper_method :proposal_states, :proposal_state
|
10
|
+
def index
|
11
|
+
enforce_permission_to :read, :proposal_state
|
12
|
+
end
|
13
|
+
|
14
|
+
def new
|
15
|
+
enforce_permission_to :create, :proposal_state
|
16
|
+
@form = form(Decidim::Proposals::Admin::ProposalStateForm).instance
|
17
|
+
end
|
18
|
+
|
19
|
+
def create
|
20
|
+
enforce_permission_to :create, :proposal_state
|
21
|
+
|
22
|
+
@form = form(ProposalStateForm).from_params(params)
|
23
|
+
|
24
|
+
CreateProposalState.call(@form) do
|
25
|
+
on(:ok) do
|
26
|
+
flash[:notice] = I18n.t("proposal_states.create.success", scope: "decidim.proposals.admin")
|
27
|
+
redirect_to proposal_states_path
|
28
|
+
end
|
29
|
+
|
30
|
+
on(:invalid) do
|
31
|
+
flash.keep[:alert] = I18n.t("proposal_states.create.error", scope: "decidim.proposals.admin")
|
32
|
+
|
33
|
+
render action: :new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def edit
|
39
|
+
enforce_permission_to(:update, :proposal_state, proposal_state:)
|
40
|
+
@form = form(Decidim::Proposals::Admin::ProposalStateForm).from_model(proposal_state)
|
41
|
+
end
|
42
|
+
|
43
|
+
def update
|
44
|
+
enforce_permission_to(:update, :proposal_state, proposal_state:)
|
45
|
+
@form = form(ProposalStateForm).from_params(params)
|
46
|
+
|
47
|
+
UpdateProposalState.call(@form, proposal_state) do
|
48
|
+
on(:ok) do
|
49
|
+
flash[:notice] = I18n.t("proposal_states.update.success", scope: "decidim.proposals.admin")
|
50
|
+
|
51
|
+
redirect_to proposal_states_path
|
52
|
+
end
|
53
|
+
|
54
|
+
on(:invalid) do
|
55
|
+
flash.now[:alert] = I18n.t("proposal_states.update.error", scope: "decidim.proposals.admin")
|
56
|
+
|
57
|
+
render action: :edit
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def destroy
|
63
|
+
enforce_permission_to(:destroy, :proposal_state, proposal_state:)
|
64
|
+
|
65
|
+
DestroyProposalState.call(proposal_state, current_user) do
|
66
|
+
on(:ok) do
|
67
|
+
flash[:notice] = I18n.t("proposal_states.destroy.success", scope: "decidim.proposals.admin")
|
68
|
+
|
69
|
+
redirect_to proposal_states_path
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def proposal_state
|
77
|
+
@proposal_state ||= proposal_states.find(params[:id])
|
78
|
+
end
|
79
|
+
|
80
|
+
def proposal_states
|
81
|
+
@proposal_states ||= paginate(ProposalState.where(component: current_component))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -14,6 +14,10 @@ module Decidim
|
|
14
14
|
helper_method :proposals, :query, :form_presenter, :proposal, :proposal_ids
|
15
15
|
helper Proposals::Admin::ProposalBulkActionsHelper
|
16
16
|
|
17
|
+
before_action :check_admin_session_filters, only: [:index]
|
18
|
+
|
19
|
+
def index; end
|
20
|
+
|
17
21
|
def show
|
18
22
|
@notes_form = form(ProposalNoteForm).instance
|
19
23
|
@answer_form = form(Admin::ProposalAnswerForm).from_model(proposal)
|
@@ -5,10 +5,12 @@ module Decidim
|
|
5
5
|
module Admin
|
6
6
|
class ValuationAssignmentsController < Admin::ApplicationController
|
7
7
|
def create
|
8
|
-
enforce_permission_to :assign_to_valuator, :proposals
|
9
|
-
|
10
8
|
@form = form(Admin::ValuationAssignmentForm).from_params(params)
|
11
9
|
|
10
|
+
@form.proposals.each do |proposal|
|
11
|
+
enforce_permission_to :assign_to_valuator, :proposals, proposal:
|
12
|
+
end
|
13
|
+
|
12
14
|
Admin::AssignProposalsToValuator.call(@form) do
|
13
15
|
on(:ok) do |_proposal|
|
14
16
|
flash[:notice] = I18n.t("valuation_assignments.create.success", scope: "decidim.proposals.admin")
|
@@ -23,9 +25,11 @@ module Decidim
|
|
23
25
|
end
|
24
26
|
|
25
27
|
def destroy
|
26
|
-
@form = form(Admin::ValuationAssignmentForm).from_params(
|
28
|
+
@form = form(Admin::ValuationAssignmentForm).from_params(params)
|
27
29
|
|
28
|
-
|
30
|
+
@form.valuator_roles.each do |valuator_role|
|
31
|
+
enforce_permission_to :unassign_from_valuator, :proposals, valuator: valuator_role.user
|
32
|
+
end
|
29
33
|
|
30
34
|
Admin::UnassignProposalsFromValuator.call(@form) do
|
31
35
|
on(:ok) do |_proposal|
|
@@ -42,13 +46,6 @@ module Decidim
|
|
42
46
|
|
43
47
|
private
|
44
48
|
|
45
|
-
def destroy_params
|
46
|
-
{
|
47
|
-
id: params.dig(:valuator_role, :id) || params[:id],
|
48
|
-
proposal_ids: params[:proposal_ids] || [params[:proposal_id]]
|
49
|
-
}
|
50
|
-
end
|
51
|
-
|
52
49
|
def skip_manage_component_permission
|
53
50
|
true
|
54
51
|
end
|
@@ -7,6 +7,7 @@ module Decidim
|
|
7
7
|
helper ProposalWizardHelper
|
8
8
|
helper ParticipatoryTextsHelper
|
9
9
|
helper UserGroupHelper
|
10
|
+
helper Decidim::Admin::IconLinkHelper
|
10
11
|
include Decidim::ApplicationHelper
|
11
12
|
include Flaggable
|
12
13
|
include Withdrawable
|
@@ -18,18 +19,17 @@ module Decidim
|
|
18
19
|
|
19
20
|
helper_method :proposal_presenter, :form_presenter, :tab_panel_items
|
20
21
|
|
21
|
-
before_action :authenticate_user!, only: [:new, :create
|
22
|
-
before_action :ensure_is_draft, only: [:
|
22
|
+
before_action :authenticate_user!, only: [:new, :create]
|
23
|
+
before_action :ensure_is_draft, only: [:preview, :publish, :edit_draft, :update_draft, :destroy_draft]
|
23
24
|
before_action :set_proposal, only: [:show, :edit, :update, :withdraw]
|
24
25
|
before_action :edit_form, only: [:edit_draft, :edit]
|
26
|
+
before_action :set_view_mode, only: [:index]
|
25
27
|
|
26
28
|
before_action :set_participatory_text
|
27
29
|
|
28
30
|
# rubocop:disable Naming/VariableNumber
|
29
31
|
STEP1 = :step_1
|
30
32
|
STEP2 = :step_2
|
31
|
-
STEP3 = :step_3
|
32
|
-
STEP4 = :step_4
|
33
33
|
# rubocop:enable Naming/VariableNumber
|
34
34
|
|
35
35
|
def index
|
@@ -43,11 +43,13 @@ module Decidim
|
|
43
43
|
.order(position: :asc)
|
44
44
|
render "decidim/proposals/proposals/participatory_texts/participatory_text"
|
45
45
|
else
|
46
|
-
@
|
46
|
+
@base_query = search
|
47
|
+
.result
|
48
|
+
.published
|
49
|
+
.not_hidden
|
47
50
|
|
48
|
-
@proposals =
|
49
|
-
@
|
50
|
-
@proposals = @proposals.includes(:component, :coauthorships, :attachments)
|
51
|
+
@proposals = @base_query.includes(:component, :coauthorships, :attachments)
|
52
|
+
@all_geocoded_proposals = @base_query.geocoded
|
51
53
|
|
52
54
|
@voted_proposals = if current_user
|
53
55
|
ProposalVote.where(
|
@@ -57,6 +59,8 @@ module Decidim
|
|
57
59
|
else
|
58
60
|
[]
|
59
61
|
end
|
62
|
+
@proposals = reorder(@proposals)
|
63
|
+
@proposals = paginate(@proposals)
|
60
64
|
end
|
61
65
|
end
|
62
66
|
|
@@ -70,20 +74,21 @@ module Decidim
|
|
70
74
|
if proposal_draft.present?
|
71
75
|
redirect_to edit_draft_proposal_path(proposal_draft, component_id: proposal_draft.component.id, question_slug: proposal_draft.component.participatory_space.slug)
|
72
76
|
else
|
73
|
-
@form = form(
|
77
|
+
@form = form(ProposalForm).from_params(body: translated_proposal_body_template)
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
77
81
|
def create
|
78
82
|
enforce_permission_to :create, :proposal
|
79
83
|
@step = STEP1
|
80
|
-
@form = form(
|
84
|
+
@form = form(ProposalForm).from_params(proposal_creation_params)
|
81
85
|
|
82
86
|
CreateProposal.call(@form, current_user) do
|
83
87
|
on(:ok) do |proposal|
|
84
88
|
flash[:notice] = I18n.t("proposals.create.success", scope: "decidim")
|
85
89
|
|
86
|
-
|
90
|
+
@proposal = proposal
|
91
|
+
redirect_to "#{Decidim::ResourceLocatorPresenter.new(proposal).path}/preview"
|
87
92
|
end
|
88
93
|
|
89
94
|
on(:invalid) do
|
@@ -93,37 +98,15 @@ module Decidim
|
|
93
98
|
end
|
94
99
|
end
|
95
100
|
|
96
|
-
def compare
|
97
|
-
enforce_permission_to :edit, :proposal, proposal: @proposal
|
98
|
-
@step = STEP2
|
99
|
-
@similar_proposals ||= Decidim::Proposals::SimilarProposals
|
100
|
-
.for(current_component, @proposal)
|
101
|
-
.all
|
102
|
-
|
103
|
-
if @similar_proposals.blank?
|
104
|
-
flash[:notice] = I18n.t("proposals.proposals.compare.no_similars_found", scope: "decidim")
|
105
|
-
redirect_to "#{Decidim::ResourceLocatorPresenter.new(@proposal).path}/complete"
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def complete
|
110
|
-
enforce_permission_to :edit, :proposal, proposal: @proposal
|
111
|
-
@step = STEP3
|
112
|
-
|
113
|
-
@form = form_proposal_model
|
114
|
-
|
115
|
-
@form.attachment = form_attachment_new
|
116
|
-
end
|
117
|
-
|
118
101
|
def preview
|
119
102
|
enforce_permission_to :edit, :proposal, proposal: @proposal
|
120
|
-
@step =
|
103
|
+
@step = STEP2
|
121
104
|
@form = form(ProposalForm).from_model(@proposal)
|
122
105
|
end
|
123
106
|
|
124
107
|
def publish
|
125
108
|
enforce_permission_to :edit, :proposal, proposal: @proposal
|
126
|
-
@step =
|
109
|
+
@step = STEP2
|
127
110
|
PublishProposal.call(@proposal, current_user) do
|
128
111
|
on(:ok) do
|
129
112
|
flash[:notice] = I18n.t("proposals.publish.success", scope: "decidim")
|
@@ -138,7 +121,7 @@ module Decidim
|
|
138
121
|
end
|
139
122
|
|
140
123
|
def edit_draft
|
141
|
-
@step =
|
124
|
+
@step = STEP1
|
142
125
|
enforce_permission_to :edit, :proposal, proposal: @proposal
|
143
126
|
end
|
144
127
|
|
@@ -205,8 +188,8 @@ module Decidim
|
|
205
188
|
flash[:notice] = I18n.t("proposals.update.success", scope: "decidim")
|
206
189
|
redirect_to Decidim::ResourceLocatorPresenter.new(@proposal).path
|
207
190
|
end
|
208
|
-
on(:
|
209
|
-
flash[:alert] = I18n.t("proposals.withdraw.errors.
|
191
|
+
on(:has_votes) do
|
192
|
+
flash[:alert] = I18n.t("proposals.withdraw.errors.has_votes", scope: "decidim")
|
210
193
|
redirect_to Decidim::ResourceLocatorPresenter.new(@proposal).path
|
211
194
|
end
|
212
195
|
end
|
@@ -224,13 +207,20 @@ module Decidim
|
|
224
207
|
with_any_origin: nil,
|
225
208
|
activity: "all",
|
226
209
|
with_any_category: nil,
|
227
|
-
with_any_state:
|
210
|
+
with_any_state: default_states,
|
228
211
|
with_any_scope: nil,
|
229
212
|
related_to: "",
|
230
213
|
type: "all"
|
231
214
|
}
|
232
215
|
end
|
233
216
|
|
217
|
+
def default_states
|
218
|
+
[
|
219
|
+
Decidim::Proposals::ProposalState.where(component: current_component).pluck(:token).map(&:to_s),
|
220
|
+
%w(state_not_published)
|
221
|
+
].flatten - ["rejected"]
|
222
|
+
end
|
223
|
+
|
234
224
|
def proposal_draft
|
235
225
|
Proposal.from_all_author_identities(current_user).not_hidden.only_amendables
|
236
226
|
.where(component: current_component).find_by(published_at: nil)
|
@@ -329,6 +319,15 @@ module Decidim
|
|
329
319
|
}
|
330
320
|
] + attachments_tab_panel_items(@proposal)
|
331
321
|
end
|
322
|
+
|
323
|
+
def set_view_mode
|
324
|
+
@view_mode ||= params[:view_mode] || session[:view_mode] || default_view_mode
|
325
|
+
session[:view_mode] = @view_mode
|
326
|
+
end
|
327
|
+
|
328
|
+
def default_view_mode
|
329
|
+
@default_view_mode ||= current_component.settings.attachments_allowed? ? "grid" : "list"
|
330
|
+
end
|
332
331
|
end
|
333
332
|
end
|
334
333
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# i18n-tasks-use t('decidim.events.proposals.proposal_state_changed.affected_user.notification_title')
|
4
|
+
# i18n-tasks-use t('decidim.events.proposals.proposal_state_changed.affected_user.email_subject')
|
5
|
+
# i18n-tasks-use t('decidim.events.proposals.proposal_state_changed.affected_user.email_outro')
|
6
|
+
# i18n-tasks-use t('decidim.events.proposals.proposal_state_changed.affected_user.email_intro')
|
7
|
+
# i18n-tasks-use t('decidim.events.proposals.proposal_state_changed.follower.notification_title')
|
8
|
+
# i18n-tasks-use t('decidim.events.proposals.proposal_state_changed.follower.email_subject')
|
9
|
+
# i18n-tasks-use t('decidim.events.proposals.proposal_state_changed.follower.email_outro')
|
10
|
+
# i18n-tasks-use t('decidim.events.proposals.proposal_state_changed.follower.email_intro')
|
11
|
+
module Decidim
|
12
|
+
module Proposals
|
13
|
+
class ProposalStateChangedEvent < Decidim::Events::SimpleEvent
|
14
|
+
include Decidim::Events::AuthorEvent
|
15
|
+
|
16
|
+
def resource_text
|
17
|
+
translated_attribute(resource.answer)
|
18
|
+
end
|
19
|
+
|
20
|
+
def event_has_roles?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_i18n_options
|
25
|
+
super.merge({ state: })
|
26
|
+
end
|
27
|
+
|
28
|
+
def state
|
29
|
+
if resource.emendation?
|
30
|
+
humanize_proposal_state(model.state)
|
31
|
+
else
|
32
|
+
translated_attribute(resource.proposal_state&.title)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -8,13 +8,13 @@ module Decidim
|
|
8
8
|
include TranslatableAttributes
|
9
9
|
mimic :proposal_answer
|
10
10
|
|
11
|
-
translatable_attribute :answer,
|
12
|
-
translatable_attribute :cost_report,
|
13
|
-
translatable_attribute :execution_period,
|
11
|
+
translatable_attribute :answer, String
|
12
|
+
translatable_attribute :cost_report, String
|
13
|
+
translatable_attribute :execution_period, String
|
14
14
|
attribute :cost, Float
|
15
15
|
attribute :internal_state, String
|
16
16
|
|
17
|
-
validates :internal_state, presence: true, inclusion: { in:
|
17
|
+
validates :internal_state, presence: true, inclusion: { in: :proposal_states }
|
18
18
|
validates :answer, translatable_presence: true, if: ->(form) { form.state == "rejected" }
|
19
19
|
|
20
20
|
with_options if: :costs_required? do
|
@@ -35,6 +35,10 @@ module Decidim
|
|
35
35
|
|
36
36
|
private
|
37
37
|
|
38
|
+
def proposal_states
|
39
|
+
Decidim::Proposals::ProposalState.where(component: current_component).pluck(:token).map(&:to_s) + ["not_answered"]
|
40
|
+
end
|
41
|
+
|
38
42
|
def costs_enabled?
|
39
43
|
current_component.current_settings.answers_with_costs?
|
40
44
|
end
|
@@ -10,7 +10,7 @@ module Decidim
|
|
10
10
|
translatable_attribute :title, String do |field, _locale|
|
11
11
|
validates field, length: { in: 15..150 }, if: proc { |resource| resource.send(field).present? }
|
12
12
|
end
|
13
|
-
translatable_attribute :body,
|
13
|
+
translatable_attribute :body, String
|
14
14
|
|
15
15
|
validates :title, :body, translatable_presence: true
|
16
16
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
module Admin
|
6
|
+
class ProposalStateForm < Decidim::Form
|
7
|
+
include Decidim::TranslatableAttributes
|
8
|
+
|
9
|
+
mimic :proposal_state
|
10
|
+
|
11
|
+
translatable_attribute :title, String
|
12
|
+
translatable_attribute :announcement_title, String
|
13
|
+
attribute :bg_color, String, default: "#F3F4F7"
|
14
|
+
attribute :text_color, String, default: "#3E4C5C"
|
15
|
+
|
16
|
+
validates :title, translatable_presence: true
|
17
|
+
validates :bg_color, presence: true
|
18
|
+
validates :text_color, presence: true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -39,7 +39,7 @@ module Decidim
|
|
39
39
|
|
40
40
|
proposals.each do |proposal|
|
41
41
|
errors_set << :not_official unless proposal.official?
|
42
|
-
errors_set << :
|
42
|
+
errors_set << :voted if proposal.votes.any? || proposal.endorsements.any?
|
43
43
|
end
|
44
44
|
|
45
45
|
errors_set.each { |error| errors.add(:base, error) } if errors_set.any?
|
@@ -19,7 +19,7 @@ module Decidim
|
|
19
19
|
validates :import_proposals, allow_nil: false, acceptance: true
|
20
20
|
validate :valid_states
|
21
21
|
|
22
|
-
VALID_STATES = %w(accepted not_answered evaluating rejected
|
22
|
+
VALID_STATES = %w(accepted not_answered evaluating rejected).freeze
|
23
23
|
|
24
24
|
def states_collection
|
25
25
|
VALID_STATES.map do |state|
|
@@ -4,32 +4,30 @@ module Decidim
|
|
4
4
|
module Proposals
|
5
5
|
module Admin
|
6
6
|
class ValuationAssignmentForm < Decidim::Form
|
7
|
-
mimic :valuator_role
|
8
|
-
|
9
7
|
attribute :id, Integer
|
10
8
|
attribute :proposal_ids, Array
|
9
|
+
attribute :valuator_role_ids, Array
|
11
10
|
|
12
|
-
validates :
|
11
|
+
validates :valuator_roles, :proposals, :current_component, presence: true
|
13
12
|
validate :same_participatory_space
|
14
13
|
|
15
14
|
def proposals
|
16
15
|
@proposals ||= Decidim::Proposals::Proposal.where(component: current_component, id: proposal_ids).uniq
|
17
16
|
end
|
18
17
|
|
19
|
-
def
|
20
|
-
@
|
21
|
-
end
|
22
|
-
|
23
|
-
def valuator_user
|
24
|
-
return unless valuator_role
|
25
|
-
|
26
|
-
@valuator_user ||= valuator_role.user
|
18
|
+
def valuator_roles
|
19
|
+
@valuator_roles ||= current_component.participatory_space.user_roles(:valuator).where(id: valuator_role_ids)
|
27
20
|
end
|
28
21
|
|
29
22
|
def same_participatory_space
|
30
|
-
return if
|
31
|
-
|
32
|
-
|
23
|
+
return if valuator_roles.empty? || !current_component
|
24
|
+
|
25
|
+
valuator_roles.each do |valuator_role|
|
26
|
+
if current_component.participatory_space != valuator_role.participatory_space
|
27
|
+
errors.add(:id, :invalid)
|
28
|
+
break
|
29
|
+
end
|
30
|
+
end
|
33
31
|
end
|
34
32
|
end
|
35
33
|
end
|
@@ -3,13 +3,17 @@
|
|
3
3
|
module Decidim
|
4
4
|
module Proposals
|
5
5
|
# A form object to be used when public users want to create a proposal.
|
6
|
-
class ProposalForm < Decidim::
|
6
|
+
class ProposalForm < Decidim::Form
|
7
7
|
include Decidim::TranslatableAttributes
|
8
8
|
include Decidim::AttachmentAttributes
|
9
9
|
include Decidim::HasUploadValidations
|
10
10
|
|
11
11
|
mimic :proposal
|
12
12
|
|
13
|
+
attribute :title, String
|
14
|
+
attribute :body, Decidim::Attributes::CleanString
|
15
|
+
attribute :body_template, String
|
16
|
+
attribute :user_group_id, Integer
|
13
17
|
attribute :address, String
|
14
18
|
attribute :latitude, Float
|
15
19
|
attribute :longitude, Float
|
@@ -20,23 +24,34 @@ module Decidim
|
|
20
24
|
|
21
25
|
attachments_attribute :documents
|
22
26
|
|
27
|
+
validates :title, :body, presence: true, etiquette: true
|
28
|
+
validates :title, length: { in: 15..150 }
|
29
|
+
validates :body, proposal_length: {
|
30
|
+
minimum: 15,
|
31
|
+
maximum: ->(record) { record.component.settings.proposal_length }
|
32
|
+
}
|
23
33
|
validates :address, geocoding: true, if: ->(form) { form.has_address? && !form.geocoded? }
|
24
34
|
validates :category, presence: true, if: ->(form) { form.category_id.present? }
|
25
35
|
validates :scope, presence: true, if: ->(form) { form.scope_id.present? }
|
26
36
|
validates :scope_id, scope_belongs_to_component: true, if: ->(form) { form.scope_id.present? }
|
37
|
+
|
38
|
+
validate :body_is_not_bare_template
|
27
39
|
validate :notify_missing_attachment_if_errored
|
28
40
|
|
41
|
+
alias component current_component
|
29
42
|
delegate :categories, to: :current_component
|
30
43
|
|
31
44
|
def map_model(model)
|
32
|
-
|
33
|
-
|
34
|
-
body = translated_attribute(model.body)
|
45
|
+
self.title = translated_attribute(model.title)
|
46
|
+
self.body = translated_attribute(model.body)
|
35
47
|
@suggested_hashtags = Decidim::ContentRenderers::HashtagRenderer.new(body).extra_hashtags.map(&:name).map(&:downcase)
|
36
48
|
|
37
49
|
presenter = ProposalPresenter.new(model)
|
38
50
|
self.body = presenter.editor_body(all_locales: body.is_a?(Hash))
|
39
51
|
|
52
|
+
self.user_group_id = model.user_groups.first&.id
|
53
|
+
self.category_id = model.categorization.decidim_category_id if model.categorization
|
54
|
+
|
40
55
|
# The scope attribute is with different key (decidim_scope_id), so it
|
41
56
|
# has to be manually mapped.
|
42
57
|
self.scope_id = model.scope.id if model.scope
|
@@ -100,6 +115,12 @@ module Decidim
|
|
100
115
|
|
101
116
|
private
|
102
117
|
|
118
|
+
def body_is_not_bare_template
|
119
|
+
return if body_template.blank?
|
120
|
+
|
121
|
+
errors.add(:body, :cant_be_equal_to_template) if body.presence == body_template.presence
|
122
|
+
end
|
123
|
+
|
103
124
|
# This method will add an error to the "add_documents" field only if there is any error
|
104
125
|
# in any other field. This is needed because when the form has an error, the attachment
|
105
126
|
# is lost, so we need a way to inform the user of this problem.
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Decidim
|
4
4
|
module Proposals
|
5
|
-
# A form object to be used when Collaborative Draft editors rejects a request to
|
5
|
+
# A form object to be used when Collaborative Draft editors rejects a request to access it.
|
6
6
|
class RejectAccessToCollaborativeDraftForm < AccessToCollaborativeDraftForm
|
7
7
|
end
|
8
8
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Decidim
|
4
4
|
module Proposals
|
5
|
-
# A form object to be used when public users want to request
|
5
|
+
# A form object to be used when public users want to request access to a Collaborative Draft.
|
6
6
|
class RequestAccessToCollaborativeDraftForm < Decidim::Form
|
7
7
|
mimic :collaborative_draft
|
8
8
|
|
@@ -8,26 +8,16 @@ module Decidim
|
|
8
8
|
Decidim::Proposals::Proposal.find(id)
|
9
9
|
end
|
10
10
|
|
11
|
-
#
|
12
|
-
|
13
|
-
# participatory_space - A participatory space instance.
|
14
|
-
# prompt - An i18n string to show as prompt
|
15
|
-
#
|
16
|
-
# Returns a String.
|
17
|
-
def bulk_valuators_select(participatory_space, prompt)
|
18
|
-
options_for_select = find_valuators_for_select(participatory_space)
|
19
|
-
select(:valuator_role, :id, options_for_select, prompt:)
|
20
|
-
end
|
21
|
-
|
22
|
-
# Internal: A method to cache to queries to find the valuators for the
|
23
|
-
# current space.
|
24
|
-
def find_valuators_for_select(participatory_space)
|
25
|
-
return @valuators_for_select if @valuators_for_select
|
26
|
-
|
11
|
+
# find the valuators for the current space.
|
12
|
+
def find_valuators_for_select(participatory_space, current_user)
|
27
13
|
valuator_roles = participatory_space.user_roles(:valuator)
|
28
14
|
valuators = Decidim::User.where(id: valuator_roles.pluck(:decidim_user_id)).to_a
|
29
15
|
|
30
|
-
|
16
|
+
filtered_valuator_roles = valuator_roles.filter do |role|
|
17
|
+
role.decidim_user_id != current_user.id
|
18
|
+
end
|
19
|
+
|
20
|
+
filtered_valuator_roles.map do |role|
|
31
21
|
valuator = valuators.find { |user| user.id == role.decidim_user_id }
|
32
22
|
|
33
23
|
[valuator.name, role.id]
|