decidim-proposals 0.30.5 → 0.31.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/proposals/collaborative_draft_metadata_cell.rb +1 -1
  3. data/app/cells/decidim/proposals/proposal_g/show.erb +1 -1
  4. data/app/cells/decidim/proposals/proposal_g_cell.rb +4 -4
  5. data/app/cells/decidim/proposals/proposal_l_cell.rb +4 -4
  6. data/app/cells/decidim/proposals/proposal_metadata_cell.rb +2 -2
  7. data/app/cells/decidim/proposals/proposal_vote/show.erb +1 -1
  8. data/app/commands/decidim/proposals/admin/{assign_proposals_to_valuator.rb → assign_proposals_to_evaluator.rb} +16 -16
  9. data/app/commands/decidim/proposals/admin/create_proposal.rb +1 -2
  10. data/app/commands/decidim/proposals/admin/create_proposal_note.rb +4 -4
  11. data/app/commands/decidim/proposals/admin/merge_proposals.rb +60 -13
  12. data/app/commands/decidim/proposals/admin/notify_proposal_answer.rb +2 -2
  13. data/app/commands/decidim/proposals/admin/proposal_notes_methods.rb +5 -5
  14. data/app/commands/decidim/proposals/admin/reply_proposal_note.rb +1 -1
  15. data/app/commands/decidim/proposals/admin/{unassign_proposals_from_valuator.rb → unassign_proposals_from_evaluator.rb} +7 -7
  16. data/app/commands/decidim/proposals/admin/update_proposal.rb +1 -2
  17. data/app/commands/decidim/proposals/create_collaborative_draft.rb +3 -8
  18. data/app/commands/decidim/proposals/create_proposal.rb +5 -22
  19. data/app/commands/decidim/proposals/publish_collaborative_draft.rb +2 -2
  20. data/app/commands/decidim/proposals/publish_proposal.rb +1 -5
  21. data/app/commands/decidim/proposals/update_collaborative_draft.rb +2 -4
  22. data/app/commands/decidim/proposals/update_proposal.rb +5 -18
  23. data/app/controllers/concerns/decidim/proposals/admin/filterable.rb +6 -6
  24. data/app/controllers/concerns/decidim/proposals/orderable.rb +3 -3
  25. data/app/controllers/decidim/proposals/admin/evaluation_assignments_controller.rb +55 -0
  26. data/app/controllers/decidim/proposals/admin/participatory_texts_controller.rb +6 -6
  27. data/app/controllers/decidim/proposals/admin/proposal_answers_controller.rb +1 -1
  28. data/app/controllers/decidim/proposals/admin/proposal_states_controller.rb +2 -2
  29. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +2 -2
  30. data/app/controllers/decidim/proposals/admin/proposals_imports_controller.rb +1 -1
  31. data/app/controllers/decidim/proposals/admin/proposals_merges_controller.rb +12 -3
  32. data/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +2 -3
  33. data/app/controllers/decidim/proposals/proposals_controller.rb +5 -6
  34. data/app/events/decidim/proposals/admin/{proposal_assigned_to_valuator_event.rb → proposal_assigned_to_evaluator_event.rb} +1 -1
  35. data/app/events/decidim/proposals/{endorsing_enabled_event.rb → liking_enabled_event.rb} +1 -1
  36. data/app/events/decidim/proposals/merged_proposal_event.rb +9 -0
  37. data/app/events/decidim/proposals/proposal_liked_event.rb +33 -0
  38. data/app/forms/decidim/proposals/admin/evaluation_assignment_form.rb +38 -0
  39. data/app/forms/decidim/proposals/admin/proposal_base_form.rb +1 -27
  40. data/app/forms/decidim/proposals/admin/proposals_fork_form.rb +1 -1
  41. data/app/forms/decidim/proposals/admin/proposals_merge_form.rb +58 -2
  42. data/app/forms/decidim/proposals/collaborative_draft_form.rb +1 -5
  43. data/app/forms/decidim/proposals/proposal_form.rb +0 -29
  44. data/app/helpers/decidim/proposals/admin/proposal_bulk_actions_helper.rb +8 -8
  45. data/app/helpers/decidim/proposals/admin/proposal_rankings_helper.rb +6 -6
  46. data/app/helpers/decidim/proposals/admin/proposals_helper.rb +2 -17
  47. data/app/helpers/decidim/proposals/application_helper.rb +3 -6
  48. data/app/jobs/decidim/proposals/settings_change_job.rb +6 -6
  49. data/app/models/decidim/proposals/collaborative_draft.rb +1 -1
  50. data/app/models/decidim/proposals/{valuation_assignment.rb → evaluation_assignment.rb} +7 -7
  51. data/app/models/decidim/proposals/proposal.rb +24 -34
  52. data/app/packs/entrypoints/decidim_proposals_admin.js +1 -0
  53. data/app/packs/src/decidim/proposals/add_proposal.js +1 -1
  54. data/app/packs/src/decidim/proposals/admin/proposals.js +22 -11
  55. data/app/packs/src/decidim/proposals/admin/proposals_form.js +1 -1
  56. data/app/packs/src/decidim/proposals/admin/proposals_merge.js +92 -0
  57. data/app/packs/src/decidim/proposals/choose_proposals.js +1 -1
  58. data/app/packs/src/decidim/proposals/exit_handler.js +1 -1
  59. data/app/packs/src/decidim/proposals/utils.js +1 -1
  60. data/app/packs/stylesheets/decidim/proposals/proposals.scss +29 -1
  61. data/app/permissions/decidim/proposals/admin/permissions.rb +20 -20
  62. data/app/presenters/decidim/proposals/admin_log/{valuation_assignment_presenter.rb → evaluation_assignment_presenter.rb} +7 -7
  63. data/app/presenters/decidim/proposals/admin_log/proposal_presenter.rb +15 -0
  64. data/app/presenters/decidim/proposals/admin_log/value_types/{valuator_role_user_presenter.rb → evaluator_role_user_presenter.rb} +2 -2
  65. data/app/presenters/decidim/proposals/admin_log/value_types/proposal_title_body_presenter.rb +1 -1
  66. data/app/presenters/decidim/proposals/collaborative_draft_presenter.rb +1 -6
  67. data/app/presenters/decidim/proposals/log/{valuation_assignment_presenter.rb → evaluation_assignment_presenter.rb} +1 -1
  68. data/app/presenters/decidim/proposals/proposal_presenter.rb +10 -13
  69. data/app/services/decidim/proposals/diff_renderer.rb +0 -1
  70. data/app/services/decidim/proposals/proposal_builder.rb +5 -10
  71. data/app/views/decidim/proposals/admin/participatory_texts/_article-preview.html.erb +1 -1
  72. data/app/views/decidim/proposals/admin/participatory_texts/index.html.erb +1 -2
  73. data/app/views/decidim/proposals/admin/proposal_notes/_form.html.erb +1 -1
  74. data/app/views/decidim/proposals/admin/proposal_notes/_proposal_notes.html.erb +1 -1
  75. data/app/views/decidim/proposals/admin/proposal_states/index.html.erb +42 -12
  76. data/app/views/decidim/proposals/admin/proposals/_actions.html.erb +87 -21
  77. data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +9 -13
  78. data/app/views/decidim/proposals/admin/proposals/_form.html.erb +2 -24
  79. data/app/views/decidim/proposals/admin/proposals/_likes.html.erb +25 -0
  80. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +13 -12
  81. data/app/views/decidim/proposals/admin/proposals/_proposals-thead.html.erb +1 -1
  82. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_assign_to_evaluator.html.erb +19 -0
  83. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_dropdown.html.erb +45 -49
  84. data/app/views/decidim/proposals/admin/proposals/bulk_actions/{_valuators_picker.html.erb → _evaluators_picker.html.erb} +4 -4
  85. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_merge.html.erb +7 -14
  86. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_unassign_from_evaluator.html.erb +19 -0
  87. data/app/views/decidim/proposals/admin/proposals/index.html.erb +9 -5
  88. data/app/views/decidim/proposals/admin/proposals/manage_trash.html.erb +2 -1
  89. data/app/views/decidim/proposals/admin/proposals/show.html.erb +17 -17
  90. data/app/views/decidim/proposals/admin/proposals_merges/_form.html.erb +49 -0
  91. data/app/views/decidim/proposals/admin/proposals_merges/new.html.erb +14 -0
  92. data/app/views/decidim/proposals/collaborative_drafts/_collaborative_actions.html.erb +2 -2
  93. data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +1 -21
  94. data/app/views/decidim/proposals/collaborative_drafts/show.html.erb +1 -1
  95. data/app/views/decidim/proposals/proposals/_actions.html.erb +2 -2
  96. data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +1 -21
  97. data/app/views/decidim/proposals/proposals/_proposal_actions.html.erb +4 -4
  98. data/app/views/decidim/proposals/proposals/_proposal_aside.html.erb +2 -2
  99. data/app/views/decidim/proposals/proposals/_proposal_voting_rules.html.erb +1 -1
  100. data/app/views/decidim/proposals/proposals/_votes_count.html.erb +1 -1
  101. data/app/views/decidim/proposals/proposals/participatory_texts/_view_index.html.erb +1 -1
  102. data/app/views/decidim/proposals/proposals/preview.html.erb +1 -1
  103. data/app/views/decidim/proposals/proposals/show.html.erb +2 -2
  104. data/config/assets.rb +2 -2
  105. data/config/locales/ar.yml +0 -65
  106. data/config/locales/bg.yml +0 -71
  107. data/config/locales/bs-BA.yml +0 -25
  108. data/config/locales/ca-IT.yml +66 -74
  109. data/config/locales/ca.yml +66 -74
  110. data/config/locales/cs.yml +52 -81
  111. data/config/locales/de.yml +66 -75
  112. data/config/locales/el.yml +0 -66
  113. data/config/locales/en.yml +69 -77
  114. data/config/locales/es-MX.yml +68 -76
  115. data/config/locales/es-PY.yml +68 -76
  116. data/config/locales/es.yml +68 -76
  117. data/config/locales/eu.yml +73 -81
  118. data/config/locales/fi-plain.yml +67 -75
  119. data/config/locales/fi.yml +68 -76
  120. data/config/locales/fr-CA.yml +49 -74
  121. data/config/locales/fr.yml +49 -74
  122. data/config/locales/ga-IE.yml +0 -22
  123. data/config/locales/gl.yml +0 -47
  124. data/config/locales/hu.yml +0 -64
  125. data/config/locales/id-ID.yml +0 -34
  126. data/config/locales/is-IS.yml +0 -14
  127. data/config/locales/it.yml +0 -69
  128. data/config/locales/ja.yml +68 -76
  129. data/config/locales/lb.yml +0 -3
  130. data/config/locales/lt.yml +0 -68
  131. data/config/locales/lv.yml +0 -62
  132. data/config/locales/nl.yml +0 -63
  133. data/config/locales/no.yml +0 -42
  134. data/config/locales/pl.yml +0 -73
  135. data/config/locales/pt-BR.yml +1 -469
  136. data/config/locales/pt.yml +0 -60
  137. data/config/locales/ro-RO.yml +45 -72
  138. data/config/locales/ru.yml +0 -15
  139. data/config/locales/sk.yml +0 -60
  140. data/config/locales/sr-CS.yml +0 -25
  141. data/config/locales/sv.yml +82 -113
  142. data/config/locales/tr-TR.yml +0 -58
  143. data/config/locales/uk.yml +0 -15
  144. data/config/locales/zh-CN.yml +0 -57
  145. data/config/locales/zh-TW.yml +0 -65
  146. data/db/migrate/20240110203500_add_withdrawn_at_field_to_proposals.rb +1 -1
  147. data/db/migrate/20240110203504_create_default_proposal_states.rb +1 -1
  148. data/db/migrate/20250121110014_rename_proposal_valuation_assignments_to_evaluation_assignments.rb +15 -0
  149. data/db/migrate/20250121110904_rename_valuation_assignments_count_to_evaluation_assignments_count.rb +16 -0
  150. data/db/migrate/20250211141313_rename_valuator_columns.rb +8 -0
  151. data/db/migrate/20250515132351_rename_proposals_endorsements_count_to_likes.rb +7 -0
  152. data/decidim-proposals.gemspec +1 -1
  153. data/lib/decidim/api/mutations/answer_proposal_attributes.rb +17 -0
  154. data/lib/decidim/api/mutations/proposal_answer_type.rb +57 -0
  155. data/lib/decidim/api/mutations/proposal_mutation_type.rb +14 -0
  156. data/lib/decidim/api/mutations/proposals_mutation_type.rb +23 -0
  157. data/lib/decidim/api/proposal_input_sort.rb +1 -1
  158. data/lib/decidim/api/proposal_state_type.rb +16 -0
  159. data/lib/decidim/api/proposal_type.rb +59 -9
  160. data/lib/decidim/proposals/admin_engine.rb +3 -3
  161. data/lib/decidim/proposals/admin_filter.rb +3 -3
  162. data/lib/decidim/proposals/api.rb +5 -0
  163. data/lib/decidim/proposals/component.rb +44 -36
  164. data/lib/decidim/proposals/engine.rb +18 -83
  165. data/lib/decidim/proposals/evaluable.rb +22 -0
  166. data/lib/decidim/proposals/import/proposal_creator.rb +1 -1
  167. data/lib/decidim/proposals/proposal_serializer.rb +9 -11
  168. data/lib/decidim/proposals/seeds.rb +17 -28
  169. data/lib/decidim/proposals/test/factories.rb +21 -53
  170. data/lib/decidim/proposals/version.rb +1 -1
  171. data/lib/decidim/proposals.rb +3 -3
  172. data/lib/tasks/proposals/upgrade/decidim_proposals_upgrade_tasks.rake +11 -11
  173. metadata +57 -47
  174. data/app/commands/decidim/proposals/hashtags_methods.rb +0 -36
  175. data/app/controllers/decidim/proposals/admin/valuation_assignments_controller.rb +0 -55
  176. data/app/events/decidim/proposals/proposal_endorsed_event.rb +0 -33
  177. data/app/forms/decidim/proposals/admin/proposals_file_import_form.rb +0 -31
  178. data/app/forms/decidim/proposals/admin/valuation_assignment_form.rb +0 -38
  179. data/app/queries/decidim/proposals/metrics/accepted_proposals_metric_manage.rb +0 -32
  180. data/app/queries/decidim/proposals/metrics/endorsements_metric_manage.rb +0 -58
  181. data/app/queries/decidim/proposals/metrics/proposal_followers_metric_measure.rb +0 -58
  182. data/app/queries/decidim/proposals/metrics/proposal_participants_metric_measure.rb +0 -74
  183. data/app/queries/decidim/proposals/metrics/proposals_metric_manage.rb +0 -48
  184. data/app/queries/decidim/proposals/metrics/votes_metric_manage.rb +0 -52
  185. data/app/views/decidim/proposals/admin/imports/_proposals_fields.html.erb +0 -11
  186. data/app/views/decidim/proposals/admin/proposals/_endorsers.html.erb +0 -25
  187. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_assign_to_valuator.html.erb +0 -19
  188. data/app/views/decidim/proposals/admin/proposals/bulk_actions/_unassign_from_valuator.html.erb +0 -19
  189. data/lib/decidim/proposals/valuatable.rb +0 -22
