decidim-accountability 0.29.1 → 0.30.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/accountability/project/show.erb +6 -0
  3. data/app/cells/decidim/accountability/project_cell.rb +23 -42
  4. data/app/cells/decidim/accountability/result_history_cell.rb +57 -0
  5. data/app/cells/decidim/accountability/result_metadata_cell.rb +17 -17
  6. data/app/cells/decidim/accountability/status_cell.rb +9 -13
  7. data/app/commands/decidim/accountability/admin/create_imported_result.rb +1 -1
  8. data/app/commands/decidim/accountability/admin/create_result.rb +3 -2
  9. data/app/commands/decidim/accountability/admin/import_component_to_accountability.rb +47 -0
  10. data/app/commands/decidim/accountability/admin/update_imported_result.rb +1 -1
  11. data/app/commands/decidim/accountability/admin/update_result.rb +3 -2
  12. data/app/commands/decidim/accountability/admin/update_result_dates.rb +56 -0
  13. data/app/commands/decidim/accountability/admin/update_result_status.rb +61 -0
  14. data/app/commands/decidim/accountability/admin/update_result_taxonomies.rb +18 -0
  15. data/app/controllers/concerns/decidim/accountability/admin/filterable.rb +8 -6
  16. data/app/controllers/decidim/accountability/admin/import_components_controller.rb +36 -0
  17. data/app/controllers/decidim/accountability/admin/results_bulk_actions_controller.rb +102 -0
  18. data/app/controllers/decidim/accountability/admin/results_controller.rb +21 -11
  19. data/app/controllers/decidim/accountability/results_controller.rb +10 -7
  20. data/app/forms/decidim/accountability/admin/import_component_form.rb +98 -0
  21. data/app/forms/decidim/accountability/admin/result_bulk_actions_form.rb +18 -0
  22. data/app/forms/decidim/accountability/admin/result_form.rb +18 -24
  23. data/app/forms/decidim/accountability/admin/timeline_entry_form.rb +1 -1
  24. data/app/helpers/decidim/accountability/admin/application_helper.rb +0 -1
  25. data/app/helpers/decidim/accountability/application_helper.rb +1 -32
  26. data/app/helpers/decidim/accountability/breadcrumb_helper.rb +10 -14
  27. data/app/jobs/decidim/accountability/admin/import_projects_job.rb +5 -3
  28. data/app/jobs/decidim/accountability/admin/import_proposals_job.rb +70 -0
  29. data/app/mailers/decidim/accountability/import_projects_mailer.rb +3 -0
  30. data/app/mailers/decidim/accountability/import_proposals_mailer.rb +28 -0
  31. data/app/models/decidim/accountability/result.rb +23 -1
  32. data/app/models/decidim/accountability/status.rb +4 -0
  33. data/app/packs/entrypoints/decidim_accountability_admin_form.js +1 -0
  34. data/app/packs/src/decidim/accountability/admin/imports.js +37 -14
  35. data/app/packs/src/decidim/accountability/admin/index/action_button.js +42 -0
  36. data/app/packs/src/decidim/accountability/admin/index/action_form.js +46 -0
  37. data/app/packs/src/decidim/accountability/admin/index/action_selector.js +37 -0
  38. data/app/packs/src/decidim/accountability/admin/index/counter.js +40 -0
  39. data/app/packs/src/decidim/accountability/admin/index/select_all.js +29 -0
  40. data/app/packs/src/decidim/accountability/admin/index.js +17 -7
  41. data/app/packs/src/decidim/accountability/admin/result_form.js +21 -0
  42. data/app/packs/stylesheets/accountability.scss +5 -0
  43. data/app/permissions/decidim/accountability/admin/permissions.rb +3 -2
  44. data/app/presenters/decidim/accountability/admin_log/result_presenter.rb +1 -1
  45. data/app/presenters/decidim/accountability/result_presenter.rb +30 -0
  46. data/app/queries/decidim/accountability/metrics/results_metric_manage.rb +6 -6
  47. data/app/services/decidim/accountability/results_calculator.rb +4 -6
  48. data/app/services/decidim/accountability/results_csv_importer.rb +1 -1
  49. data/app/views/decidim/accountability/admin/import_components/_filters.html.erb +26 -0
  50. data/app/views/decidim/accountability/admin/import_components/_form.html.erb +26 -0
  51. data/app/views/decidim/accountability/admin/import_components/new.html.erb +14 -0
  52. data/app/views/decidim/accountability/admin/results/_actions.html.erb +29 -0
  53. data/app/views/decidim/accountability/admin/results/_form.html.erb +15 -8
  54. data/app/views/decidim/accountability/admin/results/_result-tr.html.erb +32 -0
  55. data/app/views/decidim/accountability/admin/results/_results-thead.html.erb +26 -0
  56. data/app/views/decidim/accountability/admin/results/bulk_actions/_dates_form.html.erb +19 -0
  57. data/app/views/decidim/accountability/admin/results/bulk_actions/_dropdown.html.erb +40 -0
  58. data/app/views/decidim/accountability/admin/results/bulk_actions/_status_form.html.erb +16 -0
  59. data/app/views/decidim/accountability/admin/results/bulk_actions/_submit_buttons.html.erb +4 -0
  60. data/app/views/decidim/accountability/admin/results/bulk_actions/_taxonomies_form.html.erb +18 -0
  61. data/app/views/decidim/accountability/admin/results/edit.html.erb +2 -2
  62. data/app/views/decidim/accountability/admin/results/index.html.erb +50 -111
  63. data/app/views/decidim/accountability/admin/results/manage_trash.html.erb +26 -0
  64. data/app/views/decidim/accountability/admin/results/new.html.erb +2 -2
  65. data/app/views/decidim/accountability/import_projects_mailer/import.html.erb +1 -1
  66. data/app/views/decidim/accountability/import_proposals_mailer/import.html.erb +2 -0
  67. data/app/views/decidim/accountability/results/{_home_categories.html.erb → _home_taxonomies.html.erb} +6 -8
  68. data/app/views/decidim/accountability/results/_project.html.erb +1 -3
  69. data/app/views/decidim/accountability/results/_projects_aside.html.erb +9 -7
  70. data/app/views/decidim/accountability/results/home.html.erb +18 -6
  71. data/app/views/decidim/accountability/results/index.html.erb +8 -2
  72. data/app/views/decidim/accountability/results/show.html.erb +5 -5
  73. data/config/assets.rb +3 -2
  74. data/config/locales/ar.yml +141 -34
  75. data/config/locales/bg.yml +0 -57
  76. data/config/locales/bn-BD.yml +1 -0
  77. data/config/locales/bs-BA.yml +148 -0
  78. data/config/locales/ca.yml +128 -40
  79. data/config/locales/cs.yml +147 -56
  80. data/config/locales/da.yml +0 -11
  81. data/config/locales/de.yml +126 -39
  82. data/config/locales/el.yml +0 -56
  83. data/config/locales/en.yml +128 -40
  84. data/config/locales/es-MX.yml +129 -41
  85. data/config/locales/es-PY.yml +129 -41
  86. data/config/locales/es.yml +129 -41
  87. data/config/locales/eu.yml +168 -81
  88. data/config/locales/fi-plain.yml +137 -50
  89. data/config/locales/fi.yml +141 -54
  90. data/config/locales/fr-CA.yml +112 -57
  91. data/config/locales/fr.yml +112 -57
  92. data/config/locales/ga-IE.yml +0 -13
  93. data/config/locales/gl.yml +0 -17
  94. data/config/locales/he-IL.yml +47 -62
  95. data/config/locales/hu.yml +0 -57
  96. data/config/locales/id-ID.yml +0 -9
  97. data/config/locales/is-IS.yml +0 -17
  98. data/config/locales/it.yml +0 -18
  99. data/config/locales/ja.yml +133 -48
  100. data/config/locales/kaa.yml +0 -8
  101. data/config/locales/ko.yml +0 -53
  102. data/config/locales/lb.yml +0 -17
  103. data/config/locales/lt.yml +0 -60
  104. data/config/locales/lv.yml +0 -9
  105. data/config/locales/nl.yml +0 -17
  106. data/config/locales/no.yml +0 -17
  107. data/config/locales/pl.yml +0 -56
  108. data/config/locales/pt-BR.yml +6 -57
  109. data/config/locales/pt.yml +37 -19
  110. data/config/locales/ro-RO.yml +0 -37
  111. data/config/locales/ru.yml +0 -9
  112. data/config/locales/sk.yml +0 -9
  113. data/config/locales/sl.yml +0 -7
  114. data/config/locales/sq-AL.yml +0 -57
  115. data/config/locales/sr-CS.yml +0 -9
  116. data/config/locales/sv.yml +124 -36
  117. data/config/locales/th-TH.yml +0 -51
  118. data/config/locales/tr-TR.yml +0 -51
  119. data/config/locales/uk.yml +0 -9
  120. data/config/locales/zh-CN.yml +0 -11
  121. data/config/locales/zh-TW.yml +0 -54
  122. data/db/migrate/20200827154103_add_commentable_counter_cache_to_results.rb +1 -1
  123. data/db/migrate/20240828103202_add_deleted_at_to_decidim_accountability_results.rb +8 -0
  124. data/db/migrate/20240916112128_add_geolocation_fields_to_results.rb +9 -0
  125. data/decidim-accountability.gemspec +2 -2
  126. data/lib/decidim/accountability/admin_engine.rb +16 -2
  127. data/lib/decidim/accountability/component.rb +3 -3
  128. data/lib/decidim/accountability/result_serializer.rb +9 -13
  129. data/lib/decidim/accountability/seeds.rb +28 -21
  130. data/lib/decidim/accountability/test/factories.rb +6 -4
  131. data/lib/decidim/accountability/version.rb +1 -1
  132. data/lib/decidim/api/accountability_type.rb +5 -8
  133. data/lib/decidim/api/result_type.rb +10 -13
  134. data/lib/decidim/api/status_type.rb +3 -4
  135. data/lib/decidim/api/timeline_entry_type.rb +5 -6
  136. metadata +61 -31
  137. data/app/commands/decidim/accountability/admin/import_projects_to_accountability.rb +0 -37
  138. data/app/controllers/decidim/accountability/admin/projects_import_controller.rb +0 -31
  139. data/app/forms/decidim/accountability/admin/result_import_projects_form.rb +0 -51
  140. data/app/views/decidim/accountability/admin/projects_import/new.html.erb +0 -45
  141. data/app/views/decidim/accountability/results/_nav_breadcrumb.html.erb +0 -37
  142. data/app/views/decidim/accountability/results/_scope_filters.html.erb +0 -31
  143. /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
