decidim-reporting_proposals 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +32 -0
- data/.erb-lint.yml +30 -0
- data/.eslintignore +3 -0
- data/.eslintrc.json +239 -0
- data/.github/workflows/codeql-analysis.yml +74 -0
- data/.github/workflows/lint.yml +45 -0
- data/.github/workflows/test_integration.yml +125 -0
- data/.github/workflows/test_unit.yml +51 -0
- data/.gitignore +27 -0
- data/.rspec +3 -0
- data/.rubocop.yml +3 -0
- data/.rubocop_rails.yml +87 -0
- data/.rubocop_ruby.yml +1754 -0
- data/.ruby-version +1 -0
- data/.simplecov +13 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +40 -0
- data/Gemfile.lock +815 -0
- data/LICENSE-AGPLv3.txt +661 -0
- data/README.md +166 -0
- data/Rakefile +40 -0
- data/app/cells/decidim/reporting_proposals/edit_note_modal/show.erb +20 -0
- data/app/cells/decidim/reporting_proposals/edit_note_modal_cell.rb +37 -0
- data/app/commands/concerns/decidim/reporting_proposals/admin/create_category_override.rb +32 -0
- data/app/commands/concerns/decidim/reporting_proposals/admin/update_category_override.rb +32 -0
- data/app/commands/concerns/decidim/reporting_proposals/create_report_override.rb +19 -0
- data/app/commands/decidim/reporting_proposals/admin/update_proposal.rb +46 -0
- data/app/commands/decidim/reporting_proposals/admin/update_proposal_note.rb +36 -0
- data/app/commands/decidim/reporting_proposals/create_reporting_proposal.rb +68 -0
- data/app/controllers/concerns/decidim/reporting_proposals/admin/categories_controller_override.rb +16 -0
- data/app/controllers/concerns/decidim/reporting_proposals/admin/needs_header_snippets.rb +50 -0
- data/app/controllers/concerns/decidim/reporting_proposals/admin/proposal_answer_templates_controller_override.rb +18 -0
- data/app/controllers/concerns/decidim/reporting_proposals/admin/proposal_answers_controller_override.rb +35 -0
- data/app/controllers/concerns/decidim/reporting_proposals/admin/proposals_controller_override.rb +28 -0
- data/app/controllers/concerns/decidim/reporting_proposals/needs_proposal_extra_validations_snippets.rb +51 -0
- data/app/controllers/concerns/decidim/reporting_proposals/proposals_controller_override.rb +113 -0
- data/app/controllers/decidim/reporting_proposals/admin/application_controller.rb +18 -0
- data/app/controllers/decidim/reporting_proposals/admin/proposal_notes_controller.rb +38 -0
- data/app/controllers/decidim/reporting_proposals/admin/proposals_controller.rb +61 -0
- data/app/controllers/decidim/reporting_proposals/application_controller.rb +11 -0
- data/app/controllers/decidim/reporting_proposals/geolocation_controller.rb +32 -0
- data/app/forms/concerns/decidim/reporting_proposals/admin/category_form_override.rb +19 -0
- data/app/forms/concerns/decidim/reporting_proposals/form_builder_override.rb +48 -0
- data/app/forms/concerns/decidim/reporting_proposals/map_builder_override.rb +60 -0
- data/app/forms/decidim/reporting_proposals/admin/proposal_photo_form.rb +23 -0
- data/app/forms/decidim/reporting_proposals/proposal_form.rb +33 -0
- data/app/helpers/concerns/decidim/reporting_proposals/admin/proposals_helper_override.rb +63 -0
- data/app/helpers/concerns/decidim/reporting_proposals/proposal_wizard_helper_override.rb +61 -0
- data/app/jobs/decidim/reporting_proposals/assign_proposal_valuators_job.rb +51 -0
- data/app/models/concerns/decidim/reporting_proposals/category_override.rb +28 -0
- data/app/models/concerns/decidim/reporting_proposals/participatory_space_role_config/valuator_override.rb +17 -0
- data/app/models/concerns/decidim/reporting_proposals/participatory_space_user_role_override.rb +25 -0
- data/app/models/decidim/reporting_proposals/category_valuator.rb +28 -0
- data/app/overrides/decidim/admin/categories/_form/add_valuators_field.html.erb.deface +3 -0
- data/app/overrides/decidim/admin/categories/index/add_table_column_name.html.erb.deface +3 -0
- data/app/overrides/decidim/admin/categories/index/add_valuators.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/admin/proposal_notes/_proposal_notes/add_edit_link.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/admin/proposal_notes/_proposal_notes/add_links_to_note.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/admin/proposals/_proposal-tr/add_td_hide_action.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/admin/proposals/_proposal-tr/add_valuators_name.html.erb.deface +9 -0
- data/app/overrides/decidim/proposals/admin/proposals/_proposal-tr/replace_td_title.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/admin/proposals/show/add_photo_management.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/admin/proposals/show/add_send_email_btn.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/admin/proposals/show/remove_photos.html.erb.deface +4 -0
- data/app/overrides/decidim/proposals/admin/proposals/show/replace_valuators.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/proposals/_proposal_similar/add_distance_badge.html.erb.deface +5 -0
- data/app/overrides/decidim/proposals/proposals/_wizard_header/replace_title.html.erb.deface +14 -0
- data/app/overrides/decidim/proposals/proposals/edit/add_user_group.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/proposals/edit/replace_javascript.html.erb.deface +8 -0
- data/app/overrides/decidim/proposals/proposals/edit/replace_partial_edit_form_fields.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/proposals/edit_draft/add_user_group.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/proposals/edit_draft/replace_javascript.html.erb.deface +8 -0
- data/app/overrides/decidim/proposals/proposals/edit_draft/replace_partial_edit_form_fields.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/proposals/index/add_additional_button.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/proposals/new/remove_title.html.erb.deface +1 -0
- data/app/overrides/decidim/proposals/proposals/new/replace_body.html.erb.deface +3 -0
- data/app/overrides/decidim/proposals/proposals/new/replace_javascript.html.erb.deface +8 -0
- data/app/overrides/decidim/proposals/proposals/show/add_additional_button.html.erb.deface +3 -0
- data/app/overrides/layouts/decidim/_process_header_steps/always_show_new_proposals.html.erb.deface +3 -0
- data/app/packs/entrypoints/decidim_reporting_proposals.js +6 -0
- data/app/packs/entrypoints/decidim_reporting_proposals_camera.js +2 -0
- data/app/packs/entrypoints/decidim_reporting_proposals_geocoding.js +2 -0
- data/app/packs/entrypoints/decidim_reporting_proposals_js_validations.js +1 -0
- data/app/packs/entrypoints/decidim_reporting_proposals_list_component_admin.js +1 -0
- data/app/packs/entrypoints/decidim_reporting_proposals_manage_component_admin.js +1 -0
- data/app/packs/images/.keep +0 -0
- data/app/packs/src/decidim/reporting_proposals/proposal_extra_validations.js +89 -0
- data/app/packs/src/decidim/reporting_proposals/proposals/add_proposal.js +66 -0
- data/app/packs/src/decidim/reporting_proposals/reverse_geocoding.js +54 -0
- data/app/packs/src/decidim/reporting_proposals/user_camera_inputs.js +49 -0
- data/app/packs/stylesheets/decidim/reporting_proposals/geocoding_addons.scss +34 -0
- data/app/packs/stylesheets/decidim/reporting_proposals/list_component_admin.scss +27 -0
- data/app/packs/stylesheets/decidim/reporting_proposals/manage_component_admin.scss +31 -0
- data/app/packs/stylesheets/decidim/reporting_proposals/proposals/add_proposal.scss +12 -0
- data/app/packs/stylesheets/decidim/reporting_proposals/user_camera_inputs.scss +19 -0
- data/app/permissions/concerns/decidim/reporting_proposals/admin/permissions_override.rb +27 -0
- data/app/permissions/decidim/reporting_proposals/admin/permissions.rb +79 -0
- data/app/permissions/decidim/reporting_proposals/permissions.rb +17 -0
- data/app/queries/decidim/reporting_proposals/nearby_proposals.rb +57 -0
- data/app/serializers/decidim/reporting_proposals/proposal_serializer_override.rb +77 -0
- data/app/validators/concerns/decidim/reporting_proposals/component_validator_override.rb +25 -0
- data/app/views/decidim/proposals/admin/proposal_notes/_editing_note.html.erb +18 -0
- data/app/views/decidim/proposals/admin/proposal_notes/_proposal_notes_body.html.erb +6 -0
- data/app/views/decidim/proposals/admin/proposals/_send_email_button.html.erb +4 -0
- data/app/views/decidim/proposals/proposals/_additional_button.html.erb +6 -0
- data/app/views/decidim/reporting_proposals/admin/categories/_column_valuators.html.erb +1 -0
- data/app/views/decidim/reporting_proposals/admin/categories/_valuators.html.erb +1 -0
- data/app/views/decidim/reporting_proposals/admin/categories/_valuators_field.html.erb +7 -0
- data/app/views/decidim/reporting_proposals/admin/proposals/_photo_form.html.erb +24 -0
- data/app/views/decidim/reporting_proposals/admin/proposals/_photo_gallery.html.erb +21 -0
- data/app/views/decidim/reporting_proposals/admin/proposals/_photos.html.erb +14 -0
- data/app/views/decidim/reporting_proposals/admin/proposals/_proposal_td_hide.html.erb +20 -0
- data/app/views/decidim/reporting_proposals/admin/proposals/_proposal_td_title.html.erb +41 -0
- data/app/views/decidim/reporting_proposals/proposals/_additional_button_for_show.html.erb +6 -0
- data/app/views/decidim/reporting_proposals/proposals/_new_proposal_fields.html.erb +7 -0
- data/app/views/decidim/reporting_proposals/proposals/_reporting_proposal_fields.html.erb +113 -0
- data/app/views/decidim/reporting_proposals/proposals/_user_group.html.erb +5 -0
- data/bin/rails +6 -0
- data/bin/webpack-dev-server +6 -0
- data/codecov.yml +11 -0
- data/config/assets.rb +13 -0
- data/config/i18n-tasks.yml +13 -0
- data/config/locales/ca.yml +366 -0
- data/config/locales/de.yml +366 -0
- data/config/locales/en.yml +426 -0
- data/config/locales/es.yml +366 -0
- data/crowdin.yml +45 -0
- data/db/migrate/20221219151846_create_decidim_categories_valuators.rb +17 -0
- data/decidim-reporting_proposals.gemspec +34 -0
- data/lib/decidim/api/reporting_proposals_type.rb +10 -0
- data/lib/decidim/reporting_proposals/admin.rb +8 -0
- data/lib/decidim/reporting_proposals/admin_engine.rb +31 -0
- data/lib/decidim/reporting_proposals/component.rb +490 -0
- data/lib/decidim/reporting_proposals/config.rb +53 -0
- data/lib/decidim/reporting_proposals/engine.rb +96 -0
- data/lib/decidim/reporting_proposals/test/factories.rb +13 -0
- data/lib/decidim/reporting_proposals/version.rb +15 -0
- data/lib/decidim/reporting_proposals.rb +13 -0
- data/package-lock.json +7844 -0
- data/package.json +195 -0
- metadata +319 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
# Exposes the proposal resource so users can view and create them.
|
6
|
+
module NeedsProposalExtraValidationsSnippets
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
helper_method :snippets
|
11
|
+
end
|
12
|
+
|
13
|
+
def snippets
|
14
|
+
@snippets ||= Decidim::Snippets.new
|
15
|
+
|
16
|
+
unless @snippets.any?(:reporting_proposals_js_validations)
|
17
|
+
@snippets.add(:reporting_proposals_js_validations, ActionController::Base.helpers.javascript_pack_tag("decidim_reporting_proposals_js_validations"))
|
18
|
+
@snippets.add(:reporting_proposals_js_validations, rules_tag)
|
19
|
+
@snippets.add(:head, @snippets.for(:reporting_proposals_js_validations))
|
20
|
+
end
|
21
|
+
@snippets
|
22
|
+
end
|
23
|
+
|
24
|
+
def rules_tag
|
25
|
+
content_tag(:script, "Decidim.ProposalRules = #{rules.to_json};".html_safe)
|
26
|
+
end
|
27
|
+
|
28
|
+
# caps rules are not explicitly used in the JS validations
|
29
|
+
def rules
|
30
|
+
model = Decidim::Proposals::Proposal.new(title: "title", body: "body")
|
31
|
+
etiquette_validator = EtiquetteValidator.new(attributes: [:title, :body])
|
32
|
+
etiquette_validator.validate(model)
|
33
|
+
{
|
34
|
+
genericError: I18n.t("decidim.forms.errors.error"),
|
35
|
+
title: {
|
36
|
+
caps: {
|
37
|
+
enabled: model.errors.details[:title].to_s.include?(":must_start_with_caps"),
|
38
|
+
error: I18n.t("errors.messages.must_start_with_caps")
|
39
|
+
}
|
40
|
+
},
|
41
|
+
body: {
|
42
|
+
caps: {
|
43
|
+
enabled: model.errors.details[:body].to_s.include?(":must_start_with_caps"),
|
44
|
+
error: I18n.t("errors.messages.must_start_with_caps")
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
# Exposes the proposal resource so users can view and create them.
|
6
|
+
module ProposalsControllerOverride
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
include NeedsProposalExtraValidationsSnippets
|
9
|
+
|
10
|
+
included do
|
11
|
+
helper_method :reporting_proposal?, :geocoding_comparison?
|
12
|
+
|
13
|
+
def new
|
14
|
+
enforce_permission_to :create, :proposal
|
15
|
+
@step = :step_1
|
16
|
+
if proposal_draft.present?
|
17
|
+
redirect_to edit_draft_proposal_path(proposal_draft, component_id: proposal_draft.component.id, question_slug: proposal_draft.component.participatory_space.slug)
|
18
|
+
else
|
19
|
+
@form = form(new_proposal_form).from_params(body: translated_proposal_body_template)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def create
|
24
|
+
enforce_permission_to :create, :proposal
|
25
|
+
@step = :step_1
|
26
|
+
@form = form(new_proposal_form).from_params(proposal_creation_params)
|
27
|
+
|
28
|
+
create_proposal_command.call(@form, current_user) do
|
29
|
+
on(:ok) do |proposal|
|
30
|
+
flash[:notice] = I18n.t("proposals.create.success", scope: "decidim")
|
31
|
+
|
32
|
+
redirect_to "#{Decidim::ResourceLocatorPresenter.new(proposal).path}/compare"
|
33
|
+
end
|
34
|
+
|
35
|
+
on(:invalid) do
|
36
|
+
flash.now[:alert] = I18n.t("proposals.create.error", scope: "decidim")
|
37
|
+
render :new
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# change comparison class if geocoding comparison is enabled
|
43
|
+
def compare
|
44
|
+
enforce_permission_to :edit, :proposal, proposal: @proposal
|
45
|
+
@step = :step_2
|
46
|
+
klass = if geocoding_comparison?
|
47
|
+
Decidim::ReportingProposals::NearbyProposals
|
48
|
+
else
|
49
|
+
Decidim::Proposals::SimilarProposals
|
50
|
+
end
|
51
|
+
@similar_proposals ||= klass
|
52
|
+
.for(current_component, @proposal)
|
53
|
+
.all
|
54
|
+
|
55
|
+
if @similar_proposals.blank?
|
56
|
+
flash[:notice] = I18n.t("proposals.proposals.compare.no_similars_found", scope: "decidim")
|
57
|
+
redirect_to "#{Decidim::ResourceLocatorPresenter.new(@proposal).path}/complete"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# disable this step for reporting proposals
|
62
|
+
def complete
|
63
|
+
enforce_permission_to :edit, :proposal, proposal: @proposal
|
64
|
+
@step = :step_3
|
65
|
+
|
66
|
+
@form = form_proposal_model
|
67
|
+
|
68
|
+
@form.attachment = form_attachment_new
|
69
|
+
|
70
|
+
redirect_to "#{Decidim::ResourceLocatorPresenter.new(@proposal).path}/preview" if reporting_proposal?
|
71
|
+
end
|
72
|
+
|
73
|
+
def edit_draft
|
74
|
+
@step = reporting_proposal? ? :step_1 : :step_3
|
75
|
+
enforce_permission_to :edit, :proposal, proposal: @proposal
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def form_proposal_params
|
81
|
+
form(edit_proposal_form).from_params(params)
|
82
|
+
end
|
83
|
+
|
84
|
+
def form_proposal_model
|
85
|
+
form(edit_proposal_form).from_model(@proposal)
|
86
|
+
end
|
87
|
+
|
88
|
+
def edit_proposal_form
|
89
|
+
reporting_proposal? ? Decidim::ReportingProposals::ProposalForm : Decidim::Proposals::ProposalForm
|
90
|
+
end
|
91
|
+
|
92
|
+
def new_proposal_form
|
93
|
+
reporting_proposal? ? Decidim::ReportingProposals::ProposalForm : Decidim::Proposals::ProposalWizardCreateStepForm
|
94
|
+
end
|
95
|
+
|
96
|
+
def create_proposal_command
|
97
|
+
reporting_proposal? ? CreateReportingProposal : Decidim::Proposals::CreateProposal
|
98
|
+
end
|
99
|
+
|
100
|
+
def reporting_proposal?
|
101
|
+
component = current_component || @form.component
|
102
|
+
component.manifest_name == "reporting_proposals"
|
103
|
+
end
|
104
|
+
|
105
|
+
def geocoding_comparison?
|
106
|
+
if Decidim::Map.configured? && component_settings.geocoding_enabled? && component_settings.geocoding_comparison_enabled?
|
107
|
+
@proposal ? @proposal.geocoded? : true
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
module Admin
|
6
|
+
# This controller is the abstract class from which all other controllers of
|
7
|
+
# this engine inherit.
|
8
|
+
#
|
9
|
+
# Note that it inherits from `Decidim::Admin::Components::BaseController`, which
|
10
|
+
# override its layout and provide all kinds of useful methods.
|
11
|
+
class ApplicationController < Decidim::Admin::ApplicationController
|
12
|
+
def permission_class_chain
|
13
|
+
[::Decidim::ReportingProposals::Admin::Permissions] + super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
module Admin
|
6
|
+
class ProposalNotesController < Admin::ApplicationController
|
7
|
+
helper_method :note
|
8
|
+
|
9
|
+
def edit
|
10
|
+
enforce_permission_to :edit_note, :proposal_note, proposal_note: note
|
11
|
+
@notes_form = form(Decidim::Proposals::Admin::ProposalNoteForm).from_model(note)
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
enforce_permission_to :edit_note, :proposal_note, proposal_note: note
|
16
|
+
@notes_form = form(Decidim::Proposals::Admin::ProposalNoteForm).from_params(params)
|
17
|
+
|
18
|
+
Decidim::ReportingProposals::Admin::UpdateProposalNote.call(@notes_form, note) do
|
19
|
+
on(:ok) do
|
20
|
+
flash[:notice] = I18n.t("proposal_notes.update.success", scope: "decidim.reporting_proposals.admin")
|
21
|
+
end
|
22
|
+
|
23
|
+
on(:invalid) do
|
24
|
+
flash[:alert] = I18n.t("proposal_notes.update.invalid", scope: "decidim.reporting_proposals.admin")
|
25
|
+
end
|
26
|
+
redirect_back(fallback_location: decidim_admin.root_path)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def note
|
33
|
+
@note ||= Decidim::Proposals::ProposalNote.find(params[:id])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
module Admin
|
6
|
+
class ProposalsController < Admin::ApplicationController
|
7
|
+
def hide_proposal
|
8
|
+
enforce_permission_to :hide_proposal, :proposals, proposal: proposal
|
9
|
+
|
10
|
+
Decidim::Admin::HideResource.call(proposal, current_user) do
|
11
|
+
on(:ok) do
|
12
|
+
flash[:notice] = I18n.t("reportable.hide.success", scope: "decidim.moderations.admin")
|
13
|
+
end
|
14
|
+
|
15
|
+
on(:invalid) do
|
16
|
+
flash.now[:alert] = I18n.t("reportable.hide.invalid", scope: "decidim.moderations.admin")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
redirect_back(fallback_location: decidim_admin.root_path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_photos
|
23
|
+
enforce_permission_to :edit_photos, :proposals, proposal: proposal
|
24
|
+
|
25
|
+
@photo_form = form(Decidim::ReportingProposals::Admin::ProposalPhotoForm).from_params(params)
|
26
|
+
|
27
|
+
Decidim::ReportingProposals::Admin::UpdateProposal.call(@photo_form, proposal) do
|
28
|
+
on(:ok) do |_proposal|
|
29
|
+
flash[:notice] = t("proposals.update.success", scope: "decidim")
|
30
|
+
end
|
31
|
+
|
32
|
+
on(:invalid) do
|
33
|
+
flash[:alert] = t("proposals.update.error", scope: "decidim")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(proposal).show
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove_photo
|
40
|
+
enforce_permission_to :edit_photos, :proposals, proposal: proposal
|
41
|
+
|
42
|
+
attachment = proposal.attachments.find_by(id: params[:photo_id])
|
43
|
+
if attachment.try(:photo?)
|
44
|
+
attachment.destroy!
|
45
|
+
flash[:notice] = t("proposals.update.success", scope: "decidim")
|
46
|
+
else
|
47
|
+
flash[:alert] = t("proposals.update.error", scope: "decidim")
|
48
|
+
end
|
49
|
+
|
50
|
+
redirect_to Decidim::ResourceLocatorPresenter.new(proposal).show
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def proposal
|
56
|
+
@proposal ||= Decidim::Proposals::Proposal.find(params[:id])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
class GeolocationController < Decidim::ReportingProposals::ApplicationController
|
6
|
+
# overwrite original rescue_from to ensure we print messages from ajax methods (update)
|
7
|
+
rescue_from Decidim::ActionForbidden, with: :ajax_user_has_no_permission
|
8
|
+
|
9
|
+
def locate
|
10
|
+
enforce_permission_to :locate, :geolocation
|
11
|
+
|
12
|
+
unless Decidim::Map.configured?
|
13
|
+
return render(json: { message: I18n.t("unconfigured", scope: "decidim.application.geocoding"), found: false }, status: :unprocessable_entity)
|
14
|
+
end
|
15
|
+
|
16
|
+
geocoder = Decidim::Map.utility(:geocoding, organization: current_organization)
|
17
|
+
address = geocoder.address([params[:latitude], params[:longitude]])
|
18
|
+
render json: { address: address, found: address.present? }
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# Rescue ajax calls and print the update.js view which prints the info on the message ajax form
|
24
|
+
# Only if the request is AJAX, otherwise behave as Decidim standards
|
25
|
+
def ajax_user_has_no_permission
|
26
|
+
return user_has_no_permission unless request.xhr?
|
27
|
+
|
28
|
+
render json: { message: I18n.t("actions.unauthorized", scope: "decidim.core") }, status: :unprocessable_entity
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
module Admin
|
6
|
+
module CategoryFormOverride
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
attribute :valuator_ids, Array[Integer]
|
11
|
+
|
12
|
+
def map_model(model)
|
13
|
+
self.valuator_ids = model.category_valuators.pluck(:valuator_role_id)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
module FormBuilderOverride
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include Decidim::LayoutHelper
|
8
|
+
|
9
|
+
# These methods are used in deeper levels and might not be available in this context when this is called, thus the delegation
|
10
|
+
delegate :asset_pack_path, to: :@template
|
11
|
+
|
12
|
+
included do
|
13
|
+
def file_field(object_name, method, options = {})
|
14
|
+
return super(object_name, method, options) unless use_camera_button?(object_name)
|
15
|
+
|
16
|
+
unless @template.snippets.any?(:reporting_proposals_camera_addons)
|
17
|
+
@template.snippets.add(:reporting_proposals_camera_addons, @template.javascript_pack_tag("decidim_reporting_proposals_camera"))
|
18
|
+
@template.snippets.add(:reporting_proposals_camera_addons, @template.stylesheet_pack_tag("decidim_reporting_proposals_camera"))
|
19
|
+
|
20
|
+
# This will display the snippets in the <head> part of the page.
|
21
|
+
@template.snippets.add(:head, @template.snippets.for(:reporting_proposals_camera_addons))
|
22
|
+
end
|
23
|
+
|
24
|
+
content_tag(:div, class: "input-group") do
|
25
|
+
super(object_name, method, options) +
|
26
|
+
content_tag(:div, class: "input-group-button") do
|
27
|
+
content_tag(:button, class: "button secondary user-device-camera", type: "button", data: { input: "#{object_name}_#{method}" }) do
|
28
|
+
icon("camera-slr", role: "img", "aria-hidden": true) + " #{I18n.t("use_my_camera", scope: "decidim.reporting_proposals.forms")}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def use_camera_button?(object_name)
|
37
|
+
return unless @template.respond_to?(:current_component)
|
38
|
+
|
39
|
+
return unless Decidim::ReportingProposals.use_camera_button.include?(@template.current_component.manifest_name.to_sym)
|
40
|
+
|
41
|
+
return object_name == :add_photos unless Decidim::ReportingProposals.camera_button_on_attachments
|
42
|
+
|
43
|
+
true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
module MapBuilderOverride
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include Decidim::LayoutHelper
|
8
|
+
|
9
|
+
# These methods are used in deeper levels and might not be available in this context when this is called, thus the delegation
|
10
|
+
delegate :content_tag, :asset_pack_path, to: :template
|
11
|
+
|
12
|
+
included do
|
13
|
+
alias_method :original_geocoding_field, :geocoding_field
|
14
|
+
|
15
|
+
def geocoding_field(object_name, method, options = {})
|
16
|
+
return original_geocoding_field(object_name, method, options) unless show_my_location_button?
|
17
|
+
|
18
|
+
unless template.snippets.any?(:reporting_proposals_geocoding_addons)
|
19
|
+
template.snippets.add(:reporting_proposals_geocoding_addons, template.javascript_pack_tag("decidim_reporting_proposals_geocoding"))
|
20
|
+
template.snippets.add(:reporting_proposals_geocoding_addons, template.stylesheet_pack_tag("decidim_reporting_proposals_geocoding"))
|
21
|
+
|
22
|
+
# This will display the snippets in the <head> part of the page.
|
23
|
+
template.snippets.add(:head, template.snippets.for(:reporting_proposals_geocoding_addons))
|
24
|
+
end
|
25
|
+
|
26
|
+
options[:autocomplete] ||= "off"
|
27
|
+
options[:class] ||= "input-group-field"
|
28
|
+
|
29
|
+
template.content_tag(:div, class: "input-group") do
|
30
|
+
template.text_field(
|
31
|
+
object_name,
|
32
|
+
method,
|
33
|
+
options.merge("data-decidim-geocoding" => view_options.to_json)
|
34
|
+
) +
|
35
|
+
template.content_tag(:div, class: "input-group-button user-device-location") do
|
36
|
+
template.content_tag(:button, class: "button secondary", type: "button", data: {
|
37
|
+
input: "#{object_name}_#{method}",
|
38
|
+
latitude: "#{object_name}_latitude",
|
39
|
+
longitude: "#{object_name}_longitude",
|
40
|
+
error_no_location: I18n.t("errors.no_device_location", scope: "decidim.reporting_proposals.forms"),
|
41
|
+
error_unsupported: I18n.t("errors.device_not_supported", scope: "decidim.reporting_proposals.forms"),
|
42
|
+
url: Decidim::ReportingProposals::Engine.routes.url_helpers.locate_path
|
43
|
+
}) do
|
44
|
+
icon("location", role: "img", "aria-hidden": true) + " #{I18n.t("use_my_location", scope: "decidim.reporting_proposals.forms")}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def show_my_location_button?
|
53
|
+
return unless template.respond_to?(:current_component)
|
54
|
+
|
55
|
+
Decidim::ReportingProposals.show_my_location_button.include?(template.current_component.manifest_name.to_sym)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
module Admin
|
6
|
+
class ProposalPhotoForm < Decidim::Form
|
7
|
+
include Decidim::AttachmentAttributes
|
8
|
+
attribute :attachment, AttachmentForm
|
9
|
+
attachments_attribute :photos
|
10
|
+
|
11
|
+
validates :add_photos, presence: true
|
12
|
+
|
13
|
+
def proposal
|
14
|
+
@proposal ||= Decidim::Proposals::Proposal.find(id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def current_component
|
18
|
+
@current_component ||= proposal&.component
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
class ProposalForm < Decidim::Proposals::ProposalForm
|
6
|
+
attribute :address, String
|
7
|
+
attribute :has_no_address, Boolean
|
8
|
+
attribute :has_no_image, Boolean
|
9
|
+
|
10
|
+
validates :add_photos, presence: true, if: ->(form) { form.has_camera? && form.photos.blank? }
|
11
|
+
|
12
|
+
# Set the has no address
|
13
|
+
def map_model(model)
|
14
|
+
super(model)
|
15
|
+
|
16
|
+
self.has_no_address = true if model.address.blank?
|
17
|
+
self.has_no_image = true if model.photo.blank?
|
18
|
+
end
|
19
|
+
|
20
|
+
def has_address?
|
21
|
+
return if has_no_address
|
22
|
+
|
23
|
+
geocoding_enabled?
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_camera?
|
27
|
+
return if has_no_image
|
28
|
+
|
29
|
+
current_component.settings.attachments_allowed?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
module Admin
|
6
|
+
# Exposes the proposal resource so users can view and create them.
|
7
|
+
module ProposalsHelperOverride
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
# Helpers for overdue proposals
|
12
|
+
include ActionView::Helpers::DateHelper
|
13
|
+
|
14
|
+
def unanswered_proposals_overdue?(proposal)
|
15
|
+
grace_period = days_unanswered(proposal)
|
16
|
+
!grace_period.zero? &&
|
17
|
+
proposal.state.blank? && (Time.current - grace_period.days).to_date > proposal.published_at
|
18
|
+
end
|
19
|
+
|
20
|
+
def evaluating_proposals_overdue?(proposal)
|
21
|
+
grace_period = days_evaluating(proposal)
|
22
|
+
!grace_period.zero? &&
|
23
|
+
proposal.evaluating? && proposal.answered? &&
|
24
|
+
(Time.current - grace_period.days).to_date > proposal.answered_at
|
25
|
+
end
|
26
|
+
|
27
|
+
def grace_period_unanswered?(proposal)
|
28
|
+
!proposal.answered? && Time.current < last_day_to_answer(proposal)
|
29
|
+
end
|
30
|
+
|
31
|
+
def days_unanswered(proposal)
|
32
|
+
return proposal.component.settings.unanswered_proposals_overdue.to_i if proposal.component&.settings
|
33
|
+
|
34
|
+
Decidim::ReportingProposals.unanswered_proposals_overdue.to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
def days_evaluating(proposal)
|
38
|
+
return proposal.component.settings.evaluating_proposals_overdue.to_i if proposal.component&.settings
|
39
|
+
|
40
|
+
Decidim::ReportingProposals.evaluating_proposals_overdue.to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
def grace_period_evaluating?(proposal)
|
44
|
+
proposal.evaluating? && Time.current < last_day_to_evaluate(proposal)
|
45
|
+
end
|
46
|
+
|
47
|
+
def last_day_to_answer(proposal)
|
48
|
+
(proposal.published_at + days_unanswered(proposal).days).to_date
|
49
|
+
end
|
50
|
+
|
51
|
+
def last_day_to_evaluate(proposal)
|
52
|
+
(proposal.answered_at + days_evaluating(proposal).days).to_date if proposal.answered?
|
53
|
+
end
|
54
|
+
|
55
|
+
def time_elapsed_to_answer(proposal)
|
56
|
+
distance_of_time_in_words(proposal.answered_at, proposal.created_at,
|
57
|
+
scope: "decidim.reporting_proposals.admin.time_elapsed.datetime.distance_in_words")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module ReportingProposals
|
5
|
+
# Exposes the proposal resource so users can view and create them.
|
6
|
+
module ProposalWizardHelperOverride
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
def proposal_wizard_stepper(current_step)
|
11
|
+
steps = %(
|
12
|
+
#{proposal_wizard_stepper_step(:step_1, current_step)}
|
13
|
+
#{proposal_wizard_stepper_step(:step_2, current_step)}
|
14
|
+
)
|
15
|
+
steps = %(#{steps} #{proposal_wizard_stepper_step(:step_3, current_step)}) unless reporting_proposals_component?
|
16
|
+
steps = %(#{steps} #{proposal_wizard_stepper_step(:step_4, current_step)})
|
17
|
+
|
18
|
+
content_tag :ol, class: "wizard__steps" do
|
19
|
+
steps.html_safe
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def proposal_wizard_current_step_of(step)
|
24
|
+
current_step_num = proposal_wizard_step_number(step)
|
25
|
+
current_step_num = 3 if current_step_num == 4 && reporting_proposals_component?
|
26
|
+
see_steps = content_tag(:span, class: "hide-for-large") do
|
27
|
+
concat " ("
|
28
|
+
concat content_tag :a, t(:"decidim.proposals.proposals.wizard_steps.see_steps"), "data-toggle": "steps"
|
29
|
+
concat ")"
|
30
|
+
end
|
31
|
+
content_tag :span, class: "text-small" do
|
32
|
+
concat t(:"decidim.proposals.proposals.wizard_steps.step_of", current_step_num: current_step_num, total_steps: total_steps)
|
33
|
+
concat see_steps
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# rubocop:disable Rails/HelperInstanceVariable:
|
38
|
+
def distance(meters = nil)
|
39
|
+
meters = @proposal.component.settings.geocoding_comparison_radius.to_f if meters.nil?
|
40
|
+
|
41
|
+
return "#{meters.round}m" if meters < 1000
|
42
|
+
|
43
|
+
"#{(meters / 1000).round}Km"
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def total_steps
|
49
|
+
reporting_proposals_component? ? 3 : 4
|
50
|
+
end
|
51
|
+
|
52
|
+
def reporting_proposals_component?
|
53
|
+
return unless @form&.component&.manifest_name
|
54
|
+
|
55
|
+
@form.component.manifest_name == "reporting_proposals"
|
56
|
+
end
|
57
|
+
# rubocop:enable Rails/HelperInstanceVariable:
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|