@@ -10,7 +10,7 @@ class CreateDefaultProposalStates < ActiveRecord::Migration[6.1]
10
10
 
11
11
  self.table_name = :decidim_proposals_proposals
12
12
  STATES = { not_answered: 0, evaluating: 10, accepted: 20, rejected: -10 }.freeze
13
- enum old_state: STATES, _default: "not_answered"
13
+ enum :old_state, STATES, default: "not_answered"
14
14
  end
15
15
 
16
16
  def up
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RenameProposalValuationAssignmentsToEvaluationAssignments < ActiveRecord::Migration[7.0]
4
+ def change
5
+ rename_table :decidim_proposals_valuation_assignments, :decidim_proposals_evaluation_assignments
6
+
7
+ rename_index :decidim_proposals_evaluation_assignments,
8
+ "decidim_proposals_valuation_assignment_proposal",
9
+ "decidim_proposals_evaluation_assignment_proposal"
10
+
11
+ rename_index :decidim_proposals_evaluation_assignments,
12
+ "decidim_proposals_valuation_assignment_valuator_role",
13
+ "decidim_proposals_evaluation_assignment_valuator_role"
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RenameValuationAssignmentsCountToEvaluationAssignmentsCount < ActiveRecord::Migration[7.0]
4
+ def change
5
+ rename_column :decidim_proposals_proposals, :valuation_assignments_count, :evaluation_assignments_count
6
+
7
+ reversible do |dir|
8
+ dir.up do
9
+ Decidim::Proposals::Proposal.reset_column_information
10
+ Decidim::Proposals::Proposal.unscoped.find_each do |record|
11
+ Decidim::Proposals::Proposal.reset_counters(record.id, :evaluation_assignments)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RenameValuatorColumns < ActiveRecord::Migration[7.0]
4
+ def change
5
+ rename_column :decidim_proposals_evaluation_assignments, :valuator_role_type, :evaluator_role_type
6
+ rename_column :decidim_proposals_evaluation_assignments, :valuator_role_id, :evaluator_role_id
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RenameProposalsEndorsementsCountToLikes < ActiveRecord::Migration[7.0]
4
+ def change
5
+ rename_column :decidim_proposals_proposals, :endorsements_count, :likes_count
6
+ end
7
+ end
@@ -34,7 +34,7 @@ Gem::Specification.new do |s|
34
34
 