- def destroy
69
- enforce_permission_to(:destroy, :result, result:)
70
+ private
70
71
 
71
- Decidim::Commands::DestroyResource.call(result, current_user) do
72
- on(:ok) do
73
- flash[:notice] = I18n.t("results.destroy.success", scope: "decidim.accountability.admin")
72
+ def trashable_deleted_resource_type
73
+ :result
74
+ end
74
75
 
75
- redirect_to results_path(parent_id: result.parent_id)
76
- end
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
- private
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, :first_class_categories, :count_calculator
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
- with_scope: "",
42
- with_category: ""
45
+ taxonomies_part_of_contains: ""
43
46
  }
44
47
  end
45
48
 
46
- def first_class_categories
47
- @first_class_categories ||= current_participatory_space.categories.first_class
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(scope_id, category_id)
51
- Decidim::Accountability::ResultsCalculator.new(current_component, scope_id, category_id).count
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
- translatable_attribute :description, String
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
- delegate :categories, to: :current_component
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
- self.decidim_category_id = model.category.try(:id)
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
- # Finds the Scope from the given decidim_scope_id, uses participatory space scope if missing.
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
- # Scope identifier
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 category
73
- @category ||= categories.find_by(id: decidim_category_id)
66
+ def geocoded?
67
+ latitude.present? && longitude.present?
74
68
  end
