decidim-proposals 0.26.10 → 0.27.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/proposals/collaborative_draft_m_cell.rb +1 -1
  3. data/app/cells/decidim/proposals/highlighted_proposals_for_component_cell.rb +9 -1
  4. data/app/cells/decidim/proposals/proposal_m_cell.rb +6 -8
  5. data/app/commands/decidim/proposals/accept_access_to_collaborative_draft.rb +1 -1
  6. data/app/commands/decidim/proposals/admin/answer_proposal.rb +1 -1
  7. data/app/commands/decidim/proposals/admin/assign_proposals_to_valuator.rb +1 -1
  8. data/app/commands/decidim/proposals/admin/create_proposal.rb +10 -7
  9. data/app/commands/decidim/proposals/admin/create_proposal_note.rb +2 -2
  10. data/app/commands/decidim/proposals/admin/discard_participatory_text.rb +1 -1
  11. data/app/commands/decidim/proposals/admin/import_participatory_text.rb +1 -1
  12. data/app/commands/decidim/proposals/admin/import_proposals.rb +2 -5
  13. data/app/commands/decidim/proposals/admin/merge_proposals.rb +1 -1
  14. data/app/commands/decidim/proposals/admin/notify_proposal_answer.rb +1 -3
  15. data/app/commands/decidim/proposals/admin/publish_answers.rb +1 -1
  16. data/app/commands/decidim/proposals/admin/split_proposals.rb +1 -1
  17. data/app/commands/decidim/proposals/admin/unassign_proposals_from_valuator.rb +1 -1
  18. data/app/commands/decidim/proposals/admin/update_participatory_text.rb +1 -1
  19. data/app/commands/decidim/proposals/admin/update_proposal.rb +8 -2
  20. data/app/commands/decidim/proposals/admin/update_proposal_category.rb +5 -3
  21. data/app/commands/decidim/proposals/admin/update_proposal_scope.rb +3 -3
  22. data/app/commands/decidim/proposals/create_collaborative_draft.rb +5 -5
  23. data/app/commands/decidim/proposals/create_proposal.rb +1 -1
  24. data/app/commands/decidim/proposals/destroy_proposal.rb +1 -1
  25. data/app/commands/decidim/proposals/publish_collaborative_draft.rb +1 -1
  26. data/app/commands/decidim/proposals/publish_proposal.rb +1 -1
  27. data/app/commands/decidim/proposals/reject_access_to_collaborative_draft.rb +1 -1
  28. data/app/commands/decidim/proposals/request_access_to_collaborative_draft.rb +1 -1
  29. data/app/commands/decidim/proposals/unvote_proposal.rb +1 -1
  30. data/app/commands/decidim/proposals/update_collaborative_draft.rb +1 -1
  31. data/app/commands/decidim/proposals/update_proposal.rb +8 -2
  32. data/app/commands/decidim/proposals/vote_proposal.rb +1 -1
  33. data/app/commands/decidim/proposals/withdraw_collaborative_draft.rb +1 -1
  34. data/app/commands/decidim/proposals/withdraw_proposal.rb +1 -1
  35. data/app/controllers/concerns/decidim/proposals/orderable.rb +7 -5
  36. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +7 -7
  37. data/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +10 -10
  38. data/app/controllers/decidim/proposals/proposal_votes_controller.rb +1 -1
  39. data/app/controllers/decidim/proposals/proposals_controller.rb +25 -18
  40. data/app/events/decidim/proposals/publish_proposal_event.rb +0 -8
  41. data/app/forms/decidim/proposals/admin/import_participatory_text_form.rb +4 -4
  42. data/app/forms/decidim/proposals/admin/proposal_base_form.rb +4 -4
  43. data/app/forms/decidim/proposals/admin/proposal_form.rb +2 -0
  44. data/app/forms/decidim/proposals/admin/proposals_fork_form.rb +2 -2
  45. data/app/forms/decidim/proposals/admin/proposals_import_form.rb +1 -1
  46. data/app/forms/decidim/proposals/proposal_form.rb +11 -4
  47. data/app/forms/decidim/proposals/proposal_wizard_create_step_form.rb +3 -0
  48. data/app/helpers/decidim/proposals/admin/proposal_bulk_actions_helper.rb +4 -0
  49. data/app/helpers/decidim/proposals/application_helper.rb +4 -17
  50. data/app/helpers/decidim/proposals/proposal_cells_helper.rb +1 -3
  51. data/app/helpers/decidim/proposals/proposal_wizard_helper.rb +7 -7
  52. data/app/helpers/decidim/proposals/proposals_helper.rb +1 -1
  53. data/app/jobs/decidim/proposals/notify_proposals_mentioned_job.rb +1 -1
  54. data/app/models/decidim/proposals/collaborative_draft.rb +10 -0
  55. data/app/models/decidim/proposals/collaborative_draft_collaborator_request.rb +0 -2
  56. data/app/models/decidim/proposals/proposal.rb +47 -8
  57. data/app/queries/decidim/proposals/filtered_proposals.rb +1 -1
  58. data/app/queries/decidim/proposals/similar_proposals.rb +1 -1
  59. data/app/services/decidim/proposals/proposal_search.rb +16 -71
  60. data/app/validators/proposal_length_validator.rb +2 -5
  61. data/app/views/decidim/proposals/admin/participatory_texts/_article-preview.html.erb +2 -2
  62. data/app/views/decidim/proposals/admin/proposals/_form.html.erb +1 -1
  63. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +2 -2
  64. data/app/views/decidim/proposals/admin/proposals/edit.html.erb +0 -1
  65. data/app/views/decidim/proposals/admin/proposals/index.html.erb +0 -1
  66. data/app/views/decidim/proposals/admin/proposals/new.html.erb +0 -1
  67. data/app/views/decidim/proposals/admin/proposals/publish_answers.js.erb +1 -1
  68. data/app/views/decidim/proposals/admin/proposals/show.html.erb +0 -1
  69. data/app/views/decidim/proposals/admin/proposals/update_attribute.js.erb +26 -0
  70. data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +9 -17
  71. data/app/views/decidim/proposals/collaborative_drafts/_filters.html.erb +4 -4
  72. data/app/views/decidim/proposals/collaborative_drafts/_wizard_aside.html.erb +1 -1
  73. data/app/views/decidim/proposals/collaborative_drafts/edit.html.erb +3 -1
  74. data/app/views/decidim/proposals/collaborative_drafts/new.html.erb +3 -1
  75. data/app/views/decidim/proposals/collaborative_drafts/show.html.erb +1 -1
  76. data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +13 -36
  77. data/app/views/decidim/proposals/proposals/_filters.html.erb +5 -5
  78. data/app/views/decidim/proposals/proposals/_linked_proposals.html.erb +1 -2
  79. data/app/views/decidim/proposals/proposals/_proposals.html.erb +5 -5
  80. data/app/views/decidim/proposals/proposals/complete.html.erb +3 -1
  81. data/app/views/decidim/proposals/proposals/edit.html.erb +3 -1
  82. data/app/views/decidim/proposals/proposals/edit_draft.html.erb +3 -1
  83. data/app/views/decidim/proposals/proposals/new.html.erb +3 -1
  84. data/config/locales/am-ET.yml +1 -0
  85. data/config/locales/ar.yml +4 -262
  86. data/config/locales/bg.yml +1 -19
  87. data/config/locales/ca.yml +19 -31
  88. data/config/locales/cs.yml +34 -46
  89. data/config/locales/da.yml +1 -0
  90. data/config/locales/de.yml +10 -107
  91. data/config/locales/el.yml +5 -146
  92. data/config/locales/en.yml +12 -25
  93. data/config/locales/eo.yml +1 -0
  94. data/config/locales/es-MX.yml +20 -32
  95. data/config/locales/es-PY.yml +20 -32
  96. data/config/locales/es.yml +15 -27
  97. data/config/locales/et.yml +1 -0
  98. data/config/locales/eu.yml +283 -343
  99. data/config/locales/fi-plain.yml +17 -28
  100. data/config/locales/fi.yml +21 -32
  101. data/config/locales/fr-CA.yml +19 -32
  102. data/config/locales/fr.yml +31 -44
  103. data/config/locales/ga-IE.yml +1 -2
  104. data/config/locales/gl.yml +16 -13
  105. data/config/locales/hr.yml +1 -0
  106. data/config/locales/hu.yml +13 -64
  107. data/config/locales/id-ID.yml +5 -19
  108. data/config/locales/is-IS.yml +8 -17
  109. data/config/locales/it.yml +12 -18
  110. data/config/locales/ja.yml +67 -79
  111. data/config/locales/ko.yml +1 -0
  112. data/config/locales/lb.yml +1 -0
  113. data/config/locales/lt.yml +1 -1007
  114. data/config/locales/lv.yml +5 -17
  115. data/config/locales/mt.yml +1 -0
  116. data/config/locales/nl.yml +15 -20
  117. data/config/locales/no.yml +6 -11
  118. data/config/locales/om-ET.yml +1 -0
  119. data/config/locales/pl.yml +5 -28
  120. data/config/locales/pt-BR.yml +6 -33
  121. data/config/locales/pt.yml +6 -13
  122. data/config/locales/ro-RO.yml +9 -9
  123. data/config/locales/ru.yml +8 -16
  124. data/config/locales/si-LK.yml +1 -0
  125. data/config/locales/sk.yml +6 -18
  126. data/config/locales/sl.yml +4 -0
  127. data/config/locales/so-SO.yml +1 -0
  128. data/config/locales/sr-CS.yml +1 -2
  129. data/config/locales/sv.yml +12 -12
  130. data/config/locales/sw-KE.yml +1 -0
  131. data/config/locales/ti-ER.yml +1 -0
  132. data/config/locales/tr-TR.yml +7 -14
  133. data/config/locales/uk.yml +8 -16
  134. data/config/locales/val-ES.yml +1 -0
  135. data/config/locales/vi.yml +1 -0
  136. data/config/locales/zh-CN.yml +5 -16
  137. data/config/locales/zh-TW.yml +1 -964
  138. data/db/migrate/20180529110230_move_authorships_to_coauthorships.rb +1 -0
  139. data/db/migrate/20181003074440_fix_user_groups_ids_in_proposals_endorsements.rb +2 -9
  140. data/db/migrate/20200708091228_move_proposals_fields_to_i18n.rb +18 -28
  141. data/db/migrate/20201002085508_fix_proposals_data.rb +13 -25
  142. data/lib/decidim/proposals/component.rb +25 -21
  143. data/lib/decidim/proposals/engine.rb +0 -6
  144. data/lib/decidim/proposals/import/proposal_answer_creator.rb +4 -10
  145. data/lib/decidim/proposals/proposal_serializer.rb +1 -9
  146. data/lib/decidim/proposals/test/factories.rb +1 -1
  147. data/lib/decidim/proposals/version.rb +1 -1
  148. metadata +25 -52
  149. data/app/services/decidim/proposals/collaborative_draft_search.rb +0 -59
  150. data/app/views/decidim/proposals/admin/proposals/_js-callout.html.erb +0 -6
  151. data/app/views/decidim/proposals/admin/proposals/update_category.js.erb +0 -26
  152. data/app/views/decidim/proposals/admin/proposals/update_scope.js.erb +0 -27
  153. data/config/environment.rb +0 -3
  154. data/config/locales/fa-IR.yml +0 -1
  155. data/config/locales/gn-PY.yml +0 -1
  156. data/config/locales/ka-GE.yml +0 -1
  157. data/config/locales/kaa.yml +0 -1
  158. data/config/locales/lo-LA.yml +0 -1
  159. data/config/locales/oc-FR.yml +0 -1
  160. data/config/locales/sq-AL.yml +0 -1
  161. data/config/locales/th-TH.yml +0 -1
  162. data/lib/tasks/proposals/upgrade/decdim_proposal_upgrade_tasks.rake +0 -34