35
35
  s.add_dependency "decidim-comments", Decidim::Proposals.version
36
36
  s.add_dependency "decidim-core", Decidim::Proposals.version
37
- s.add_dependency "doc2text", "~> 0.4.7"
37
+ s.add_dependency "doc2text", "~> 0.4.0", ">= 0.4.8"
38
38
  s.add_dependency "redcarpet", "~> 3.5", ">= 3.5.1"
39
39
 
40
40
  s.add_development_dependency "decidim-admin", Decidim::Proposals.version
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ class AnswerProposalAttributes < Decidim::Api::Types::BaseInputObject
6
+ graphql_name "ProposalAttributes"
7
+ description "Attributes of a proposal"
8
+
9
+ argument :answer_content, GraphQL::Types::JSON, description: "The answer feedback for the status for this proposal", required: false
10
+ argument :cost, GraphQL::Types::Float, description: "Estimated cost of the proposal", required: false
11
+ argument :cost_report, GraphQL::Types::JSON, description: "Report on expenses", required: false
12
+ argument :execution_period, GraphQL::Types::JSON, description: "Report on the execution period", required: false
13
+ argument :state, GraphQL::Types::String,
14
+ description: "The answer status in which the proposal is in. Can be one of 'accepted', 'rejected' or 'evaluating'", required: false
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ class ProposalAnswerType < Decidim::Api::Types::BaseMutation
6
+ graphql_name "Answer"
7
+
8
+ description "Answers a proposal"
9
+ type Decidim::Proposals::ProposalType
10
+
11
+ argument :attributes, AnswerProposalAttributes, description: "input attributes of a proposal", required: true
12
+
13
+ def resolve(attributes:)
14
+ answer_content = attributes.to_h.fetch(:answer_content, object.answer)
15
+ internal_state = attributes.to_h.fetch(:state, object.internal_state)
16
+ params = attributes.to_h.reverse_merge(
17
+ internal_state:,
18
+ answer: answer_content,
19
+ cost: object.cost,
20
+ cost_report: object.cost_report,
21
+ execution_period: object.execution_period
22
+ )
23
+
24
+ form = Decidim::Proposals::Admin::ProposalAnswerForm.from_params(
25
+ params
26
+ ).with_context(
27
+ current_component: object.component,
28
+ current_user:,
29
+ current_organization: current_user.organization
30
+ )
31
+
32
+ Admin::AnswerProposal.call(form, object) do
33
+ on(:ok) do
34
+ return object
35
+ end
36
+ on(:invalid) do
37
+ return GraphQL::ExecutionError.new(
38
+ form.errors.full_messages.join(", ")
39
+ )
40
+ end
41
+
42
+ GraphQL::ExecutionError.new(
43
+ I18n.t("decidim.proposals.admin.proposals.answer.invalid")
44
+ )
45
+ end
46
+ end
47
+
48
+ def authorized?(attributes:)
49
+ super && allowed_to?(:create, :proposal_answer, object, context, scope: :admin)
50
+ end
51
+
52
+ def current_user
53
+ context[:current_user]
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ class ProposalMutationType < Decidim::Api::Types::BaseObject
6
+ include Decidim::ApiResponseHelper
7
+
8
+ graphql_name "ProposalMutation"
9
+ description "a proposal which includes its available mutations"
10
+
11
+ field :answer, mutation: Decidim::Proposals::ProposalAnswerType, description: "Answers a proposal"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ class ProposalsMutationType < Decidim::Core::ComponentType
6
+ description "A proposals of a component."
7
+
8
+ field :proposal, type: Decidim::Proposals::ProposalMutationType, description: "Mutates a proposal", null: true do
9
+ argument :id, GraphQL::Types::ID, "The ID of the proposal", required: true
10
+ end
11
+
12
+ def proposal(id:)
13
+ collection.find(id)
14
+ end
15
+
16
+ private
17
+
18
+ def collection
19
+ Proposal.where(component: object).not_hidden.published
20
+ end
21
+ end
22
+ end
23
+ end
@@ -4,7 +4,7 @@ module Decidim
4
4
  module Proposals
