decidim-reporting_proposals 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|