@@ -5,7 +5,7 @@ module Decidim
5
5
  # Exposes the proposal vote resource so users can vote proposals.
6
6
  class ProposalVotesController < Decidim::Proposals::ApplicationController
7
7
  include ProposalVotesHelper
8
- include Rectify::ControllerHelpers
8
+ include Decidim::ControllerHelpers
9
9
 
10
10
  helper_method :proposal
11
11
 
@@ -25,6 +25,13 @@ module Decidim
25
25
 
26
26
  before_action :set_participatory_text
27
27
 
28
+ # rubocop:disable Naming/VariableNumber
29
+ STEP1 = :step_1
30
+ STEP2 = :step_2
31
+ STEP3 = :step_3
32
+ STEP4 = :step_4
33
+ # rubocop:enable Naming/VariableNumber
34
+
28
35
  def index
29
36
  if component_settings.participatory_texts_enabled?
30
37
  @proposals = Decidim::Proposals::Proposal
@@ -37,7 +44,7 @@ module Decidim
37
44
  render "decidim/proposals/proposals/participatory_texts/participatory_text"
38
45
  else
39
46
  @base_query = search
40
- .results
47
+ .result
41
48
  .published
42
49
  .not_hidden
43
50
 
@@ -52,8 +59,8 @@ module Decidim
52
59
  else