5
5
  class ProposalInputSort < Decidim::Core::BaseInputSort
6
6
  include Decidim::Core::HasPublishableInputSort
7
- include Decidim::Core::HasEndorsableInputSort
7
+ include Decidim::Core::HasLikeableInputSort
8
8
 
9
9
  graphql_name "ProposalSort"
10
10
  description "A type used for sorting proposals"
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ class ProposalStateType < Decidim::Api::Types::BaseObject
6
+ description "A proposal state"
7
+
8
+ field :announcement_title, Decidim::Core::TranslatedFieldType, "The announcement for this proposal state", null: true
9
+ field :bg_color, GraphQL::Types::String, description: "The background color of proposal state label", null: true
10
+ field :id, GraphQL::Types::ID, "The id of the proposal state", null: false
11
+ field :proposals_count, GraphQL::Types::Int, "The number of proposals having this state", null: true
12
+ field :text_color, GraphQL::Types::String, description: "The text color of this proposal state label", null: true
13
+ field :title, Decidim::Core::TranslatedFieldType, "The title for this proposal state", null: true
14
+ end
15
+ end
16
+ end
@@ -3,6 +3,8 @@
3
3
  module Decidim
4
4
  module Proposals
5
5
  class ProposalType < Decidim::Api::Types::BaseObject
