decidim-proposals 0.15.2 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +12 -0
  3. data/app/assets/config/decidim_proposals_manifest.js +1 -0
  4. data/app/assets/javascripts/decidim/proposals/add_proposal.js.es6 +1 -1
  5. data/app/assets/javascripts/decidim/proposals/admin/proposals_form.js.es6 +23 -0
  6. data/app/cells/decidim/proposals/collaborative_draft_cell.rb +0 -2
  7. data/app/cells/decidim/proposals/collaborative_draft_m_cell.rb +5 -1
  8. data/app/cells/decidim/proposals/highlighted_proposals/show.erb +3 -0
  9. data/app/cells/decidim/proposals/highlighted_proposals_cell.rb +25 -0
  10. data/app/cells/decidim/proposals/highlighted_proposals_for_component/show.erb +19 -0
  11. data/app/cells/decidim/proposals/highlighted_proposals_for_component_cell.rb +34 -0
  12. data/app/cells/decidim/proposals/participatory_text_proposal/buttons.erb +33 -0
  13. data/app/cells/decidim/proposals/participatory_text_proposal/show.erb +9 -0
  14. data/app/cells/decidim/proposals/participatory_text_proposal_cell.rb +77 -0
  15. data/app/cells/decidim/proposals/proposal_cell.rb +0 -2
  16. data/app/cells/decidim/proposals/proposal_m/footer.erb +1 -1
  17. data/app/cells/decidim/proposals/proposal_m_cell.rb +6 -1
  18. data/app/commands/decidim/proposals/accept_access_to_collaborative_draft.rb +3 -3
  19. data/app/commands/decidim/proposals/admin/answer_proposal.rb +2 -1
  20. data/app/commands/decidim/proposals/admin/create_proposal.rb +7 -7
  21. data/app/commands/decidim/proposals/admin/import_participatory_text.rb +8 -8
  22. data/app/commands/decidim/proposals/admin/update_proposal.rb +13 -6
  23. data/app/commands/decidim/proposals/admin/update_proposal_category.rb +1 -1
  24. data/app/commands/decidim/proposals/create_collaborative_draft.rb +6 -3
  25. data/app/commands/decidim/proposals/create_proposal.rb +25 -11
  26. data/app/commands/decidim/proposals/endorse_proposal.rb +1 -2
  27. data/app/commands/decidim/proposals/hashtags_methods.rb +36 -0
  28. data/app/commands/decidim/proposals/publish_collaborative_draft.rb +39 -34
  29. data/app/commands/decidim/proposals/publish_proposal.rb +13 -17
  30. data/app/commands/decidim/proposals/reject_access_to_collaborative_draft.rb +2 -3
  31. data/app/commands/decidim/proposals/request_access_to_collaborative_draft.rb +1 -2
  32. data/app/commands/decidim/proposals/update_collaborative_draft.rb +11 -8
  33. data/app/commands/decidim/proposals/update_proposal.rb +37 -13
  34. data/app/commands/decidim/proposals/withdraw_collaborative_draft.rb +3 -3
  35. data/app/commands/decidim/proposals/withdraw_proposal.rb +14 -1
  36. data/app/controllers/decidim/proposals/admin/participatory_texts_controller.rb +2 -1
  37. data/app/controllers/decidim/proposals/admin/proposals_controller.rb +9 -1
  38. data/app/controllers/decidim/proposals/collaborative_drafts_controller.rb +8 -0
  39. data/app/controllers/decidim/proposals/proposals_controller.rb +64 -27
  40. data/app/controllers/decidim/proposals/versions_controller.rb +5 -1
  41. data/app/events/decidim/proposals/accepted_proposal_event.rb +8 -0
  42. data/app/events/decidim/proposals/evaluating_proposal_event.rb +3 -0
  43. data/app/events/decidim/proposals/proposal_endorsed_event.rb +4 -0
  44. data/app/events/decidim/proposals/publish_proposal_event.rb +4 -0
  45. data/app/events/decidim/proposals/rejected_proposal_event.rb +8 -0
  46. data/app/forms/decidim/proposals/admin/import_participatory_text_form.rb +4 -0
  47. data/app/forms/decidim/proposals/admin/proposal_form.rb +49 -0
  48. data/app/forms/decidim/proposals/collaborative_draft_form.rb +2 -0
  49. data/app/forms/decidim/proposals/proposal_form.rb +32 -0
  50. data/app/helpers/decidim/proposals/admin/proposals_helper.rb +19 -0
  51. data/app/helpers/decidim/proposals/application_helper.rb +48 -12
  52. data/app/helpers/decidim/proposals/control_version_helper.rb +61 -0
  53. data/app/helpers/decidim/proposals/participatory_texts_helper.rb +8 -0
  54. data/app/helpers/decidim/proposals/proposal_cells_helper.rb +7 -1
  55. data/app/helpers/decidim/proposals/proposal_endorsements_helper.rb +8 -6
  56. data/app/jobs/decidim/proposals/notify_proposals_mentioned_job.rb +2 -2
  57. data/app/jobs/decidim/proposals/settings_change_job.rb +8 -6
  58. data/app/models/decidim/proposals/collaborative_draft.rb +3 -0
  59. data/app/models/decidim/proposals/proposal.rb +20 -8
  60. data/app/permissions/decidim/proposals/admin/permissions.rb +1 -1
  61. data/app/presenters/decidim/proposals/admin_log/value_types/proposal_title_body_presenter.rb +2 -1
  62. data/app/presenters/decidim/proposals/collaborative_draft_presenter.rb +15 -2
  63. data/app/presenters/decidim/proposals/official_author_presenter.rb +4 -0
  64. data/app/presenters/decidim/proposals/proposal_presenter.rb +10 -14
  65. data/app/queries/decidim/proposals/metrics/endorsements_metric_manage.rb +54 -0
  66. data/app/queries/decidim/proposals/metrics/proposal_followers_metric_measure.rb +56 -0
  67. data/app/queries/decidim/proposals/metrics/proposal_participants_metric_measure.rb +64 -0
  68. data/app/services/decidim/proposals/proposal_search.rb +46 -5
  69. data/app/views/decidim/participatory_processes/participatory_process_groups/_highlighted_proposals.html.erb +1 -1
  70. data/app/views/decidim/proposals/admin/proposals/_form.html.erb +43 -2
  71. data/app/views/decidim/proposals/admin/proposals/_proposal-tr.html.erb +6 -2
  72. data/app/views/decidim/proposals/admin/proposals/edit.html.erb +1 -1
  73. data/app/views/decidim/proposals/admin/proposals/new.html.erb +1 -1
  74. data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +81 -0
  75. data/app/views/decidim/proposals/collaborative_drafts/complete.html.erb +1 -49
  76. data/app/views/decidim/proposals/collaborative_drafts/edit.html.erb +1 -29
  77. data/app/views/decidim/proposals/collaborative_drafts/show.html.erb +5 -5
  78. data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +27 -3
  79. data/app/views/decidim/proposals/proposals/_filters.html.erb +5 -2
  80. data/app/views/decidim/proposals/proposals/_proposal.html.erb +5 -1
  81. data/app/views/decidim/proposals/proposals/_proposal_similar.html.erb +2 -2
  82. data/app/views/decidim/proposals/proposals/_vote_button.html.erb +39 -35
  83. data/app/views/decidim/proposals/proposals/_votes_count.html.erb +16 -12
  84. data/app/views/decidim/proposals/proposals/new.html.erb +1 -1
  85. data/app/views/decidim/proposals/proposals/participatory_texts/_index.html.erb +19 -0
  86. data/app/views/decidim/proposals/proposals/participatory_texts/_proposal_vote_button.html.erb +46 -0
  87. data/app/views/decidim/proposals/proposals/participatory_texts/_proposal_votes_count.html.erb +41 -0
  88. data/app/views/decidim/proposals/proposals/participatory_texts/_view_index.html.erb +10 -0
  89. data/app/views/decidim/proposals/proposals/participatory_texts/participatory_text.html.erb +15 -0
  90. data/app/views/decidim/proposals/proposals/show.html.erb +45 -4
  91. data/app/views/decidim/proposals/versions/_version.html.erb +2 -2
  92. data/app/views/decidim/proposals/versions/index.html.erb +1 -1
  93. data/app/views/decidim/proposals/versions/show.html.erb +2 -2
  94. data/config/locales/ca.yml +87 -33
  95. data/config/locales/de.yml +87 -36
  96. data/config/locales/en.yml +87 -33
  97. data/config/locales/es-PY.yml +87 -33
  98. data/config/locales/es.yml +88 -34
  99. data/config/locales/eu.yml +87 -33
  100. data/config/locales/fi-pl.yml +87 -33
  101. data/config/locales/fi.yml +87 -33
  102. data/config/locales/fr.yml +87 -33
  103. data/config/locales/gl.yml +87 -33
  104. data/config/locales/hu.yml +87 -33
  105. data/config/locales/id-ID.yml +84 -30
  106. data/config/locales/it.yml +87 -33
  107. data/config/locales/nl.yml +87 -33
  108. data/config/locales/pl.yml +87 -33
  109. data/config/locales/pt-BR.yml +87 -33
  110. data/config/locales/pt.yml +87 -33
  111. data/config/locales/ru.yml +21 -38
  112. data/config/locales/sv.yml +87 -33
  113. data/config/locales/tr-TR.yml +86 -32
  114. data/config/locales/uk.yml +21 -38
  115. data/db/migrate/20181026073215_add_created_in_meeting.rb +7 -0
  116. data/lib/decidim/proposals.rb +2 -0
  117. data/lib/decidim/proposals/component.rb +74 -0
  118. data/lib/decidim/proposals/doc_to_markdown.rb +40 -0
  119. data/lib/decidim/proposals/engine.rb +52 -35
  120. data/lib/decidim/proposals/odt_to_markdown.rb +46 -0
  121. data/lib/decidim/proposals/proposal_serializer.rb +29 -13
  122. data/lib/decidim/proposals/test/factories.rb +76 -0
  123. data/lib/decidim/proposals/version.rb +1 -1
  124. metadata +56 -20
  125. data/app/views/decidim/participatory_spaces/_highlighted_proposals.html.erb +0 -15