53
60
  []
54
61
  end
55
- @proposals = reorder(@proposals)
56
62
  @proposals = paginate(@proposals)
63
+ @proposals = reorder(@proposals)
57
64
  end
58
65
  end
59
66
 
@@ -63,7 +70,7 @@ module Decidim
63
70
 
64
71
  def new
65
72
  enforce_permission_to :create, :proposal
66
- @step = :step_1
73
+ @step = STEP1
67
74
  if proposal_draft.present?
68
75
  redirect_to edit_draft_proposal_path(proposal_draft, component_id: proposal_draft.component.id, question_slug: proposal_draft.component.participatory_space.slug)
69
76
  else
@@ -73,7 +80,7 @@ module Decidim
73
80
 
74
81
  def create
75
82
  enforce_permission_to :create, :proposal
76
- @step = :step_1
83
+ @step = STEP1
77
84
  @form = form(ProposalWizardCreateStepForm).from_params(proposal_creation_params)
78
85
 
79
86
  CreateProposal.call(@form, current_user) do
@@ -92,7 +99,7 @@ module Decidim
92
99
 
93
100
  def compare
94
101
  enforce_permission_to :edit, :proposal, proposal: @proposal
95
- @step = :step_2
102
+ @step = STEP2
96
103
  @similar_proposals ||= Decidim::Proposals::SimilarProposals
97
104
  .for(current_component, @proposal)
98
105
  .all
@@ -105,7 +112,7 @@ module Decidim
105
112
 
106
113
  def complete