75
69
 
76
70
  def parent
@@ -11,7 +11,7 @@ module Decidim
11
11
  attribute :decidim_accountability_result_id, Integer
12
12
  attribute :entry_date, Decidim::Attributes::LocalizedDate
13
13
  translatable_attribute :title, String
14
- translatable_attribute :description, String
14
+ translatable_attribute :description, Decidim::Attributes::RichText
15
15
 
16
16
  validates :entry_date, presence: true
17
17
  validates :title, translatable_presence: true
@@ -6,7 +6,6 @@ module Decidim
6
6
  # Custom helpers, scoped to the accountability admin engine.
7
7
  #
8
8
  module ApplicationHelper
9
- include Decidim::Admin::ResourceScopeHelper
10
9
  include Decidim::PaginateHelper
11
10
  end
12
11
  end
@@ -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 current_scope
9
- params[:filter][:with_scope] if params[:filter]
8
+ def progress_calculator(taxonomy_id)
9
+ Decidim::Accountability::ResultsCalculator.new(current_component, taxonomy_id).progress
10
10
  end
11
11
 
12
- def progress_calculator(scope_id, category_id)
13
- Decidim::Accountability::ResultsCalculator.new(current_component, scope_id, category_id).progress
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
- @category ||= current_participatory_space.categories.find(category_id.is_a?(Array) ? category_id.first : category_id)
15
+ @taxonomy ||= current_organization.taxonomies.find(taxonomy_id.is_a?(Array) ? taxonomy_id.first : taxonomy_id)
20
16
  end
21
17
 
22
- def parent_categories(category)
23
- return [] if category&.parent.blank?
18
+ def parent_taxonomies(taxonomy)
19
+ return [] if taxonomy&.parent.blank? || taxonomy&.parent&.root?
24
20
 
25
- [*parent_categories(category.parent), category.parent]
21
+ [*parent_taxonomies(taxonomy.parent), taxonomy.parent]
26
22
  end
27
23
 
28
- def categories_hierarchy
29
- parent_categories(category)
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
- category: project.category,
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
@@ -5,6 +5,9 @@ module Decidim
5
5
  # This mailer sends a notification email containing the result of importing
6
6
  # Cprojects to the results.
7
7
  class ImportProjectsMailer < Decidim::ApplicationMailer
8
+ include Decidim::TranslatableAttributes
9
+ helper Decidim::TranslationsHelper
10
+
8
11
  # Public: Sends a notification email with the result of projects import selected projects to Accountability
9
12
  #
10
13
  # user - The user to be notified.
@@ -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