@@ -47,14 +47,14 @@ module Decidim
47
47
  end
48
48
 
49
49
  def send_notification_to_authors
50
- recipient_ids = @collaborative_draft.authors.pluck(:id) - [@current_user.id]
51
- return if recipient_ids.blank?
50
+ recipients = @collaborative_draft.authors - [@current_user]
51
+ return if recipients.blank?
52
52
 
53
53
  Decidim::EventsManager.publish(
54
54
  event: "decidim.events.proposals.collaborative_draft_withdrawn",
55
55
  event_class: Decidim::Proposals::CollaborativeDraftWithdrawnEvent,
56
56
  resource: @collaborative_draft,
57
- recipient_ids: recipient_ids.uniq,
57
+ affected_users: recipients.uniq,
58
58
  extra: {
59
59
  author_id: @current_user.id
60
60
  }
@@ -22,7 +22,10 @@ module Decidim
22
22
  def call
23
23
  return broadcast(:invalid) if @proposal.votes.any?
24
24
 
25
- change_proposal_state_to_withdrawn
25
+ transaction do
26
+ change_proposal_state_to_withdrawn
27
+ reject_emendations_if_any
28
+ end
26
29
 
27
30
  broadcast(:ok, @proposal)
28
31
  end
@@ -32,6 +35,16 @@ module Decidim
32
35
  def change_proposal_state_to_withdrawn
33
36
  @proposal.update state: "withdrawn"
34
37
  end
38
+
39
+ def reject_emendations_if_any
40
+ return if @proposal.emendations.empty?
41
+
42
+ @proposal.emendations.each do |emendation|
43
+ @form = form(Decidim::Amendable::RejectForm).from_params(id: emendation.amendment.id)
44
+ result = Decidim::Amendable::Reject.call(@form)
45
+ return result[:ok] if result[:ok]
46
+ end
47
+ end
35
48
  end
36
49
  end
37
50
  end
@@ -16,7 +16,8 @@ module Decidim
16
16
 
17
17
  def new_import
18
18
  enforce_permission_to :import, :participatory_texts
19
- @import = form(Admin::ImportParticipatoryTextForm).instance
19
+ participatory_text = Decidim::Proposals::ParticipatoryText.find_by(component: current_component)
20
+ @import = form(Admin::ImportParticipatoryTextForm).from_model(participatory_text)
20
21
  end
21
22
 
22
23
  def import
@@ -5,8 +5,10 @@ module Decidim
5
5
  module Admin
6
6
  # This controller allows admins to manage proposals in a participatory process.
7
7
  class ProposalsController < Admin::ApplicationController
8
+ include Decidim::ApplicationHelper
9
+
8
10
  helper Proposals::ApplicationHelper
9
- helper_method :proposals, :query
11
+ helper_method :proposals, :query, :form_presenter
10
12
 
11
13
  def new
12
14
  enforce_permission_to :create, :proposal
@@ -104,6 +106,7 @@ module Decidim
104
106
 
105
107
  def update_proposals_category_response_successful(response)
106
108
  return if response[:successful].blank?
109
+
107
110
  I18n.t(
108
111
  "proposals.update_category.success",
109
112
  category: response[:category_name],
@@ -114,6 +117,7 @@ module Decidim
114
117
 
115
118
  def update_proposals_category_response_errored(response)
116
119
  return if response[:errored].blank?
120
+
117
121
  I18n.t(
118
122
  "proposals.update_category.invalid",
119
123
  category: response[:category_name],
@@ -121,6 +125,10 @@ module Decidim
121
125
  scope: "decidim.proposals.admin"
122
126
  )
123
127
  end
128
+
129
+ def form_presenter
130
+ @form_presenter ||= present(@form, presenter_class: Decidim::Proposals::ProposalPresenter)
131
+ end
124
132
  end
125
133
  end
126
134
  end
@@ -7,11 +7,15 @@ module Decidim
7
7
  helper Decidim::WidgetUrlsHelper
8
8
  helper ProposalWizardHelper
9
9
  helper TooltipHelper
10
+
11
+ include Decidim::ApplicationHelper
10
12
  include FormFactory
11
13
  include FilterResource
12
14
  include CollaborativeOrderable
13
15
  include Paginable
14
16
 
17
+ helper_method :form_presenter
18
+
15
19
  helper_method :geocoded_collaborative_draft, :collaborative_draft
16
20
  before_action :collaborative_drafts_enabled?
17
21
  before_action :authenticate_user!, only: [:new, :create, :complete]
@@ -140,6 +144,10 @@ module Decidim
140
144
 
141
145
  private
142
146
 
147
+ def form_presenter
148
+ @form_presenter ||= present(@form, presenter_class: Decidim::Proposals::CollaborativeDraftPresenter)
149
+ end
150
+
143
151
  def collaborative_drafts_enabled?
144
152
  raise ActionController::RoutingError, "Not Found" unless component_settings.collaborative_drafts_enabled?
145
153
  end
@@ -6,34 +6,50 @@ module Decidim
6
6
  class ProposalsController < Decidim::Proposals::ApplicationController
7
7
  helper Decidim::WidgetUrlsHelper
8
8
  helper ProposalWizardHelper
9
+ helper ParticipatoryTextsHelper
10
+ include Decidim::ApplicationHelper
9
11
  include FormFactory
10
12
  include FilterResource
11
13
  include Orderable
12
14
  include Paginable
13
15
 
16
+ helper_method :form_presenter
17
+
14
18
  before_action :authenticate_user!, only: [:new, :create, :complete]
15
19
  before_action :ensure_is_draft, only: [:compare, :complete, :preview, :publish, :edit_draft, :update_draft, :destroy_draft]
16
20
  before_action :set_proposal, only: [:show, :edit, :update, :withdraw]
17
21
  before_action :edit_form, only: [:edit_draft, :edit]
22
+
23
+ before_action :set_participatory_text
24
+
18
25
  def index
19
- @proposals = search
20
- .results
21
- .published
22
- .not_hidden
23
- .includes(:category)
24
- .includes(:scope)
25
-
26
- @voted_proposals = if current_user
27
- ProposalVote.where(
28
- author: current_user,
29
- proposal: @proposals.pluck(:id)
30
- ).pluck(:decidim_proposal_id)
31
- else
32
- []
33
- end
34
-
35
- @proposals = paginate(@proposals)
36
- @proposals = reorder(@proposals)
26
+ if component_settings.participatory_texts_enabled?
27
+ @proposals = Decidim::Proposals::Proposal
28
+ .where(component: current_component)
29
+ .published
30
+ .not_hidden
31
+ .includes(:category, :scope)
32
+ .order(position: :asc)
33
+ render "decidim/proposals/proposals/participatory_texts/participatory_text"
34
+ else
35
+ @proposals = search
36
+ .results
37
+ .published
38
+ .not_hidden
39
+ .includes(:category)
40
+ .includes(:scope)
41
+
42
+ @voted_proposals = if current_user
43
+ ProposalVote.where(
44
+ author: current_user,
45
+ proposal: @proposals.pluck(:id)
46
+ ).pluck(:decidim_proposal_id)
47
+ else
48
+ []
49
+ end
50
+ @proposals = paginate(@proposals)
51
+ @proposals = reorder(@proposals)
52
+ end
37
53
  end
38
54
 
39
55
  def show
@@ -171,15 +187,27 @@ module Decidim
171
187
 
172
188
  def withdraw
173
189
  enforce_permission_to :withdraw, :proposal, proposal: @proposal
174
-
175
- WithdrawProposal.call(@proposal, current_user) do
176
- on(:ok) do |_proposal|
177
- flash[:notice] = I18n.t("proposals.update.success", scope: "decidim")
178
- redirect_to Decidim::ResourceLocatorPresenter.new(@proposal).path
190
+ if @proposal.emendation?
191
+ Decidim::Amendable::Withdraw.call(@proposal, current_user) do
192
+ on(:ok) do |_proposal|
193
+ flash[:notice] = I18n.t("proposals.update.success", scope: "decidim")
194
+ redirect_to Decidim::ResourceLocatorPresenter.new(@emendation).path
195
+ end
196
+ on(:invalid) do
197
+ flash[:alert] = I18n.t("proposals.update.error", scope: "decidim")
198
+ redirect_to Decidim::ResourceLocatorPresenter.new(@emendation).path
199
+ end
179
200
  end
180
- on(:invalid) do
181
- flash[:alert] = I18n.t("proposals.update.error", scope: "decidim")
182
- redirect_to Decidim::ResourceLocatorPresenter.new(@proposal).path
201
+ else
202
+ WithdrawProposal.call(@proposal, current_user) do
203
+ on(:ok) do |_proposal|
204
+ flash[:notice] = I18n.t("proposals.update.success", scope: "decidim")
205
+ redirect_to Decidim::ResourceLocatorPresenter.new(@proposal).path
206
+ end
207
+ on(:invalid) do
208
+ flash[:alert] = I18n.t("proposals.update.error", scope: "decidim")
209
+ redirect_to Decidim::ResourceLocatorPresenter.new(@proposal).path
210
+ end
183
211
  end
184
212
  end
185
213
  end
@@ -198,7 +226,8 @@ module Decidim
198
226
  category_id: "",
199
227
  state: "except_rejected",
200
228
  scope_id: nil,
201
- related_to: ""
229
+ related_to: "",
230
+ type: "all"
202
231
  }
203
232
  end
204
233
 
@@ -223,6 +252,10 @@ module Decidim
223
252
  form(ProposalForm).from_model(@proposal)
224
253
  end
225
254
 
255
+ def form_presenter
256
+ @form_presenter ||= present(@form, presenter_class: Decidim::Proposals::ProposalPresenter)
257
+ end
258
+
226
259
  def form_attachment_new
227
260
  form(AttachmentForm).from_params({})
228
261
  end
@@ -233,6 +266,10 @@ module Decidim
233
266
  @form.attachment = form_attachment_model
234
267
  @form
235
268
  end
269
+
270
+ def set_participatory_text
271
+ @participatory_text = Decidim::Proposals::ParticipatoryText.find_by(component: current_component)
272
+ end
236
273
  end
237
274
  end
238
275
  end
@@ -11,7 +11,11 @@ module Decidim
11
11
  private
12
12
 
13
13
  def item
14
- @item ||= CollaborativeDraft.where(component: current_component).find(params[:collaborative_draft_id])
14
+ @item ||= if params[:proposal_id]
15
+ Proposal.where(component: current_component).find(params[:proposal_id])
16
+ else
17
+ CollaborativeDraft.where(component: current_component).find(params[:collaborative_draft_id])
18
+ end
15
19
  end
16
20
 
17
21
  def current_version
@@ -4,6 +4,14 @@ module Decidim
4
4
  module Proposals
5
5
  class AcceptedProposalEvent < Decidim::Events::SimpleEvent
6
6
  include Decidim::Events::AuthorEvent
7
+
8
+ def resource_text
9
+ translated_attribute(resource.answer)
10
+ end
11
+
12
+ def event_has_roles?
13
+ true
14
+ end
7
15
  end
8
16
  end
9
17
  end
@@ -3,6 +3,9 @@
3
3
  module Decidim
4
4
  module Proposals
5
5
  class EvaluatingProposalEvent < Decidim::Events::SimpleEvent
6
+ def event_has_roles?
7
+ true
8
+ end
6
9
  end
7
10
  end
8
11
  end
@@ -15,6 +15,10 @@ module Decidim
15
15
  endorser.profile_path
16
16
  end
17
17
 
18
+ def resource_text
19
+ resource.body
20
+ end
21
+
18
22
  private
19
23
 
20
24
  def endorser
@@ -5,6 +5,10 @@ module Decidim
5
5
  class PublishProposalEvent < Decidim::Events::SimpleEvent
6
6
  include Decidim::Events::CoauthorEvent
7
7
 
8
+ def resource_text
9
+ resource.body
10
+ end
11
+
8
12
  private
9
13
 
10
14
  def i18n_scope
@@ -4,6 +4,14 @@ module Decidim
4
4
  module Proposals
5
5
  class RejectedProposalEvent < Decidim::Events::SimpleEvent
6
6
  include Decidim::Events::AuthorEvent
7
+
8
+ def resource_text
9
+ translated_attribute(resource.answer)
10
+ end
11
+
12
+ def event_has_roles?
13
+ true
14
+ end
7
15
  end
8
16
  end
9
17
  end
@@ -22,6 +22,10 @@ module Decidim
22
22
  def document_text
23
23
  document&.read
24
24
  end
25
+
26
+ def document_type
27
+ document.content_type
28
+ end
25
29
  end
26
30
  end
27
31
  end
@@ -5,6 +5,7 @@ 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::Form
8
+ include Decidim::ApplicationHelper
8
9
  mimic :proposal
9
10
 
10
11
  attribute :title, String
@@ -16,12 +17,16 @@ module Decidim
16
17
  attribute :scope_id, Integer
17
18
  attribute :attachment, AttachmentForm
18
19
  attribute :position, Integer
20
+ attribute :created_in_meeting, Boolean
21
+ attribute :meeting_id, Integer
22
+ attribute :suggested_hashtags, Array[String]
19
23
 
20
24
  validates :title, :body, presence: true, etiquette: true
21
25
  validates :title, length: { maximum: 150 }
22
26
  validates :address, geocoding: true, if: -> { current_component.settings.geocoding_enabled? }
23
27
  validates :category, presence: true, if: ->(form) { form.category_id.present? }
24
28
  validates :scope, presence: true, if: ->(form) { form.scope_id.present? }
29
+ validates :meeting_as_author, presence: true, if: ->(form) { form.created_in_meeting? }
25
30
 
26
31
  validate :scope_belongs_to_participatory_space_scope
27
32
 
@@ -34,6 +39,8 @@ module Decidim
34
39
 
35
40
  self.category_id = model.categorization.decidim_category_id
36
41
  self.scope_id = model.decidim_scope_id
42
+
43
+ @suggested_hashtags = Decidim::ContentRenderers::HashtagRenderer.new(model.body).extra_hashtags.map(&:name).map(&:downcase)
37
44
  end
38
45
 
39
46
  alias component current_component
@@ -59,6 +66,44 @@ module Decidim
59
66
  @scope_id || scope&.id
60
67
  end
61
68
 
69
+ # Finds the Meetings of the current participatory space
70
+ def meetings
71
+ @meetings ||= Decidim.find_resource_manifest(:meetings).try(:resource_scope, current_component)
72
+ &.order(title: :asc)
73
+ end
74
+
75
+ # Return the meeting as author
76
+ def meeting_as_author
77
+ @meeting_as_author ||= meetings.find_by(id: meeting_id)
78
+ end
79
+
80
+ def author
81
+ return current_organization unless created_in_meeting?
82
+
83
+ meeting_as_author
84
+ end
85
+
86
+ def extra_hashtags
87
+ @extra_hashtags ||= (component_automatic_hashtags + suggested_hashtags).uniq
88
+ end
89
+
90
+ def suggested_hashtags
91
+ downcased_suggested_hashtags = Array(@suggested_hashtags&.map(&:downcase)).to_set
92
+ component_suggested_hashtags.select { |hashtag| downcased_suggested_hashtags.member?(hashtag.downcase) }
93
+ end
94
+
95
+ def suggested_hashtag_checked?(hashtag)
96
+ suggested_hashtags.member?(hashtag)
97
+ end
98
+
99
+ def component_automatic_hashtags
100
+ @component_automatic_hashtags ||= ordered_hashtag_list(current_component.current_settings.automatic_hashtags)
101
+ end
102
+
103
+ def component_suggested_hashtags
104
+ @component_suggested_hashtags ||= ordered_hashtag_list(current_component.current_settings.suggested_hashtags)
105
+ end
106
+
62
107
  private
63
108
 
64
109
  def scope_belongs_to_participatory_space_scope
@@ -72,6 +117,10 @@ module Decidim
72
117
  def notify_missing_attachment_if_errored
73
118
  errors.add(:attachment, :needs_to_be_reattached) if errors.any? && attachment.present?
74
119
  end
120
+
121
+ def ordered_hashtag_list(string)
122
+ string.to_s.split.reject(&:blank?).uniq.sort_by(&:parameterize)
123
+ end
75
124
  end
76
125
  end
77
126
  end
@@ -5,6 +5,8 @@ module Decidim
5
5
  # A form object to be used when public users want to create a Collaborative Draft.
6
6
  class CollaborativeDraftForm < Decidim::Proposals::ProposalForm
7
7
  def map_model(model)
8
+ super
9
+
8
10
  return unless model.categorization
9
11
 
10
12
  self.category_id = model.categorization.decidim_category_id