107
114
  enforce_permission_to :edit, :proposal, proposal: @proposal
108
- @step = :step_3
115
+ @step = STEP3
109
116
 
110
117
  @form = form_proposal_model
111
118
 
@@ -114,13 +121,13 @@ module Decidim
114
121
 
115
122
  def preview
116
123
  enforce_permission_to :edit, :proposal, proposal: @proposal
117
- @step = :step_4
124
+ @step = STEP4
118
125
  @form = form(ProposalForm).from_model(@proposal)
119
126
  end
120
127
 
121
128
  def publish
122
129
  enforce_permission_to :edit, :proposal, proposal: @proposal
123
- @step = :step_4
130
+ @step = STEP4
124
131
  PublishProposal.call(@proposal, current_user) do
125
132
  on(:ok) do
126
133
  flash[:notice] = I18n.t("proposals.publish.success", scope: "decidim")
@@ -135,12 +142,12 @@ module Decidim
135
142
  end
136
143
 
137
144
  def edit_draft
138
- @step = :step_3
145
+ @step = STEP3
139
146
  enforce_permission_to :edit, :proposal, proposal: @proposal
140
147
  end
141
148
 
142
149
  def update_draft
143
- @step = :step_1
150
+ @step = STEP1
144
151
  enforce_permission_to :edit, :proposal, proposal: @proposal
145
152
 
146
153
  @form = form_proposal_params
@@ -211,25 +218,25 @@ module Decidim
211
218
 
212
219
  private
213
220
 
214
- def search_klass
215
- ProposalSearch
221
+ def search_collection
222
+ Proposal.where(component: current_component).published.not_hidden.with_availability(params[:filter].try(:[], :with_availability))
216
223
  end
217
224
 
218
225
  def default_filter_params
219
226
  {
220
- search_text: "",
221
- origin: default_filter_origin_params,
227
+ search_text_cont: "",
228
+ with_any_origin: default_filter_origin_params,
222
229
  activity: "all",
223
- category_id: default_filter_category_params,
224
- state: %w(accepted evaluating state_not_published),
225
- scope_id: default_filter_scope_params,
230
+ with_any_category: default_filter_category_params,
231
+ with_any_state: %w(accepted evaluating state_not_published),
232
+ with_any_scope: default_filter_scope_params,
226
233
  related_to: "",
227
234
  type: "all"
228
235
  }
229
236
  end
230
237
 
231
238
  def default_filter_origin_params
232
- filter_origin_params = %w(citizens meeting)
239
+ filter_origin_params = %w(participants meeting)
233
240
  filter_origin_params << "official" if component_settings.official_proposals_enabled
234
241
  filter_origin_params << "user_group" if current_organization.user_groups_enabled?
235
242
  filter_origin_params
@@ -13,8 +13,6 @@ module Decidim
13
13
  end
14
14
 
15
15
  def i18n_options
16
- return super if author.blank?
17
-
18
16
  author_path = link_to("@#{author.nickname}", profile_path(author.nickname))
19
17
  author_string = "#{author.name} #{author_path}"
20
18
  super.merge({ author: author_string })
@@ -37,12 +35,6 @@ module Decidim
37
35
  I18n.with_locale(I18n.locale) { translated_attribute(resource_text, nil, true).to_s.html_safe }
38
36
  end
39
37
 
40
- def notification_title
41
- i18n_key = resource.official? ? "notification_title_official" : "notification_title"
42
-
43
- I18n.t(i18n_key, **i18n_options).html_safe
44
- end
45
-
46
38
  private
47
39
 
48
40
  def i18n_scope
@@ -15,7 +15,7 @@ module Decidim
15
15
 
16
16
  translatable_attribute :title, String
17
17
  translatable_attribute :description, String
18
- attribute :document
18
+ attribute :document, Decidim::Attributes::Blob
19
19
 
20
20
  validates :title, translatable_presence: true
21
21
  validates :document, presence: true, if: :new_participatory_text?
@@ -44,9 +44,9 @@ module Decidim
44
44
  end
45
45
 
46
46
  def i18n_invalid_document_type_text
47
- I18n.t("invalid_document_type",
47
+ I18n.t("allowed_file_content_types",
48
48
  scope: "activemodel.errors.models.participatory_text.attributes.document",
49
- valid_mime_types: i18n_valid_mime_types_text)
49
+ types: i18n_valid_mime_types_text)
50
50
  end
51
51
 
52
52
  def i18n_valid_mime_types_text
@@ -60,7 +60,7 @@ module Decidim
60
60
  end
61
61
 
62
62
  def document_text
63
- @document_text ||= document&.read
63
+ @document_text ||= document&.download
64
64
  end
65
65
  end
66
66
  end
@@ -57,14 +57,14 @@ module Decidim
57
57
  #
58
58
  # Returns a Decidim::Scope
59
59
  def scope