6
+ include ActiveSupport::NumberHelper
7
+
6
8
  description "A proposal"
7
9
 
8
10
  implements Decidim::Comments::CommentableInterface
@@ -13,39 +15,77 @@ module Decidim
13
15
  implements Decidim::Core::AmendableInterface
14
16
  implements Decidim::Core::AmendableEntityInterface
15
17
  implements Decidim::Core::TraceableInterface
16
- implements Decidim::Core::EndorsableInterface
18
+ implements Decidim::Core::LikeableInterface
17
19
  implements Decidim::Core::TimestampsInterface
20
+ implements Decidim::Core::ReferableInterface
21
+ implements Decidim::Core::LocalizableInterface
22
+ implements Decidim::Core::FollowableInterface
18
23
 
19
- field :address, GraphQL::Types::String, "The physical address (location) of this proposal", null: true
20
24
  field :answer, Decidim::Core::TranslatedFieldType, "The answer feedback for the status for this proposal", null: true
21
25
  field :answered_at, Decidim::Core::DateTimeType, description: "The date and time this proposal was answered", null: true
22
26
  field :body, Decidim::Core::TranslatedFieldType, "The description for this body", null: true
23
- field :coordinates, Decidim::Core::CoordinatesType, "Physical coordinates for this proposal", null: true
27
+ field :cost, GraphQL::Types::String, "The proposal cost", null: true
28
+ field :cost_report, Decidim::Core::TranslatedFieldType, "The cost report for this proposal", null: true
24
29
  field :created_in_meeting, GraphQL::Types::Boolean, "Whether this proposal comes from a meeting or not", method: :official_meeting?, null: true
30
+ field :execution_period, Decidim::Core::TranslatedFieldType, "The execution period for this proposal", null: true
25
31
  field :id, GraphQL::Types::ID, "The id of the Proposal", null: false
26
32
  field :meeting, Decidim::Meetings::MeetingType, description: "If the proposal comes from a meeting, the related meeting", null: true
27
33
  field :official, GraphQL::Types::Boolean, "Whether this proposal is official or not", method: :official?, null: true
28
34
  field :participatory_text_level, GraphQL::Types::String, description: "If it is a participatory text, the level indicates the type of paragraph", null: true
29
35
  field :position, GraphQL::Types::Int, "Position of this proposal in the participatory text", null: true
36
+ field :proposal_state, Decidim::Proposals::ProposalStateType, "The proposal state for this proposal", null: true
30
37
  field :published_at, Decidim::Core::DateTimeType, description: "The date and time this proposal was published", null: true
31
- field :reference, GraphQL::Types::String, "This proposal's unique reference", null: true
32
38
  field :state, GraphQL::Types::String, "The answer status in which proposal is in", null: true
33
- field :title, Decidim::Core::TranslatedFieldType, "The title for this title", null: true
39
+ field :title, Decidim::Core::TranslatedFieldType, "The title for this proposal", null: true
34
40
  field :vote_count, GraphQL::Types::Int, description: "The total amount of votes the proposal has received", null: true
35
41
  field :withdrawn, GraphQL::Types::Boolean, "Whether this proposal has been withdrawn or not", method: :withdrawn?, null: true
36
42
  field :withdrawn_at, Decidim::Core::DateTimeType, description: "The date and time this proposal was withdrawn", null: true
37
43
 
38
- def coordinates
39
- [object.latitude, object.longitude]
44
+ field :url, GraphQL::Types::String, "The URL for this proposal", null: false
45
+
46
+ def url
47
+ Decidim::ResourceLocatorPresenter.new(object).url
48
+ end
49
+
50
+ def answered_at
51
+ return unless object.published_state?
52
+
53
+ object.answered_at
54
+ end
55
+
56
+ def answer
57
+ return unless object.published_state?
58
+
59
+ object.answer
40
60
  end
