decidim-accountability 0.29.2 → 0.30.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/accountability/project/show.erb +6 -0
- data/app/cells/decidim/accountability/project_cell.rb +23 -42
- data/app/cells/decidim/accountability/result_history_cell.rb +57 -0
- data/app/cells/decidim/accountability/result_metadata_cell.rb +17 -17
- data/app/cells/decidim/accountability/status_cell.rb +9 -13
- data/app/commands/decidim/accountability/admin/create_imported_result.rb +1 -1
- data/app/commands/decidim/accountability/admin/create_result.rb +3 -2
- data/app/commands/decidim/accountability/admin/import_component_to_accountability.rb +47 -0
- data/app/commands/decidim/accountability/admin/update_imported_result.rb +1 -1
- data/app/commands/decidim/accountability/admin/update_result.rb +3 -2
- data/app/commands/decidim/accountability/admin/update_result_dates.rb +56 -0
- data/app/commands/decidim/accountability/admin/update_result_status.rb +61 -0
- data/app/commands/decidim/accountability/admin/update_result_taxonomies.rb +18 -0
- data/app/controllers/concerns/decidim/accountability/admin/filterable.rb +8 -6
- data/app/controllers/decidim/accountability/admin/import_components_controller.rb +36 -0
- data/app/controllers/decidim/accountability/admin/results_bulk_actions_controller.rb +102 -0
- data/app/controllers/decidim/accountability/admin/results_controller.rb +21 -11
- data/app/controllers/decidim/accountability/results_controller.rb +10 -7
- data/app/forms/decidim/accountability/admin/import_component_form.rb +98 -0
- data/app/forms/decidim/accountability/admin/result_bulk_actions_form.rb +18 -0
- data/app/forms/decidim/accountability/admin/result_form.rb +17 -23
- data/app/helpers/decidim/accountability/admin/application_helper.rb +0 -1
- data/app/helpers/decidim/accountability/application_helper.rb +1 -32
- data/app/helpers/decidim/accountability/breadcrumb_helper.rb +10 -14
- data/app/jobs/decidim/accountability/admin/import_projects_job.rb +5 -3
- data/app/jobs/decidim/accountability/admin/import_proposals_job.rb +70 -0
- data/app/mailers/decidim/accountability/import_proposals_mailer.rb +28 -0
- data/app/models/decidim/accountability/result.rb +23 -1
- data/app/models/decidim/accountability/status.rb +4 -0
- data/app/packs/entrypoints/decidim_accountability_admin_form.js +1 -0
- data/app/packs/src/decidim/accountability/admin/imports.js +37 -14
- data/app/packs/src/decidim/accountability/admin/index/action_button.js +42 -0
- data/app/packs/src/decidim/accountability/admin/index/action_form.js +46 -0
- data/app/packs/src/decidim/accountability/admin/index/action_selector.js +37 -0
- data/app/packs/src/decidim/accountability/admin/index/counter.js +40 -0
- data/app/packs/src/decidim/accountability/admin/index/select_all.js +29 -0
- data/app/packs/src/decidim/accountability/admin/index.js +17 -7
- data/app/packs/src/decidim/accountability/admin/result_form.js +21 -0
- data/app/packs/stylesheets/accountability.scss +5 -0
- data/app/permissions/decidim/accountability/admin/permissions.rb +3 -2
- data/app/presenters/decidim/accountability/admin_log/result_presenter.rb +1 -1
- data/app/presenters/decidim/accountability/result_presenter.rb +30 -0
- data/app/queries/decidim/accountability/metrics/results_metric_manage.rb +6 -6
- data/app/services/decidim/accountability/results_calculator.rb +4 -6
- data/app/services/decidim/accountability/results_csv_importer.rb +1 -1
- data/app/views/decidim/accountability/admin/import_components/_filters.html.erb +26 -0
- data/app/views/decidim/accountability/admin/import_components/_form.html.erb +26 -0
- data/app/views/decidim/accountability/admin/import_components/new.html.erb +14 -0
- data/app/views/decidim/accountability/admin/results/_actions.html.erb +29 -0
- data/app/views/decidim/accountability/admin/results/_form.html.erb +15 -8
- data/app/views/decidim/accountability/admin/results/_result-tr.html.erb +32 -0
- data/app/views/decidim/accountability/admin/results/_results-thead.html.erb +26 -0
- data/app/views/decidim/accountability/admin/results/bulk_actions/_dates_form.html.erb +19 -0
- data/app/views/decidim/accountability/admin/results/bulk_actions/_dropdown.html.erb +40 -0
- data/app/views/decidim/accountability/admin/results/bulk_actions/_status_form.html.erb +16 -0
- data/app/views/decidim/accountability/admin/results/bulk_actions/_submit_buttons.html.erb +4 -0
- data/app/views/decidim/accountability/admin/results/bulk_actions/_taxonomies_form.html.erb +18 -0
- data/app/views/decidim/accountability/admin/results/edit.html.erb +2 -2
- data/app/views/decidim/accountability/admin/results/index.html.erb +50 -111
- data/app/views/decidim/accountability/admin/results/manage_trash.html.erb +26 -0
- data/app/views/decidim/accountability/admin/results/new.html.erb +2 -2
- data/app/views/decidim/accountability/import_proposals_mailer/import.html.erb +2 -0
- data/app/views/decidim/accountability/results/{_home_categories.html.erb → _home_taxonomies.html.erb} +6 -8
- data/app/views/decidim/accountability/results/_project.html.erb +1 -3
- data/app/views/decidim/accountability/results/_projects_aside.html.erb +9 -7
- data/app/views/decidim/accountability/results/home.html.erb +18 -6
- data/app/views/decidim/accountability/results/index.html.erb +8 -2
- data/app/views/decidim/accountability/results/show.html.erb +5 -5
- data/config/assets.rb +3 -2
- data/config/locales/ar.yml +97 -55
- data/config/locales/bg.yml +0 -50
- data/config/locales/bs-BA.yml +0 -16
- data/config/locales/ca.yml +128 -40
- data/config/locales/cs.yml +147 -56
- data/config/locales/da.yml +0 -20
- data/config/locales/de.yml +126 -39
- data/config/locales/el.yml +0 -48
- data/config/locales/en.yml +128 -40
- data/config/locales/es-MX.yml +129 -41
- data/config/locales/es-PY.yml +129 -41
- data/config/locales/es.yml +129 -41
- data/config/locales/eu.yml +140 -53
- data/config/locales/fi-plain.yml +136 -49
- data/config/locales/fi.yml +136 -49
- data/config/locales/fr-CA.yml +111 -54
- data/config/locales/fr.yml +111 -54
- data/config/locales/ga-IE.yml +0 -13
- data/config/locales/gl.yml +0 -17
- data/config/locales/gn-PY.yml +0 -11
- data/config/locales/he-IL.yml +45 -54
- data/config/locales/hu.yml +0 -50
- data/config/locales/id-ID.yml +0 -16
- data/config/locales/is-IS.yml +0 -17
- data/config/locales/it.yml +0 -18
- data/config/locales/ja.yml +132 -47
- data/config/locales/kaa.yml +0 -8
- data/config/locales/ko.yml +0 -47
- data/config/locales/lb.yml +0 -17
- data/config/locales/lt.yml +0 -50
- data/config/locales/lv.yml +0 -19
- data/config/locales/nl.yml +0 -17
- data/config/locales/no.yml +0 -17
- data/config/locales/pl.yml +0 -47
- data/config/locales/pt-BR.yml +6 -50
- data/config/locales/pt.yml +35 -23
- data/config/locales/ro-RO.yml +0 -29
- data/config/locales/ru.yml +0 -16
- data/config/locales/si-LK.yml +0 -11
- data/config/locales/sk.yml +0 -19
- data/config/locales/sl.yml +0 -17
- data/config/locales/sq-AL.yml +0 -50
- data/config/locales/sr-CS.yml +0 -16
- data/config/locales/sv.yml +124 -36
- data/config/locales/th-TH.yml +0 -50
- data/config/locales/tr-TR.yml +0 -47
- data/config/locales/uk.yml +0 -16
- data/config/locales/zh-CN.yml +0 -20
- data/config/locales/zh-TW.yml +0 -47
- data/db/migrate/20200827154103_add_commentable_counter_cache_to_results.rb +1 -1
- data/db/migrate/20240828103202_add_deleted_at_to_decidim_accountability_results.rb +8 -0
- data/db/migrate/20240916112128_add_geolocation_fields_to_results.rb +9 -0
- data/decidim-accountability.gemspec +1 -1
- data/lib/decidim/accountability/admin_engine.rb +16 -2
- data/lib/decidim/accountability/component.rb +3 -3
- data/lib/decidim/accountability/result_serializer.rb +9 -13
- data/lib/decidim/accountability/seeds.rb +28 -21
- data/lib/decidim/accountability/test/factories.rb +6 -4
- data/lib/decidim/accountability/version.rb +1 -1
- data/lib/decidim/api/accountability_type.rb +4 -5
- data/lib/decidim/api/result_type.rb +10 -13
- data/lib/decidim/api/status_type.rb +3 -4
- data/lib/decidim/api/timeline_entry_type.rb +5 -6
- metadata +58 -30
- data/app/commands/decidim/accountability/admin/import_projects_to_accountability.rb +0 -37
- data/app/controllers/decidim/accountability/admin/projects_import_controller.rb +0 -31
- data/app/forms/decidim/accountability/admin/result_import_projects_form.rb +0 -51
- data/app/views/decidim/accountability/admin/projects_import/new.html.erb +0 -45
- data/app/views/decidim/accountability/results/_nav_breadcrumb.html.erb +0 -37
- data/app/views/decidim/accountability/results/_scope_filters.html.erb +0 -31
- /data/app/packs/entrypoints/{decidim_accountability_admin.js → decidim_accountability_admin_index.js} +0 -0
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Accountability
|
5
|
+
module Admin
|
6
|
+
class ResultsBulkActionsController < Admin::ApplicationController
|
7
|
+
include Decidim::ApplicationHelper
|
8
|
+
include Decidim::SanitizeHelper
|
9
|
+
include Decidim::Admin::ComponentTaxonomiesHelper
|
10
|
+
|
11
|
+
def update_taxonomies
|
12
|
+
enforce_permission_to :create, :bulk_update
|
13
|
+
|
14
|
+
Admin::UpdateResultTaxonomies.call(result_params[:taxonomies], result_ids, current_organization) do
|
15
|
+
on(:invalid_taxonomies) do
|
16
|
+
flash[:alert] = I18n.t(
|
17
|
+
"results.update_taxonomies.select_a_taxonomy",
|
18
|
+
scope: "decidim.accountability.admin"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
on(:invalid_resources) do
|
23
|
+
flash[:alert] = I18n.t(
|
24
|
+
"results.update_taxonomies.select_a_result",
|
25
|
+
scope: "decidim.accountability.admin"
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
on(:update_resources_taxonomies) do |response|
|
30
|
+
if response[:successful].any?
|
31
|
+
flash[:notice] = t(
|
32
|
+
"results.update_taxonomies.success",
|
33
|
+
taxonomies: response[:taxonomies].map { |taxonomy| decidim_escape_translated(taxonomy.name) }.to_sentence,
|
34
|
+
results: response[:successful].map { |resource| decidim_escape_translated(resource.title) }.to_sentence,
|
35
|
+
scope: "decidim.accountability.admin"
|
36
|
+
)
|
37
|
+
end
|
38
|
+
if response[:errored].any?
|
39
|
+
flash[:alert] = t(
|
40
|
+
"results.update_taxonomies.invalid",
|
41
|
+
taxonomies: response[:taxonomies].map { |taxonomy| decidim_escape_translated(taxonomy.name) }.to_sentence,
|
42
|
+
results: response[:errored].map { |resource| decidim_escape_translated(resource.title) }.to_sentence,
|
43
|
+
scope: "decidim.accountability.admin"
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
redirect_to results_path
|
50
|
+
end
|
51
|
+
|
52
|
+
def update_status
|
53
|
+
enforce_permission_to :create, :bulk_update
|
54
|
+
|
55
|
+
UpdateResultStatus.call(result_params[:decidim_accountability_status_id], result_ids, current_user) do
|
56
|
+
on(:ok) do
|
57
|
+
flash[:notice] = I18n.t("results.update_status.success", scope: "decidim.accountability.admin")
|
58
|
+
redirect_to results_path
|
59
|
+
end
|
60
|
+
|
61
|
+
on(:invalid) do
|
62
|
+
flash[:alert] = I18n.t("results.update_status.invalid", scope: "decidim.accountability.admin")
|
63
|
+
redirect_to results_path
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def update_dates
|
69
|
+
enforce_permission_to :create, :bulk_update
|
70
|
+
|
71
|
+
UpdateResultDates.call(result_params[:start_date], result_params[:end_date], result_ids, current_user) do
|
72
|
+
on(:ok) do
|
73
|
+
flash[:notice] = I18n.t("results.update_dates.success", scope: "decidim.accountability.admin")
|
74
|
+
redirect_to results_path
|
75
|
+
end
|
76
|
+
|
77
|
+
on(:invalid) do
|
78
|
+
flash[:alert] = I18n.t("results.update_dates.invalid", scope: "decidim.accountability.admin")
|
79
|
+
redirect_to results_path
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def result_ids
|
87
|
+
result_params[:result_ids].map { |ids| ids.split(",") }.flatten.map(&:to_i)
|
88
|
+
end
|
89
|
+
|
90
|
+
def result_params
|
91
|
+
@result_params ||= params.require(:result_bulk_actions).permit(
|
92
|
+
:decidim_accountability_status_id,
|
93
|
+
:start_date,
|
94
|
+
:end_date,
|
95
|
+
result_ids: [],
|
96
|
+
taxonomies: []
|
97
|
+
)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -7,13 +7,15 @@ module Decidim
|
|
7
7
|
class ResultsController < Admin::ApplicationController
|
8
8
|
include Decidim::ApplicationHelper
|
9
9
|
include Decidim::SanitizeHelper
|
10
|
+
include Decidim::Admin::ComponentTaxonomiesHelper
|
10
11
|
include Decidim::Accountability::Admin::Filterable
|
12
|
+
include Decidim::Admin::HasTrashableResources
|
11
13
|
|
12
|
-
helper_method :results, :parent_result, :parent_results, :statuses, :present
|
14
|
+
helper_method :results, :parent_result, :parent_results, :statuses, :present, :bulk_actions_form
|
13
15
|
|
14
16
|
def collection
|
15
17
|
parent_id = params[:parent_id].presence
|
16
|
-
@collection ||= Result.where(component: current_component, parent_id:).page(params[:page]).per(15)
|
18
|
+
@collection ||= Result.where(component: current_component, parent_id:).page(params[:page]).per(15).order(created_at: :asc)
|
17
19
|
end
|
18
20
|
|
19
21
|
def new
|
@@ -65,19 +67,23 @@ module Decidim
|
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
68
|
-
|
69
|
-
enforce_permission_to(:destroy, :result, result:)
|
70
|
+
private
|
70
71
|
|
71
|
-
|
72
|
-
|
73
|
-
|
72
|
+
def trashable_deleted_resource_type
|
73
|
+
:result
|
74
|
+
end
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
end
|
76
|
+
def trashable_deleted_resource
|
77
|
+
@trashable_deleted_resource ||= Result.with_deleted.where(component: current_component).find_by(id: params[:id])
|
78
78
|
end
|
79
79
|
|
80
|
-
|
80
|
+
def trashable_deleted_collection
|
81
|
+
@trashable_deleted_collection = filtered_collection.only_deleted.deleted_at_desc
|
82
|
+
end
|
83
|
+
|
84
|
+
def find_parent_resource
|
85
|
+
parent_result
|
86
|
+
end
|
81
87
|
|
82
88
|
def results
|
83
89
|
@results ||= filtered_collection
|
@@ -98,6 +104,10 @@ module Decidim
|
|
98
104
|
def statuses
|
99
105
|
@statuses ||= Status.where(component: current_component)
|
100
106
|
end
|
107
|
+
|
108
|
+
def bulk_actions_form
|
109
|
+
@bulk_actions_form ||= ResultBulkActionsForm.new(result_ids: [])
|
110
|
+
end
|
101
111
|
end
|
102
112
|
end
|
103
113
|
end
|
@@ -8,7 +8,7 @@ module Decidim
|
|
8
8
|
helper Decidim::TraceabilityHelper
|
9
9
|
helper Decidim::Accountability::BreadcrumbHelper
|
10
10
|
|
11
|
-
helper_method :results, :result, :
|
11
|
+
helper_method :results, :result, :first_class_taxonomies, :count_calculator
|
12
12
|
|
13
13
|
before_action :set_controller_breadcrumb
|
14
14
|
|
@@ -16,6 +16,10 @@ module Decidim
|
|
16
16
|
raise ActionController::RoutingError, "Not Found" unless result
|
17
17
|
end
|
18
18
|
|
19
|
+
def home
|
20
|
+
@all_geocoded_results = results.geocoded
|
21
|
+
end
|
22
|
+
|
19
23
|
private
|
20
24
|
|
21
25
|
def results
|
@@ -38,17 +42,16 @@ module Decidim
|
|
38
42
|
def default_filter_params
|
39
43
|
{
|
40
44
|
search_text_cont: "",
|
41
|
-
|
42
|
-
with_category: ""
|
45
|
+
taxonomies_part_of_contains: ""
|
43
46
|
}
|
44
47
|
end
|
45
48
|
|
46
|
-
def
|
47
|
-
@
|
49
|
+
def first_class_taxonomies
|
50
|
+
@first_class_taxonomies ||= current_organization.taxonomies.where(parent_id: current_component.available_root_taxonomies, id: current_component.available_taxonomy_ids)
|
48
51
|
end
|
49
52
|
|
50
|
-
def count_calculator(
|
51
|
-
Decidim::Accountability::ResultsCalculator.new(current_component,
|
53
|
+
def count_calculator(taxonomy_id)
|
54
|
+
Decidim::Accountability::ResultsCalculator.new(current_component, taxonomy_id).count
|
52
55
|
end
|
53
56
|
|
54
57
|
def controller_breadcrumb_items
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Accountability
|
5
|
+
module Admin
|
6
|
+
# A form object to be used when admin users want to import results from
|
7
|
+
# another component into Accountability component.
|
8
|
+
class ImportComponentForm < Decidim::Form
|
9
|
+
include Decidim::TranslatableAttributes
|
10
|
+
include Decidim::HasTaxonomyFormAttributes
|
11
|
+
|
12
|
+
attribute :origin_component_id, Integer
|
13
|
+
attribute :proposal_state_id, Integer
|
14
|
+
|
15
|
+
validates :origin_component_id, presence: true
|
16
|
+
validates :filtered_items_count, numericality: { greater_than: 0 }, if: ->(form) { form.origin_component_id }
|
17
|
+
|
18
|
+
def origin_component
|
19
|
+
@origin_component ||= origin_components.find_by(id: origin_component_id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def origin_components
|
23
|
+
@origin_components ||= current_participatory_space.components.where(manifest_name: %w(budgets proposals))
|
24
|
+
end
|
25
|
+
|
26
|
+
def origin_components_collection
|
27
|
+
origin_components.map do |component|
|
28
|
+
[component.name[I18n.locale.to_s], component.id]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def proposal_states_collection
|
33
|
+
Decidim::Proposals::ProposalState.where(component: origin_component).map do |state|
|
34
|
+
[translated_attribute(state.title), state.id]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
delegate :count, to: :filtered_items, prefix: true
|
39
|
+
|
40
|
+
def filtered_items
|
41
|
+
if origin_component.manifest_name == "budgets"
|
42
|
+
filtered_budget_projects
|
43
|
+
elsif origin_component.manifest_name == "proposals"
|
44
|
+
filtered_proposals
|
45
|
+
else
|
46
|
+
raise "Invalid component"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def project_already_copied?(original_project)
|
51
|
+
original_project.linked_resources(:results, "included_projects").any? do |result|
|
52
|
+
result.component == current_component
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def proposal_already_copied?(original_proposal)
|
57
|
+
original_proposal.linked_resources(:results, "included_proposals").any? do |result|
|
58
|
+
result.component == current_component
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def filtered_budget_projects
|
65
|
+
scope = Decidim::Budgets::Project.joins(:budget).selected.where(budget: { component: origin_component })
|
66
|
+
scope = filter_taxonomies(scope)
|
67
|
+
scope.reject { |project| project_already_copied?(project) }
|
68
|
+
end
|
69
|
+
|
70
|
+
def filtered_proposals
|
71
|
+
scope = Decidim::Proposals::Proposal.where(component: origin_component).not_hidden
|
72
|
+
scope = scope.where(decidim_proposals_proposal_state_id: proposal_state_id) if proposal_state_id
|
73
|
+
scope = filter_taxonomies(scope)
|
74
|
+
scope.reject { |proposal| proposal_already_copied?(proposal) }
|
75
|
+
end
|
76
|
+
|
77
|
+
def filter_taxonomies(scope)
|
78
|
+
if taxonomy_sets.any?
|
79
|
+
scope.with_any_taxonomies(*taxonomy_sets)
|
80
|
+
else
|
81
|
+
scope
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def taxonomy_sets
|
86
|
+
@taxonomy_sets ||= taxonomies.compact.map do |taxonomy_id|
|
87
|
+
taxonomy = Decidim::Taxonomy.find(taxonomy_id)
|
88
|
+
root_taxonomy_id = taxonomy.root_taxonomy.id
|
89
|
+
|
90
|
+
return nil if !root_taxonomy_id || !taxonomy_id
|
91
|
+
|
92
|
+
[root_taxonomy_id, [taxonomy_id]]
|
93
|
+
end.compact
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Accountability
|
5
|
+
module Admin
|
6
|
+
# This class holds a Form to create/update results from Decidim's admin panel.
|
7
|
+
class ResultBulkActionsForm < Decidim::Form
|
8
|
+
include Decidim::TranslationsHelper
|
9
|
+
include Decidim::HasTaxonomyFormAttributes
|
10
|
+
|
11
|
+
attribute :result_ids, Array[Integer]
|
12
|
+
attribute :start_date, Decidim::Attributes::LocalizedDate
|
13
|
+
attribute :end_date, Decidim::Attributes::LocalizedDate
|
14
|
+
attribute :decidim_accountability_status_id, Integer
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -5,14 +5,13 @@ module Decidim
|
|
5
5
|
module Admin
|
6
6
|
# This class holds a Form to create/update results from Decidim's admin panel.
|
7
7
|
class ResultForm < Decidim::Form
|
8
|
-
include TranslatableAttributes
|
9
|
-
include TranslationsHelper
|
8
|
+
include Decidim::TranslatableAttributes
|
9
|
+
include Decidim::TranslationsHelper
|
10
|
+
include Decidim::HasTaxonomyFormAttributes
|
10
11
|
|
11
12
|
translatable_attribute :title, String
|
12
13
|
translatable_attribute :description, Decidim::Attributes::RichText
|
13
14
|
|
14
|
-
attribute :decidim_scope_id, Integer
|
15
|
-
attribute :decidim_category_id, Integer
|
16
15
|
attribute :proposal_ids, Array[Integer]
|
17
16
|
attribute :project_ids, Array[Integer]
|
18
17
|
attribute :start_date, Decidim::Attributes::LocalizedDate
|
@@ -22,25 +21,26 @@ module Decidim
|
|
22
21
|
attribute :parent_id, Integer
|
23
22
|
attribute :external_id, String
|
24
23
|
attribute :weight, Float
|
24
|
+
attribute :address, String
|
25
|
+
attribute :latitude, Float
|
26
|
+
attribute :longitude, Float
|
25
27
|
|
26
28
|
validates :title, translatable_presence: true
|
27
29
|
|
28
30
|
validates :progress, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }, if: ->(form) { form.progress.present? }
|
29
31
|
|
30
|
-
validates :scope, presence: true, if: ->(form) { form.decidim_scope_id.present? }
|
31
|
-
validates :decidim_scope_id, scope_belongs_to_component: true, if: ->(form) { form.decidim_scope_id.present? }
|
32
|
-
|
33
|
-
validates :category, presence: true, if: ->(form) { form.decidim_category_id.present? }
|
34
|
-
|
35
32
|
validates :parent, presence: true, if: ->(form) { form.parent_id.present? }
|
36
33
|
validates :status, presence: true, if: ->(form) { form.decidim_accountability_status_id.present? }
|
37
34
|
|
38
|
-
|
35
|
+
validates :address, geocoding: true, if: ->(form) { form.has_address? && !form.geocoded? }
|
39
36
|
|
40
37
|
def map_model(model)
|
41
38
|
self.proposal_ids = model.linked_resources(:proposals, "included_proposals").pluck(:id)
|
42
39
|
self.project_ids = model.linked_resources(:projects, "included_projects").pluck(:id)
|
43
|
-
|
40
|
+
end
|
41
|
+
|
42
|
+
def participatory_space_manifest
|
43
|
+
@participatory_space_manifest ||= current_component.participatory_space.manifest.name
|
44
44
|
end
|
45
45
|
|
46
46
|
def proposals
|
@@ -55,22 +55,16 @@ module Decidim
|
|
55
55
|
&.select(:title, :id)&.map { |a| [a.title[I18n.locale.to_s], a.id] }
|
56
56
|
end
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
# Returns a Decidim::Scope
|
61
|
-
def scope
|
62
|
-
@scope ||= @attributes["decidim_scope_id"].value ? current_component.scopes.find_by(id: @attributes["decidim_scope_id"].value) : current_component.scope
|
58
|
+
def geocoding_enabled?
|
59
|
+
Decidim::Map.available?(:geocoding) && current_component.settings.geocoding_enabled?
|
63
60
|
end
|
64
61
|
|
65
|
-
|
66
|
-
|
67
|
-
# Returns the scope identifier related to the result
|
68
|
-
def decidim_scope_id
|
69
|
-
super || scope&.id
|
62
|
+
def has_address?
|
63
|
+
geocoding_enabled? && address.present?
|
70
64
|
end
|
71
65
|
|
72
|
-
def
|
73
|
-
|
66
|
+
def geocoded?
|
67
|
+
latitude.present? && longitude.present?
|
74
68
|
end
|
75
69
|
|
76
70
|
def parent
|
@@ -7,6 +7,7 @@ module Decidim
|
|
7
7
|
module ApplicationHelper
|
8
8
|
include PaginateHelper
|
9
9
|
include Decidim::Comments::CommentsHelper
|
10
|
+
include Decidim::MapHelper
|
10
11
|
|
11
12
|
def display_percentage(number)
|
12
13
|
return if number.blank?
|
@@ -18,38 +19,6 @@ module Decidim
|
|
18
19
|
(defined?(current_component) && translated_attribute(current_component&.name).presence) || t("decidim.components.accountability.name")
|
19
20
|
end
|
20
21
|
|
21
|
-
def filter_items_for(participatory_space:, category:)
|
22
|
-
[
|
23
|
-
{
|
24
|
-
url: url_for(filter: { with_category: category.try(:id) }),
|
25
|
-
text: t("results.filters.all", scope: "decidim.accountability"),
|
26
|
-
icon: "apps-2-line",
|
27
|
-
active: current_scope.blank?,
|
28
|
-
sr_text: Decidim::Scope.model_name.human(count: 2)
|
29
|
-
},
|
30
|
-
*(
|
31
|
-
if participatory_space.scope
|
32
|
-
[{
|
33
|
-
url: url_for(filter: { with_scope: participatory_space.scope.id, with_category: category.try(:id) }),
|
34
|
-
text: translated_attribute(participatory_space.scope.name),
|
35
|
-
icon: resource_type_icon_key(participatory_space.scope.class),
|
36
|
-
active: participatory_space.scope.id.to_s == current_scope.to_s,
|
37
|
-
sr_text: Decidim::Scope.model_name.human(count: 1)
|
38
|
-
}]
|
39
|
-
end
|
40
|
-
),
|
41
|
-
*participatory_space.subscopes.map do |scope|
|
42
|
-
{
|
43
|
-
url: url_for(filter: { with_scope: scope.id, with_category: category.try(:id) }),
|
44
|
-
text: translated_attribute(scope.name),
|
45
|
-
icon: resource_type_icon_key(scope.class),
|
46
|
-
active: scope.id.to_s == current_scope.to_s,
|
47
|
-
sr_text: Decidim::Scope.model_name.human(count: 1)
|
48
|
-
}
|
49
|
-
end
|
50
|
-
]
|
51
|
-
end
|
52
|
-
|
53
22
|
def apply_accountability_pack_tags
|
54
23
|
append_stylesheet_pack_tag("decidim_accountability", media: "all")
|
55
24
|
append_javascript_pack_tag("decidim_accountability")
|
@@ -5,28 +5,24 @@ module Decidim
|
|
5
5
|
# Helpers needed to render the navigation breadcrumbs in results.
|
6
6
|
#
|
7
7
|
module BreadcrumbHelper
|
8
|
-
def
|
9
|
-
|
8
|
+
def progress_calculator(taxonomy_id)
|
9
|
+
Decidim::Accountability::ResultsCalculator.new(current_component, taxonomy_id).progress
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
def category
|
17
|
-
return if (category_id = params.dig(:filter, :with_category)).blank?
|
12
|
+
def taxonomy
|
13
|
+
return if (taxonomy_id = params.dig(:filter, :taxonomies_part_of_contains)).blank?
|
18
14
|
|
19
|
-
@
|
15
|
+
@taxonomy ||= current_organization.taxonomies.find(taxonomy_id.is_a?(Array) ? taxonomy_id.first : taxonomy_id)
|
20
16
|
end
|
21
17
|
|
22
|
-
def
|
23
|
-
return [] if
|
18
|
+
def parent_taxonomies(taxonomy)
|
19
|
+
return [] if taxonomy&.parent.blank? || taxonomy&.parent&.root?
|
24
20
|
|
25
|
-
[*
|
21
|
+
[*parent_taxonomies(taxonomy.parent), taxonomy.parent]
|
26
22
|
end
|
27
23
|
|
28
|
-
def
|
29
|
-
|
24
|
+
def taxonomies_hierarchy
|
25
|
+
parent_taxonomies(taxonomy)
|
30
26
|
end
|
31
27
|
end
|
32
28
|
end
|
@@ -28,11 +28,13 @@ module Decidim
|
|
28
28
|
params = {
|
29
29
|
title: project.title,
|
30
30
|
description: project.description,
|
31
|
-
|
32
|
-
scope: project.scope || project.budget.scope,
|
31
|
+
taxonomies: project.taxonomies,
|
33
32
|
component:,
|
34
33
|
status:,
|
35
|
-
progress: status&.progress || 0
|
34
|
+
progress: status&.progress || 0,
|
35
|
+
address: project.address,
|
36
|
+
latitude: project.latitude,
|
37
|
+
longitude: project.longitude
|
36
38
|
}
|
37
39
|
@result = Decidim.traceability.create!(
|
38
40
|
Result,
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Accountability
|
5
|
+
module Admin
|
6
|
+
class ImportProposalsJob < ApplicationJob
|
7
|
+
queue_as :default
|
8
|
+
|
9
|
+
def perform(proposals, component, user)
|
10
|
+
proposals.map do |id|
|
11
|
+
original_proposal = Decidim::Proposals::Proposal.find_by(id:)
|
12
|
+
|
13
|
+
new_result = create_result_from_proposal!(original_proposal, statuses(component).first, component, user)
|
14
|
+
new_result.link_resources([original_proposal], "included_proposals")
|
15
|
+
|
16
|
+
copy_attachments(original_proposal, new_result)
|
17
|
+
end.compact
|
18
|
+
Decidim::Accountability::ImportProposalsMailer.import(user, component, proposals.count).deliver_now
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def create_result_from_proposal!(proposal, status, component, user)
|
24
|
+
params = {
|
25
|
+
title: proposal.title,
|
26
|
+
description: proposal.body,
|
27
|
+
taxonomies: proposal.taxonomies,
|
28
|
+
component:,
|
29
|
+
status:,
|
30
|
+
progress: status&.progress || 0,
|
31
|
+
address: proposal.address,
|
32
|
+
latitude: proposal.latitude,
|
33
|
+
longitude: proposal.longitude
|
34
|
+
}
|
35
|
+
@result = Decidim.traceability.create!(
|
36
|
+
Result,
|
37
|
+
user,
|
38
|
+
params,
|
39
|
+
visibility: "all"
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def copy_attachments(proposal, result)
|
44
|
+
proposal.attachments.each do |attachment|
|
45
|
+
new_attachment = Decidim::Attachment.new(
|
46
|
+
{
|
47
|
+
# Attached to needs to be always defined before the file is set
|
48
|
+
attached_to: result
|
49
|
+
}.merge(
|
50
|
+
attachment.attributes.slice("content_type", "description", "file_size", "title", "weight")
|
51
|
+
)
|
52
|
+
)
|
53
|
+
|
54
|
+
if attachment.file.attached?
|
55
|
+
new_attachment.file = attachment.file.blob
|
56
|
+
else
|
57
|
+
new_attachment.attached_uploader(:file).remote_url = attachment.attached_uploader(:file)
|
58
|
+
end
|
59
|
+
|
60
|
+
new_attachment.save!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def statuses(component)
|
65
|
+
Decidim::Accountability::Status.where(component:).order(:progress)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Accountability
|
5
|
+
# This mailer sends a notification email containing the result of importing
|
6
|
+
# proposals to the results.
|
7
|
+
class ImportProposalsMailer < Decidim::ApplicationMailer
|
8
|
+
include Decidim::TranslatableAttributes
|
9
|
+
helper Decidim::TranslationsHelper
|
10
|
+
|
11
|
+
# Public: Sends a notification email with the result of proposals import selected proposals to Accountability
|
12
|
+
#
|
13
|
+
# user - The user to be notified.
|
14
|
+
#
|
15
|
+
# Returns nothing.
|
16
|
+
def import(user, component, proposals)
|
17
|
+
@user = user
|
18
|
+
@organization = user.organization
|
19
|
+
@component = component
|
20
|
+
@proposals = proposals
|
21
|
+
|
22
|
+
with_user(user) do
|
23
|
+
mail(to: "#{user.name} <#{user.email}>", subject: I18n.t("decidim.accountability.import_proposals_mailer.import.subject"))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -6,6 +6,7 @@ module Decidim
|
|
6
6
|
# title, description and any other useful information to render a custom result.
|
7
7
|
class Result < Accountability::ApplicationRecord
|
8
8
|
include Decidim::Resourceable
|
9
|
+
include Decidim::Taxonomizable
|
9
10
|
include Decidim::HasAttachments
|
10
11
|
include Decidim::HasAttachmentCollections
|
11
12
|
include Decidim::HasComponent
|
@@ -20,6 +21,7 @@ module Decidim
|
|
20
21
|
include Decidim::Searchable
|
21
22
|
include Decidim::TranslatableResource
|
22
23
|
include Decidim::FilterableResource
|
24
|
+
include Decidim::SoftDeletable
|
23
25
|
|
24
26
|
component_manifest_name "accountability"
|
25
27
|
|
@@ -45,10 +47,16 @@ module Decidim
|
|
45
47
|
datetime: :start_date
|
46
48
|
)
|
47
49
|
|
50
|
+
geocoded_by :address
|
51
|
+
|
48
52
|
def self.log_presenter_class_for(_log)
|
49
53
|
Decidim::Accountability::AdminLog::ResultPresenter
|
50
54
|
end
|
51
55
|
|
56
|
+
def presenter
|
57
|
+
Decidim::Accountability::ResultPresenter.new(self)
|
58
|
+
end
|
59
|
+
|
52
60
|
def update_parent_progress
|
53
61
|
return if parent.blank?
|
54
62
|
|
@@ -83,7 +91,7 @@ module Decidim
|
|
83
91
|
end
|
84
92
|
|
85
93
|
def self.ransackable_scopes(_auth_object = nil)
|
86
|
-
[:
|
94
|
+
[:with_any_taxonomies]
|
87
95
|
end
|
88
96
|
|
89
97
|
ransacker :id_string do
|
@@ -94,6 +102,20 @@ module Decidim
|
|
94
102
|
# Create the :search_text ransacker alias for searching from both of these.
|
95
103
|
ransacker_i18n_multi :search_text, [:title, :description]
|
96
104
|
|
105
|
+
def self.ransackable_attributes(auth_object = nil)
|
106
|
+
base = %w(search_text title description)
|
107
|
+
|
108
|
+
return base unless auth_object&.admin?
|
109
|
+
|
110
|
+
base + %w(id_string created_at id progress)
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.ransackable_associations(auth_object = nil)
|
114
|
+
return [] unless auth_object&.admin?
|
115
|
+
|
116
|
+
%w(taxonomies status)
|
117
|
+
end
|
118
|
+
|
97
119
|
private
|
98
120
|
|
99
121
|
# Private: When a row uses weight 1 and there is more than one, weight should not be considered
|