60
- @scope ||= @scope_id ? current_component.scopes.find_by(id: @scope_id) : current_component.scope
60
+ @scope ||= @attributes["scope_id"].value ? current_component.scopes.find_by(id: @attributes["scope_id"].value) : current_component.scope
61
61
  end
62
62
 
63
63
  # Scope identifier
64
64
  #
65
65
  # Returns the scope identifier related to the proposal
66
66
  def scope_id
67
- @scope_id || scope&.id
67
+ super || scope&.id
68
68
  end
69
69
 
70
70
  def geocoding_enabled?
@@ -101,7 +101,7 @@ module Decidim
101
101
  end
102
102
 
103
103
  def suggested_hashtags
104
- downcased_suggested_hashtags = Array(@suggested_hashtags&.map(&:downcase)).to_set
104
+ downcased_suggested_hashtags = super.map(&:downcase).to_set
105
105
  component_suggested_hashtags.select { |hashtag| downcased_suggested_hashtags.member?(hashtag.downcase) }
106
106
  end
107
107
 
@@ -129,7 +129,7 @@ module Decidim
129
129
  end
130
130
 
131
131
  def ordered_hashtag_list(string)
132
- string.to_s.split.reject(&:blank?).uniq.sort_by(&:parameterize)
132
+ string.to_s.split.compact_blank.uniq.sort_by(&:parameterize)
133
133
  end
134
134
  end
135
135
  end
@@ -5,6 +5,8 @@ module Decidim
5
5
  module Admin
6
6
  # A form object to be used when admin users want to create a proposal.
7
7
  class ProposalForm < Decidim::Proposals::Admin::ProposalBaseForm
8
+ include Decidim::HasUploadValidations
9
+
8
10
  translatable_attribute :title, String do |field, _locale|
9
11
  validates field, length: { in: 15..150 }, if: proc { |resource| resource.send(field).present? }
10
12
  end
@@ -7,7 +7,7 @@ module Decidim
7
7
  class ProposalsForkForm < Decidim::Form
8
8
  mimic :proposals_import
9
9
 
10
- attribute :target_component_id, Integer
10
+ attribute :target_component_id, Array[Integer]
11
11
  attribute :proposal_ids, Array
12
12
 
13
13
  validates :target_component, :proposals, :current_component, presence: true
@@ -55,7 +55,7 @@ module Decidim
55
55
  #
56
56
  # We receive this as ["id"] since it's from a select in a form.
57
57
  def clean_target_component_id
58
- target_component_id.first.to_i
58
+ target_component_id.first
59
59
  end
60
60
  end
61
61
  end
@@ -31,7 +31,7 @@ module Decidim
31
31
  end
32
32
 
33
33
  def states
34
- super.reject(&:blank?)
34
+ super.compact_blank
35
35
  end
36
36
 
37
37
  def scopes
@@ -6,6 +6,7 @@ module Decidim
6
6
  class ProposalForm < Decidim::Proposals::ProposalWizardCreateStepForm
7
7
  include Decidim::TranslatableAttributes
8
8
  include Decidim::AttachmentAttributes
9
+ include Decidim::HasUploadValidations
9
10
 
10
11
  mimic :proposal
11
12
 
@@ -41,6 +42,12 @@ module Decidim
41
42
  self.scope_id = model.scope.id if model.scope
42
43
 
43
44
  self.has_address = true if model.address.present?
45
+
46
+ # Proposals have the "photos" field reserved for the proposal card image
47
+ # so we don't want to show all photos there. Instead, only show the
48
+ # first photo.
49
+ self.photos = [model.photo].compact.select { |p| p.weight.zero? }
50
+ self.documents = model.attachments - photos
44
51
  end
45
52
 
46
53
  # Finds the Category from the category_id.
@@ -54,14 +61,14 @@ module Decidim
54
61
  #
55
62
  # Returns a Decidim::Scope
56
63
  def scope
57
- @scope ||= @scope_id ? current_component.scopes.find_by(id: @scope_id) : current_component.scope
64
+ @scope ||= @attributes["scope_id"].value ? current_component.scopes.find_by(id: @attributes["scope_id"].value) : current_component.scope
58
65
  end
59
66
 
60
67
  # Scope identifier
61
68
  #
62
69
  # Returns the scope identifier related to the proposal
63
70
  def scope_id
64
- @scope_id || scope&.id
71
+ super || scope&.id
65
72
  end
66
73
 
67
74
  def geocoding_enabled?
@@ -89,7 +96,7 @@ module Decidim
89
96
  end
90
97
 
91
98
  def suggested_hashtags
92
- downcased_suggested_hashtags = Array(@suggested_hashtags&.map(&:downcase)).to_set
99
+ downcased_suggested_hashtags = super.map(&:downcase).to_set
93
100
  component_suggested_hashtags.select { |hashtag| downcased_suggested_hashtags.member?(hashtag.downcase) }
94
101
  end
95
102
 
@@ -119,7 +126,7 @@ module Decidim
119
126
  end
120
127
 
121
128
  def ordered_hashtag_list(string)