41
61
 
42
62
  def meeting
43
63
  object.authors.first if object.official_meeting?
44
64
  end
45
65
 
66
+ def cost_report
67
+ return unless object.published_state?
68
+ return unless proposal_has_costs? && current_settings.answers_with_costs?
69
+
70
+ object.cost_report
71
+ end
72
+
73
+ def execution_period
74
+ return unless object.published_state?
75
+ return unless proposal_has_costs? && current_settings.answers_with_costs?
76
+
77
+ object.execution_period
78
+ end
79
+
80
+ def cost
81
+ return unless object.published_state?
82
+ return unless proposal_has_costs? && current_settings.answers_with_costs?
83
+
84
+ number_to_currency(object.cost, unit: Decidim.currency_unit)
85
+ end
86
+
46
87
  def vote_count
47
- current_component = object.component
48
- object.proposal_votes_count unless current_component.current_settings.votes_hidden?
88
+ object.proposal_votes_count unless current_settings.votes_hidden?
49
89
  end
50
90
 
51
91
  def self.authorized?(object, context)
@@ -60,6 +100,16 @@ module Decidim
60
100
  rescue Decidim::PermissionAction::PermissionNotSetError
61
101
  false
62
102
  end
103
+
104
+ private
105
+
106
+ def current_settings
107
+ object.component.current_settings
108
+ end
109
+
110
+ def proposal_has_costs?
111
+ object.cost.present?
112
+ end
63
113
  end
64
114
  end
65
115
  end
@@ -13,7 +13,7 @@ module Decidim
13
13
 
14
14
  routes do
15
15
  resources :proposals, only: [:show, :index, :new, :create, :edit, :update] do
16
- resources :valuation_assignments, only: [:destroy]
16
+ resources :evaluation_assignments, only: [:destroy]
17
17
  member do
18
18
  patch :soft_delete
19
19
  patch :restore
@@ -24,9 +24,9 @@ module Decidim
24
24
  post :update_multiple_answers, controller: "proposal_answers"
25
25
  get :manage_trash, controller: "proposals"
26
26
  resource :proposals_import, only: [:new, :create]
27
- resource :proposals_merge, only: [:create]
27
+ resource :proposals_merge, only: [:new, :create]
28
28
  resource :proposals_split, only: [:create]
29
- resource :valuation_assignment, only: [:create, :destroy]
29
+ resource :evaluation_assignment, only: [:create, :destroy]
30
30
  end
31
31
  resources :proposal_answers, only: [:edit, :update]
32
32
  resources :proposal_notes, only: [:create] do
@@ -10,7 +10,7 @@ module Decidim
10
10
  :state_eq,
11
11
  :with_any_state,
12
12
  :taxonomies_part_of_contains,
13
- :valuator_role_ids_has
13
+ :evaluator_role_ids_has
14
14
  )
15
15
 
16
16
  configuration.add_filters_with_values(
@@ -18,11 +18,11 @@ module Decidim
18
18
  state_eq: state_eq_values,
19
19
  with_any_state: %w(state_published state_not_published),
20
20
  taxonomies_part_of_contains: taxonomy_ids_hash(available_root_taxonomies),
21
- valuator_role_ids_has: valuator_role_ids
21
+ evaluator_role_ids_has: evaluator_role_ids
22
22
  )
23
23
 