122
- string.to_s.split.reject(&:blank?).uniq.sort_by(&:parameterize)
129
+ string.to_s.split.compact_blank.uniq.sort_by(&:parameterize)
123
130
  end
124
131
  end
125
132
  end
@@ -23,6 +23,9 @@ module Decidim
23
23
  alias component current_component
24
24
 
25
25
  def map_model(model)
26
+ self.title = translated_attribute(model.title)
27
+ self.body = translated_attribute(model.body)
28
+
26
29
  self.user_group_id = model.user_groups.first&.id
27
30
  return unless model.categorization
28
31
 
@@ -4,6 +4,10 @@ module Decidim
4
4
  module Proposals
5
5
  module Admin
6
6
  module ProposalBulkActionsHelper
7
+ def proposal_find(id)
8
+ Decidim::Proposals::Proposal.find(id)
9
+ end
10
+
7
11
  # Public: Generates a select field with the valuators of the given participatory space.
8
12
  #
9
13
  # participatory_space - A participatory space instance.
@@ -40,12 +40,10 @@ module Decidim
40
40
  case state
41
41
  when "accepted"
42
42
  "text-success"
43
- when "rejected"
43
+ when "rejected", "withdrawn"
44
44
  "text-alert"
45
45
  when "evaluating"
46
46
  "text-warning"
47
- when "withdrawn"
48
- "text-alert"
49
47
  else
50
48
  "text-info"
51
49
  end
@@ -97,23 +95,12 @@ module Decidim
97
95
  # the proposal comes from a collaborative_draft or a participatory_text.
98
96
  def safe_content?
99
97
  (rich_text_editor_in_public_views? && not_from_collaborative_draft(@proposal)) ||
100
- safe_content_admin?
101
- end
102
-
103
- # For admin entered content, the proposal body can contain certain extra
104
- # tags, such as iframes.
105
- def safe_content_admin?
106
- (@proposal.official? || @proposal.official_meeting?) && not_from_participatory_text(@proposal)
98
+ ((@proposal.official? || @proposal.official_meeting?) && not_from_participatory_text(@proposal))
107
99
  end
108
100
 
109
101
  # If the content is safe, HTML tags are sanitized, otherwise, they are stripped.
110
102
  def render_proposal_body(proposal)
111
- sanitized = render_sanitized_content(proposal, :body)
112
- if safe_content?
113
- Decidim::ContentProcessor.render_without_format(sanitized).html_safe
114
- else
115
- Decidim::ContentProcessor.render(sanitized, "div")
116
- end
103
+ Decidim::ContentProcessor.render(render_sanitized_content(proposal, :body), "div")
117
104
  end
118
105
 
119
106
  # Returns :text_area or :editor based on the organization' settings.
@@ -183,7 +170,7 @@ module Decidim
183
170
  def filter_origin_values
184
171
  origin_values = []
185
172
  origin_values << TreePoint.new("official", t("decidim.proposals.application_helper.filter_origin_values.official")) if component_settings.official_proposals_enabled
186
- origin_values << TreePoint.new("citizens", t("decidim.proposals.application_helper.filter_origin_values.citizens"))
173
+ origin_values << TreePoint.new("participants", t("decidim.proposals.application_helper.filter_origin_values.participants"))
187
174
  origin_values << TreePoint.new("user_group", t("decidim.proposals.application_helper.filter_origin_values.user_groups")) if current_organization.user_groups_enabled?
188
175
  origin_values << TreePoint.new("meeting", t("decidim.proposals.application_helper.filter_origin_values.meetings"))
189
176
 
@@ -60,12 +60,10 @@ module Decidim
60
60
  case state
61
61
  when "accepted"
62
62
  ["success"]
63
- when "rejected"
63
+ when "rejected", "withdrawn"
64
64
  ["alert"]
65
65
  when "evaluating"
66
66
  ["warning"]
67
- when "withdrawn"
68
- ["alert"]
69
67
  else
70
68
  ["muted"]
71
69
  end
@@ -73,10 +73,10 @@ module Decidim
73
73
  def proposal_wizard_stepper(current_step)
74
74
  content_tag :ol, class: "wizard__steps" do
75
75
  %(
76
- #{proposal_wizard_stepper_step(:step_1, current_step)}
77
- #{proposal_wizard_stepper_step(:step_2, current_step)}
78
- #{proposal_wizard_stepper_step(:step_3, current_step)}
79
- #{proposal_wizard_stepper_step(:step_4, current_step)}
76
+ #{proposal_wizard_stepper_step(ProposalsController::STEP1, current_step)}
77
+ #{proposal_wizard_stepper_step(ProposalsController::STEP2, current_step)}
78
+ #{proposal_wizard_stepper_step(ProposalsController::STEP3, current_step)}
79
+ #{proposal_wizard_stepper_step(ProposalsController::STEP4, current_step)}
80
80
  ).html_safe
81
81
  end
82
82
  end
@@ -120,11 +120,11 @@ module Decidim
120
120
  # Renders the back link except for step_2: compare
121
121
  def proposal_wizard_aside_link_to_back(step)
122
122
  case step
123
- when :step_1
123
+ when ProposalsController::STEP1
124
124
  proposals_path
125
- when :step_3
125
+ when ProposalsController::STEP3
126
126
  compare_proposal_path
127
- when :step_4
127
+ when ProposalsController::STEP4
128
128
  edit_draft_proposal_path
129
129
  end
130
130
  end
@@ -7,7 +7,7 @@ module Decidim
7
7
  def proposal_reason_callout_announcement
8
8
  {
9
9
  title: proposal_reason_callout_title,
10
- body: decidim_sanitize_editor_admin(translated_attribute(@proposal.answer))
10
+ body: decidim_sanitize_editor(translated_attribute(@proposal.answer))
11
11
  }
12
12
  end
13
13
 
@@ -8,7 +8,7 @@ module Decidim
8
8
 
9
9
  linked_proposals.each do |proposal_id|
10
10
  proposal = Proposal.find(proposal_id)
11
- affected_users = proposal.notifiable_identities - [comment.author]
11
+ affected_users = proposal.notifiable_identities
12
12
 
13
13
  Decidim::EventsManager.publish(
14
14
  event: "decidim.events.proposals.proposal_mentioned",
@@ -16,6 +16,7 @@ module Decidim
16
16
  include Decidim::Traceable
17
17
  include Decidim::Loggable
18
18
  include Decidim::Randomable
19
+ include Decidim::FilterableResource
19
20
 
20
21
  has_many :collaborator_requests,
21
22
  class_name: "Decidim::Proposals::CollaborativeDraftCollaboratorRequest",
@@ -35,6 +36,8 @@ module Decidim
35
36
  scope :except_withdrawn, -> { where.not(state: "withdrawn").or(where(state: nil)) }
36
37
  scope :published, -> { where(state: "published") }
37
38
 
39
+ scope_search_multi :with_any_state, [:open, :published, :withdrawn]
40
+
38
41
  # Checks whether the user can edit the given proposal.
39
42
  #
40
43
  # user - the user to check for authorship
@@ -68,6 +71,13 @@ module Decidim
68
71
  def reported_searchable_content_extras
69
72
  [authors.map(&:name).join("\n")]
70
73
  end
74
+
75
+ # Create the :search_text ransacker alias for searching from both :title or :body.
76
+ ransacker_text_multi :search_text, [:title, :body]
77
+
78
+ def self.ransackable_scopes(_auth_object = nil)
79
+ [:with_any_state, :related_to, :with_any_scope, :with_any_category]
80
+ end
71
81
  end
72
82
  end
73
83
  end
@@ -4,8 +4,6 @@ module Decidim
4
4
  module Proposals
5
5
  # A collaborative_draft can accept requests to coauthor and contribute
6
6
  class CollaborativeDraftCollaboratorRequest < Proposals::ApplicationRecord
7
- validates :collaborative_draft, :user, presence: true
8
-
9
7
  belongs_to :collaborative_draft, class_name: "Decidim::Proposals::CollaborativeDraft", foreign_key: :decidim_proposals_collaborative_draft_id
10
8
  belongs_to :user, class_name: "Decidim::User", foreign_key: :decidim_user_id
11
9
  end
@@ -18,7 +18,7 @@ module Decidim
18
18
  include Decidim::Traceable
19
19
  include Decidim::Loggable
20
20
  include Decidim::Fingerprintable
21
- include Decidim::DataPortability
21
+ include Decidim::DownloadYourData
22
22
  include Decidim::Proposals::ParticipatoryTextSection
23
23
  include Decidim::Amendable
24
24
  include Decidim::NewsletterParticipant
@@ -27,6 +27,7 @@ module Decidim
27
27
  include Decidim::Proposals::Valuatable
28
28
  include Decidim::TranslatableResource
29
29
  include Decidim::TranslatableAttributes
30
+ include Decidim::FilterableResource
30
31
 
31
32
  translatable_fields :title, :body
32
33
 
@@ -67,10 +68,33 @@ module Decidim
67
68
  scope :except_rejected, -> { where.not(state: "rejected").or(state_not_published) }
68
69
  scope :except_withdrawn, -> { where.not(state: "withdrawn").or(where(state: nil)) }
69
70
  scope :drafts, -> { where(published_at: nil) }
70
- scope :except_drafts, -> { where.not(published_at: nil) }
71
71
  scope :published, -> { where.not(published_at: nil) }
72
72
  scope :order_by_most_recent, -> { order(created_at: :desc) }
73
73
 
74
+ scope :with_availability, lambda { |state_key|
75
+ case state_key
76
+ when "withdrawn"
77
+ withdrawn
78
+ else
79
+ except_withdrawn
80
+ end
81
+ }
82
+
83
+ scope :with_type, lambda { |type_key, user, component|
84
+ case type_key
85
+ when "proposals"
86
+ only_amendables
87
+ when "amendments"
88
+ only_visible_emendations_for(user, component)
89
+ else # Assume 'all'
90
+ amendables_and_visible_emendations_for(user, component)
91
+ end
92
+ }
93
+
94
+ scope :voted_by, lambda { |user|
95
+ includes(:votes).where(decidim_proposals_proposal_votes: { decidim_author_id: user })
96
+ }
97
+
74
98
  scope :sort_by_valuation_assignments_count_asc, lambda {
75
99
  order(Arel.sql("#{sort_by_valuation_assignments_count_nulls_last_query} ASC NULLS FIRST").to_s)
76
100
  }
@@ -79,6 +103,8 @@ module Decidim
79
103
  order(Arel.sql("#{sort_by_valuation_assignments_count_nulls_last_query} DESC NULLS LAST").to_s)
80
104
  }