24
24
  configuration.add_dynamically_translated_filters(
25
- :valuator_role_ids_has,
25
+ :evaluator_role_ids_has,
26
26
  :proposal_state_id_eq,
27
27
  :taxonomies_part_of_contains,
28
28
  :state_eq
@@ -6,5 +6,10 @@ module Decidim
6
6
  autoload :ProposalInputSort, "decidim/api/proposal_input_sort"
7
7
  autoload :ProposalType, "decidim/api/proposal_type"
8
8
  autoload :ProposalsType, "decidim/api/proposals_type"
9
+ autoload :ProposalStateType, "decidim/api/proposal_state_type"
10
+ autoload :ProposalsMutationType, "decidim/api/mutations/proposals_mutation_type"
11
+ autoload :ProposalMutationType, "decidim/api/mutations/proposal_mutation_type"
12
+ autoload :ProposalAnswerType, "decidim/api/mutations/proposal_answer_type"
13
+ autoload :AnswerProposalAttributes, "decidim/api/mutations/answer_proposal_attributes"
9
14
  end
10
15
  end
@@ -16,29 +16,17 @@ Decidim.register_component(:proposals) do |component|
16
16
  Decidim::Proposals.create_default_states!(instance, admin_user)
17
17
  end
18
18
 
19
- component.on(:publish) do |instance|
20
- Decidim::Proposals::Proposal.where(component: instance).find_in_batches(batch_size: 100) do |batch|
21
- Decidim::UpdateSearchIndexesJob.perform_later(batch)
22
- end
23
- end
24
-
25
- component.on(:unpublish) do |instance|
26
- Decidim::Proposals::Proposal.where(component: instance).find_in_batches(batch_size: 100) do |batch|
27
- Decidim::RemoveSearchIndexesJob.perform_later(batch)
28
- end
29
- end
30
-
31
19
  component.data_portable_entities = ["Decidim::Proposals::Proposal"]
32
20
 
33
21
  component.newsletter_participant_entities = ["Decidim::Proposals::Proposal"]
34
22
 
35
- component.actions = %w(endorse vote create withdraw amend comment vote_comment)
23
+ component.actions = %w(like vote create withdraw amend comment vote_comment)
36
24
 
37
25
  component.query_type = "Decidim::Proposals::ProposalsType"
38
26
 
39
27
  component.permissions_class_name = "Decidim::Proposals::Permissions"
40
28
 
41
- POSSIBLE_SORT_ORDERS = %w(automatic random recent most_endorsed most_voted most_commented most_followed with_more_authors).freeze
29
+ POSSIBLE_SORT_ORDERS = %w(automatic random recent most_liked most_voted most_commented most_followed with_more_authors).freeze
42
30
 
43
31
  component.settings(:global) do |settings|
44
32
  settings.attribute :taxonomy_filters, type: :taxonomy_filters
@@ -46,12 +34,12 @@ Decidim.register_component(:proposals) do |component|
46
34
  settings.attribute :minimum_votes_per_user, type: :integer, default: 0, required: true
47
35
  settings.attribute :proposal_limit, type: :integer, default: 0, required: true
48
36
  settings.attribute :proposal_length, type: :integer, default: 500
49
- settings.attribute :proposal_edit_time, type: :enum, default: "limited", choices: -> { %w(infinite limited) }
37
+ settings.attribute :proposal_edit_time, type: :enum, default: "limited", choices: ->(_context) { %w(infinite limited) }
50
38
  settings.attribute :edit_time, type: :integer_with_units, default: [5, "minutes"], required: true, units: %w(minutes hours days)
51
39
  settings.attribute :threshold_per_proposal, type: :integer, default: 0, required: true
52
40
  settings.attribute :can_accumulate_votes_beyond_threshold, type: :boolean, default: false
53
41
  settings.attribute :proposal_answering_enabled, type: :boolean, default: true
54
- settings.attribute :default_sort_order, type: :select, default: "automatic", choices: -> { POSSIBLE_SORT_ORDERS }
42
+ settings.attribute :default_sort_order, type: :select, default: "automatic", choices: ->(_context) { POSSIBLE_SORT_ORDERS }
55
43
  settings.attribute :official_proposals_enabled, type: :boolean, default: true
56
44
  settings.attribute :comments_enabled, type: :boolean, default: true
57
45
  settings.attribute :comments_max_length, type: :integer, required: true
@@ -75,8 +63,8 @@ Decidim.register_component(:proposals) do |component|
75
63
  end
76
64
 
77
65
  component.settings(:step) do |settings|
78
- settings.attribute :endorsements_enabled, type: :boolean, default: true
79
- settings.attribute :endorsements_blocked, type: :boolean
66
+ settings.attribute :likes_enabled, type: :boolean, default: true
67
+ settings.attribute :likes_blocked, type: :boolean
80
68
  settings.attribute :votes_enabled, type: :boolean
81
69
  settings.attribute :votes_blocked, type: :boolean
82
70
  settings.attribute :votes_hidden, type: :boolean, default: false
@@ -85,16 +73,14 @@ Decidim.register_component(:proposals) do |component|
85
73
  settings.attribute :proposal_answering_enabled, type: :boolean, default: true
86
74
  settings.attribute :publish_answers_immediately, type: :boolean, default: true
87
75
  settings.attribute :answers_with_costs, type: :boolean, default: false
88
- settings.attribute :default_sort_order, type: :select, include_blank: true, choices: -> { POSSIBLE_SORT_ORDERS }
76
+ settings.attribute :default_sort_order, type: :select, include_blank: true, choices: ->(_context) { POSSIBLE_SORT_ORDERS }
89
77
  settings.attribute :amendment_creation_enabled, type: :boolean, default: true
90
78
  settings.attribute :amendment_reaction_enabled, type: :boolean, default: true
91
79
  settings.attribute :amendment_promotion_enabled, type: :boolean, default: true
92
80
  settings.attribute :amendments_visibility,
93
81
  type: :enum, default: "all",
94
- choices: -> { Decidim.config.amendments_visibility_options }
82
+ choices: ->(_context) { Decidim.config.amendments_visibility_options }
95
83
  settings.attribute :announcement, type: :text, translated: true, editor: true
96
- settings.attribute :automatic_hashtags, type: :text, editor: false, required: false
97
- settings.attribute :suggested_hashtags, type: :text, editor: false, required: false
98
84
  end
99
85
 
100
86
  component.register_resource(:proposal) do |resource|
@@ -102,7 +88,7 @@ Decidim.register_component(:proposals) do |component|
102
88
  resource.template = "decidim/proposals/proposals/linked_proposals"
103
89
  resource.card = "decidim/proposals/proposal"
104
90
  resource.reported_content_cell = "decidim/proposals/reported_content"
105
- resource.actions = %w(endorse vote amend comment vote_comment)
91
+ resource.actions = %w(like vote amend comment vote_comment)
106
92
  resource.searchable = true
107
93
  end
108
94
 
@@ -112,30 +98,55 @@ Decidim.register_component(:proposals) do |component|
112
98
  resource.reported_content_cell = "decidim/proposals/collaborative_drafts/reported_content"
113
99
  end
114
100
 
115
- component.register_stat :proposals_count, primary: true, priority: Decidim::StatsRegistry::HIGH_PRIORITY do |components, start_at, end_at|
101
+ component.register_stat :proposals_count,
102
+ primary: true,
103
+ admin: false,
104
+ priority: Decidim::StatsRegistry::HIGH_PRIORITY,
105
+ icon_name: "chat-new-line",
106
+ tooltip_key: "proposals_count_tooltip" do |components, start_at, end_at|
116
107
  Decidim::Proposals::FilteredProposals.for(components, start_at, end_at).published.not_withdrawn.not_hidden.count
117
108
  end
118
109
 
119
- component.register_stat :proposals_accepted, primary: true, priority: Decidim::StatsRegistry::HIGH_PRIORITY do |components, start_at, end_at|
110
+ component.register_stat :participatory_space_proposals_count,
111
+ priority: Decidim::StatsRegistry::MEDIUM_PRIORITY,
112
+ sub_title: "votes",
113
+ icon_name: "chat-new-line",
114
+ tooltip_key: "proposals_count_tooltip" do |components, start_at, end_at|
115
+ proposals = Decidim::Proposals::FilteredProposals.for(components, start_at, end_at).published.not_withdrawn.not_hidden
116
+ [
117
+ proposals.count,
118
+ Decidim::Proposals::ProposalVote.where(proposal: proposals).count
119
+ ]
120
+ end
121
+
122
+ component.register_stat :proposals_accepted, primary: true, priority: Decidim::StatsRegistry::LOW_PRIORITY do |components, start_at, end_at|
120
123
  Decidim::Proposals::FilteredProposals.for(components, start_at, end_at).accepted.not_hidden.count
121
124
  end
122
125
 
123
- component.register_stat :votes_count, priority: Decidim::StatsRegistry::HIGH_PRIORITY do |components, start_at, end_at|
126
+ component.register_stat :votes_count, priority: Decidim::StatsRegistry::LOW_PRIORITY do |components, start_at, end_at|
124
127
  proposals = Decidim::Proposals::FilteredProposals.for(components, start_at, end_at).published.not_hidden
125
128
  Decidim::Proposals::ProposalVote.where(proposal: proposals).count
126
129
  end
127
130
 
128
- component.register_stat :endorsements_count, priority: Decidim::StatsRegistry::MEDIUM_PRIORITY do |components, start_at, end_at|
131
+ component.register_stat :likes_count, priority: Decidim::StatsRegistry::LOW_PRIORITY do |components, start_at, end_at|
129
132
  proposals = Decidim::Proposals::FilteredProposals.for(components, start_at, end_at).not_hidden
130
- proposals.sum(:endorsements_count)
133
+ proposals.sum(:likes_count)
131
134
  end
132
135
 
133
- component.register_stat :comments_count, tag: :comments do |components, start_at, end_at|
136
+ component.register_stat :comments_count,
137
+ priority: Decidim::StatsRegistry::HIGH_PRIORITY,
138
+ icon_name: "chat-1-line",
139
+ tooltip_key: "comments_count",
140
+ tag: :comments do |components, start_at, end_at|
134
141
  proposals = Decidim::Proposals::FilteredProposals.for(components, start_at, end_at).published.not_hidden
135
142
  proposals.sum(:comments_count)
136
143
  end
137
144
 
138
- component.register_stat :followers_count, tag: :followers, priority: Decidim::StatsRegistry::LOW_PRIORITY do |components, start_at, end_at|
145
+ component.register_stat :followers_count,
146
+ tag: :followers,
147
+ icon_name: "user-follow-line",
148
+ tooltip_key: "followers_count_tooltip",
149
+ priority: Decidim::StatsRegistry::MEDIUM_PRIORITY do |components, start_at, end_at|
139
150
  proposals_ids = Decidim::Proposals::FilteredProposals.for(components, start_at, end_at).published.not_hidden.pluck(:id)
140
151
  Decidim::Follow.where(decidim_followable_type: "Decidim::Proposals::Proposal", decidim_followable_id: proposals_ids).count
141
152
  end
@@ -150,8 +161,8 @@ Decidim.register_component(:proposals) do |component|
150
161
  .where(component: component_instance)
151
162
  .includes(:taxonomies, :component)
152
163
 
153
- if space.user_roles(:valuator).where(user:).any?
154
- collection.with_valuation_assigned_to(user, space)
164
+ if space.user_roles(:evaluator).where(user:).any?
165
+ collection.with_evaluation_assigned_to(user, space)
155
166
  else
156
167
  collection
157
168
  end
@@ -166,7 +177,7 @@ Decidim.register_component(:proposals) do |component|
166
177
  exports.collection do |component_instance|
167
178
  Decidim::Comments::Export.comments_for_resource(
168
179
  Decidim::Proposals::Proposal, component_instance
169
- ).includes(:author, :user_group, root_commentable: { component: { participatory_space: :organization } })
180
+ ).includes(:author, root_commentable: { component: { participatory_space: :organization } })
170
181
  end
171
182
 
172
183
  exports.include_in_open_data = true
@@ -175,9 +186,6 @@ Decidim.register_component(:proposals) do |component|
175
186
  end
176
187
 
177
188
  component.imports :proposals do |imports|
178
- imports.form_view = "decidim/proposals/admin/imports/proposals_fields"
179
- imports.form_class_name = "Decidim::Proposals::Admin::ProposalsFileImportForm"
180
-
181
189
  imports.messages do |msg|
182
190
  msg.set(:resource_name) { |count: 1| I18n.t("decidim.proposals.admin.imports.resources.proposals", count:) }
183
191
  msg.set(:title) { I18n.t("decidim.proposals.admin.imports.title.proposals") }