81
105
 
106
+ scope_search_multi :with_any_state, [:accepted, :rejected, :evaluating, :state_not_published]
107
+
82
108
  def self.with_valuation_assigned_to(user, space)
83
109
  valuator_roles = space.user_roles(:valuator).where(user: user)
84
110
 
@@ -103,7 +129,7 @@ module Decidim
103
129
  end
104
130
 
105
131
  # Returns a collection scoped by an author.
106
- # Overrides this method in DataPortability to support Coauthorable.
132
+ # Overrides this method in DownloadYourData to support Coauthorable.
107
133
  def self.user_collection(author)
108
134
  return unless author.is_a?(Decidim::User)
109
135
 
@@ -241,8 +267,9 @@ module Decidim
241
267
  end
242
268
 
243
269
  # Public: Overrides the `reported_searchable_content_extras` Reportable concern method.
270
+ # Returns authors name or title in case it's a meeting
244
271
  def reported_searchable_content_extras
245
- [authors.map(&:name).join("\n")]
272
+ [authors.map { |p| p.respond_to?(:name) ? p.name : p.title }.join("\n")]
246
273
  end
247
274
 
248
275
  # Public: Whether the proposal is official or not.
@@ -252,7 +279,7 @@ module Decidim
252
279
 
253
280
  # Public: Whether the proposal is created in a meeting or not.
254
281
  def official_meeting?
255
- authors.first.class.name == "Decidim::Meetings::Meeting"
282
+ authors.first.instance_of?(Decidim::Meetings::Meeting)
256
283
  end
257
284
 
258
285
  # Public: The maximum amount of votes allowed for this proposal.
@@ -302,6 +329,10 @@ module Decidim
302
329
  published_at.nil?
303
330
  end
304
331
 
332
+ def self.ransack(params = {}, options = {})
333
+ ProposalSearch.new(self, params, options)
334
+ end
335
+
305
336
  # Defines the base query so that ransack can actually sort by this value
306
337
  def self.sort_by_valuation_assignments_count_nulls_last_query
307
338
  <<-SQL.squish
@@ -327,10 +358,18 @@ module Decidim
327
358
  where(query, value: value)
328
359
  end
329
360
 
330
- def self.ransackable_scopes(_auth = nil)
331
- [:valuator_role_ids_has]
361
+ def self.ransackable_scopes(auth_object = nil)
362
+ base = [:with_any_origin, :with_any_state, :voted_by, :coauthored_by, :related_to, :with_any_scope, :with_any_category]
363
+ return base unless auth_object&.admin?
364
+
365
+ # Add extra scopes for admins for the admin panel searches
366
+ base + [:valuator_role_ids_has]
332
367
  end
333
368
 
369
+ # Create i18n ransackers for :title and :body.
370
+ # Create the :search_text ransacker alias for searching from both of these.
371
+ ransacker_i18n_multi :search_text, [:title, :body]
372
+
334
373
  ransacker :state_published do
335
374
  Arel.sql("CASE
336
375
  WHEN EXISTS (
@@ -379,7 +418,7 @@ module Decidim
379
418
  Decidim::Proposals::ProposalSerializer
380
419
  end
381
420
 
382
- def self.data_portability_images(user)
421
+ def self.download_your_data_images(user)
383
422
  user_collection(user).map { |p| p.attachments.collect(&:file) }
384
423
  end
385
424
 
@@ -3,7 +3,7 @@
3
3
  module Decidim
4
4
  module Proposals
5
5
  # A class used to find proposals filtered by components and a date range
6
- class FilteredProposals < Rectify::Query
6
+ class FilteredProposals < Decidim::Query
7
7
  # Syntactic sugar to initialize the class and return the queried objects.
8
8
  #
9
9
  # components - An array of Decidim::Component
@@ -3,7 +3,7 @@
3
3
  module Decidim
4
4
  module Proposals
5
5
  # Class used to retrieve similar proposals.
6
- class SimilarProposals < Rectify::Query
6
+ class SimilarProposals < Decidim::Query
7
7
  include Decidim::TranslationsHelper
8
8
 
9
9
  # Syntactic sugar to initialize the class and return the queried objects.