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
@@ -13,6 +13,7 @@ module Decidim
13
13
  attribute :scope_id, Integer
14
14
  attribute :has_address, Boolean
15
15
  attribute :attachment, AttachmentForm
16
+ attribute :suggested_hashtags, Array[String]
16
17
 
17
18
  validates :address, geocoding: true, if: ->(form) { Decidim.geocoder.present? && form.has_address? }
18
19
  validates :address, presence: true, if: ->(form) { form.has_address? }
@@ -25,6 +26,12 @@ module Decidim
25
26
 
26
27
  delegate :categories, to: :current_component
27
28
 
29
+ def map_model(model)
30
+ super
31
+
32
+ @suggested_hashtags = Decidim::ContentRenderers::HashtagRenderer.new(model.body).extra_hashtags.map(&:name).map(&:downcase)
33
+ end
34
+
28
35
  # Finds the Category from the category_id.
29
36
  #
30
37
  # Returns a Decidim::Category
@@ -50,6 +57,27 @@ module Decidim
50
57
  current_component.settings.geocoding_enabled? && has_address
51
58
  end
52
59
 
60
+ def extra_hashtags
61
+ @extra_hashtags ||= (component_automatic_hashtags + suggested_hashtags).uniq
62
+ end
63
+
64
+ def suggested_hashtags
65
+ downcased_suggested_hashtags = Array(@suggested_hashtags&.map(&:downcase)).to_set
66
+ component_suggested_hashtags.select { |hashtag| downcased_suggested_hashtags.member?(hashtag.downcase) }
67
+ end
68
+
69
+ def suggested_hashtag_checked?(hashtag)
70
+ suggested_hashtags.member?(hashtag)
71
+ end
72
+
73
+ def component_automatic_hashtags
74
+ @component_automatic_hashtags ||= ordered_hashtag_list(current_component.current_settings.automatic_hashtags)
75
+ end
76
+
77
+ def component_suggested_hashtags
78
+ @component_suggested_hashtags ||= ordered_hashtag_list(current_component.current_settings.suggested_hashtags)
79
+ end
80
+
53
81
  private
54
82
 
55
83
  def scope_belongs_to_participatory_space_scope
@@ -63,6 +91,10 @@ module Decidim
63
91
  def notify_missing_attachment_if_errored
64
92
  errors.add(:attachment, :needs_to_be_reattached) if errors.any? && attachment.present?
65
93
  end
94
+
95
+ def ordered_hashtag_list(string)
96
+ string.to_s.split.reject(&:blank?).uniq.sort_by(&:parameterize)
97
+ end
66
98
  end
67
99
  end
68
100
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ module Admin
6
+ # This class contains helpers needed to format Meetings
7
+ # in order to use them in select forms for Proposals.
8
+ #
9
+ module ProposalsHelper
10
+ # Public: A formatted collection of Meetings to be used
11
+ # in forms.
12
+ def meetings_as_authors_selected
13
+ return unless @proposal.present? && @proposal.official_meeting?
14
+ @meetings_as_authors_selected ||= @proposal.authors.pluck(:id)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -12,6 +12,7 @@ module Decidim
12
12
  include Decidim::MapHelper
13
13
  include Decidim::Proposals::MapHelper
14
14
  include CollaborativeDraftHelper
15
+ include ControlVersionHelper
15
16
 
16
17
  delegate :minimum_votes_per_user, to: :component_settings
17
18
 
@@ -36,9 +37,11 @@ module Decidim
36
37
  when "rejected"
37
38
  "text-alert"
38
39
  when "evaluating"
39
- "text-info"
40
- else
41
40
  "text-warning"
41
+ when "withdrawn"
42
+ "text-alert"
43
+ else
44
+ "text-info"
42
45
  end
43
46
  end
44
47
 
@@ -92,16 +95,16 @@ module Decidim
92
95
  Proposal.where(component: current_component, author: current_user)
93
96
  end
94
97
 
95
- def follow_button_for(model)
96
- if current_user
97
- render partial: "decidim/shared/follow_button.html", locals: { followable: model }
98
- else
99
- content_tag(:p, class: "mt-s mb-none") do
100
- t("decidim.proposals.proposals.show.sign_in_or_up",
101
- in: link_to(t("decidim.proposals.proposals.show.sign_in"), decidim.new_user_session_path),
102
- up: link_to(t("decidim.proposals.proposals.show.sign_up"), decidim.new_user_registration_path)).html_safe
103
- end
104
- end
98
+ def follow_button_for(model, large = nil)
99
+ render partial: "decidim/shared/follow_button.html", locals: { followable: model, large: large }
100
+ end
101
+
102
+ def votes_count_for(model, from_proposals_list)
103
+ render partial: "decidim/proposals/proposals/participatory_texts/proposal_votes_count.html", locals: { proposal: model, from_proposals_list: from_proposals_list }
104
+ end
105
+
106
+ def vote_button_for(model, from_proposals_list)
107
+ render partial: "decidim/proposals/proposals/participatory_texts/proposal_vote_button.html", locals: { proposal: model, from_proposals_list: from_proposals_list }
105
108
  end
106
109
 
107
110
  def endorsers_for(proposal)
@@ -125,6 +128,39 @@ module Decidim
125
128
  return true if can_accumulate_supports_beyond_threshold?
126
129
  return true if minimum_votes_per_user_enabled?
127
130
  end
131
+
132
+ def filter_origin_values
133
+ base = if component_settings.official_proposals_enabled
134
+ [
135
+ ["all", t("decidim.proposals.application_helper.filter_origin_values.all")],
136
+ ["official", t("decidim.proposals.application_helper.filter_origin_values.official")]
137
+ ]
138
+ else
139
+ [["all", t("decidim.proposals.application_helper.filter_origin_values.all")]]
140
+ end
141
+
142
+ base += [["citizens", t("decidim.proposals.application_helper.filter_origin_values.citizens")]]
143
+ base += [["user_group", t("decidim.proposals.application_helper.filter_origin_values.user_groups")]] if current_organization.user_groups_enabled?
144
+ base + [["meeting", t("decidim.proposals.application_helper.filter_origin_values.meetings")]]
145
+ end
146
+
147
+ def filter_state_values
148
+ [
149
+ ["except_rejected", t("decidim.proposals.application_helper.filter_state_values.except_rejected")],
150
+ ["accepted", t("decidim.proposals.application_helper.filter_state_values.accepted")],
151
+ ["evaluating", t("decidim.proposals.application_helper.filter_state_values.evaluating")],
152
+ ["rejected", t("decidim.proposals.application_helper.filter_state_values.rejected")],
153
+ ["all", t("decidim.proposals.application_helper.filter_state_values.all")]
154
+ ]
155
+ end
156
+
157
+ def filter_type_values
158
+ [
159
+ ["all", t("decidim.proposals.application_helper.filter_type_values.all")],
160
+ ["proposals", t("decidim.proposals.application_helper.filter_type_values.proposals")],
161
+ ["amendments", t("decidim.proposals.application_helper.filter_type_values.amendments")]
162
+ ]
163
+ end
128
164
  end
129
165
  end
130
166
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ # Custom helpers, scoped to the proposals engine.
6
+ #
7
+ module ControlVersionHelper
8
+ def versions_controller?
9
+ return true if params[:controller] == "decidim/proposals/versions"
10
+
11
+ false
12
+ end
13
+
14
+ def proposal?
15
+ return true if item.class == Decidim::Proposals::Proposal
16
+
17
+ false
18
+ end
19
+
20
+ def back_to_resource_path_text
21
+ return unless versions_controller?
22
+
23
+ if proposal?
24
+ t("versions.stats.back_to_proposal", scope: "decidim.proposals")
25
+ else
26
+ t("versions.stats.back_to_collaborative_draft", scope: "decidim.proposals")
27
+ end
28
+ end
29
+
30
+ def back_to_resource_path
31
+ return unless versions_controller?
32
+
33
+ if proposal?
34
+ proposal_path(item)
35
+ else
36
+ collaborative_draft_path(item)
37
+ end
38
+ end
39
+
40
+ def resource_version_path(index)
41
+ return unless versions_controller?
42
+
43
+ if proposal?
44
+ proposal_version_path(item, index + 1)
45
+ else
46
+ collaborative_draft_version_path(item, index + 1)
47
+ end
48
+ end
49
+
50
+ def resource_all_versions_path
51
+ return unless versions_controller?
52
+
53
+ if proposal?
54
+ proposal_versions_path(item)
55
+ else
56
+ collaborative_draft_versions_path(item)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -13,6 +13,14 @@ module Decidim
13
13
  translated = t(proposal.participatory_text_level, scope: "decidim.proposals.admin.participatory_texts.sections", title: proposal.title)
14
14
  translated.html_safe
15
15
  end
16
+
17
+ def render_participatory_text_title(participatory_text)
18
+ if participatory_text.nil?
19
+ t("alternative_title", scope: "decidim.proposals.participatory_text_proposal")
20
+ else
21
+ translated_attribute(participatory_text.title)
22
+ end
23
+ end
16
24
  end
17
25
  end
18
26
  end
@@ -14,9 +14,15 @@ module Decidim
14
14
  include Decidim::TranslatableAttributes
15
15
  include Decidim::CardHelper
16
16
 
17
- delegate :title, :state, :answered?, :withdrawn?, to: :model
17
+ delegate :title, :state, :answered?, :withdrawn?, :amendable?, :emendation?, to: :model
18
18
 
19
19
  def has_actions?
20
+ return context[:has_actions] if context[:has_actions].present?
21
+ proposals_controller? && index_action? && current_settings.votes_enabled? && !model.draft?
22
+ end
23
+
24
+ def has_footer?
25
+ return context[:has_footer] if context[:has_footer].present?
20
26
  proposals_controller? && index_action? && current_settings.votes_enabled? && !model.draft?
21
27
  end
22
28
 
@@ -108,10 +108,11 @@ module Decidim
108
108
  end
109
109
 
110
110
  # Renders the counter of endorsements that appears in card at show Propoal.
111
- def render_endorsements_count_card_part(proposal, fully_endorsed)
111
+ def render_endorsements_count_card_part(proposal, fully_endorsed, html_class = nil)
112
112
  content = icon("bullhorn", class: "icon--small", aria_label: "Endorsements", role: "img")
113
113
  content += proposal.proposal_endorsements_count.to_s
114
- tag_params = { id: "proposal-#{proposal.id}-endorsements-count", class: "button small compact light button--sc button--shadow #{fully_endorsed ? "success" : "secondary"}" }
114
+ html_class = "button small compact light button--sc button--shadow" if html_class.blank?
115
+ tag_params = { id: "proposal-#{proposal.id}-endorsements-count", class: "#{html_class} #{fully_endorsed ? "success" : "secondary"}" }
115
116
  if proposal.proposal_endorsements_count.positive?
116
117
  link_to "#list-of-endorsements", tag_params do
117
118
  content
@@ -123,18 +124,19 @@ module Decidim
123
124
  end
124
125
  end
125
126
 
126
- def render_endorsements_button_card_part(proposal, fully_endorsed)
127
+ def render_endorsements_button_card_part(proposal, fully_endorsed, html_class = nil)
127
128
  endorse_translated = t("decidim.proposals.proposal_endorsements_helper.render_endorsements_button_card_part.endorse")
129
+ html_class = "card__button button" if html_class.blank?
128
130
  if current_settings.endorsements_blocked? || !current_component.participatory_space.can_participate?(current_user)
129
- content_tag :span, endorse_translated, class: "card__button button #{endorsement_button_classes(false)} disabled", disabled: true, title: endorse_translated
131
+ content_tag :span, endorse_translated, class: "#{html_class} #{endorsement_button_classes(false)} disabled", disabled: true, title: endorse_translated
130
132
  elsif current_user && allowed_to?(:endorse, :proposal, proposal: proposal)
131
133
  render partial: "endorsement_identities_cabin", locals: { proposal: proposal, fully_endorsed: fully_endorsed }
132
134
  elsif current_user
133
135
  button_to(endorse_translated, proposal_path(proposal),
134
136
  data: { open: "authorizationModal", "open-url": modal_path(:endorse, proposal) },
135
- class: "card__button button #{endorsement_button_classes(false)} secondary")
137
+ class: "#{html_class} #{endorsement_button_classes(false)} secondary")
136
138
  else
137
- action_authorized_button_to :endorse, endorse_translated, "", resource: proposal, class: "card__button button #{endorsement_button_classes(false)} secondary"
139
+ action_authorized_button_to :endorse, endorse_translated, "", resource: proposal, class: "#{html_class} #{endorsement_button_classes(false)} secondary"
138
140
  end
139
141
  end
140
142
  end
@@ -8,13 +8,13 @@ module Decidim
8
8
 
9
9
  linked_proposals.each do |proposal_id|
10
10
  proposal = Proposal.find(proposal_id)
11
- recipient_ids = proposal.notifiable_authors.map(&:id)
11
+ affected_users = proposal.notifiable_identities
12
12
 
13
13
  Decidim::EventsManager.publish(
14
14
  event: "decidim.events.proposals.proposal_mentioned",
15
15
  event_class: Decidim::Proposals::ProposalMentionedEvent,
16
16
  resource: comment.root_commentable,
17
- recipient_ids: recipient_ids,
17
+ affected_users: affected_users,
18
18
  extra: {
19
19
  comment_id: comment.id,
20
20
  mentioned_proposal_id: proposal_id
@@ -23,26 +23,28 @@ module Decidim
23
23
  event: event,
24
24
  event_class: event_class,
25
25
  resource: component,
26
- recipient_ids: component.participatory_space.followers.pluck(:id)
26
+ followers: component.participatory_space.followers
27
27
  )
28
28
  end
29
29
 
30
30
  private
31
31
 
32
+ # rubocop:disable Style/DoubleNegation
32
33
  def creation_enabled?(previous_settings, current_settings)
33
34
  current_settings[:creation_enabled] == true &&
34
- previous_settings[:creation_enabled] == false
35
+ !!previous_settings[:creation_enabled] == false
35
36
  end
36
37
 
37
38
  def voting_enabled?(previous_settings, current_settings)
38
- (current_settings[:votes_enabled] == true && current_settings[:votes_blocked] == false) &&
39
- (previous_settings[:votes_enabled] == false || previous_settings[:votes_blocked] == true)
39
+ (current_settings[:votes_enabled] == true && !!current_settings[:votes_blocked] == false) &&
40
+ (!!previous_settings[:votes_enabled] == false || previous_settings[:votes_blocked] == true)
40
41
  end
41
42
 
42
43
  def endorsing_enabled?(previous_settings, current_settings)
43
- (current_settings[:endorsements_enabled] == true && current_settings[:endorsements_blocked] == false) &&
44
- (previous_settings[:endorsements_enabled] == false || previous_settings[:endorsements_blocked] == true)
44
+ (current_settings[:endorsements_enabled] == true && !!current_settings[:endorsements_blocked] == false) &&
45
+ (!!previous_settings[:endorsements_enabled] == false || previous_settings[:endorsements_blocked] == true)
45
46
  end
47
+ # rubocop:enable Style/DoubleNegation
46
48
  end
47
49
  end
48
50
  end
@@ -27,8 +27,11 @@ module Decidim
27
27
  class_name: "Decidim::User",
28
28
  foreign_key: :decidim_user_id
29
29
 
30
+ geocoded_by :address, http_headers: ->(collaborative_draft) { { "Referer" => collaborative_draft.component.organization.host } }
31
+
30
32
  scope :open, -> { where(state: "open") }
31
33
  scope :withdrawn, -> { where(state: "withdrawn") }
34
+ scope :except_withdrawn, -> { where.not(state: "withdrawn").or(where(state: nil)) }
32
35
  scope :published, -> { where(state: "published") }
33
36
 
34
37
  # Checks whether the user can edit the given proposal.
@@ -21,9 +21,16 @@ module Decidim
21
21
  include Decidim::DataPortability
22
22
  include Decidim::Hashtaggable
23
23
  include Decidim::Proposals::ParticipatoryTextSection
24
+ include Decidim::Amendable
24
25
 
25
26
  fingerprint fields: [:title, :body]
26
27
 
28
+ amendable(
29
+ fields: [:title, :body],
30
+ ignore: [:published_at, :reference, :state, :answered_at, :answer],
31
+ form: "Decidim::Proposals::ProposalForm"
32
+ )
33
+
27
34
  component_manifest_name "proposals"
28
35
 
29
36
  has_many :endorsements, foreign_key: "decidim_proposal_id", class_name: "ProposalEndorsement", dependent: :destroy, counter_cache: "proposal_endorsements_count"
@@ -59,7 +66,7 @@ module Decidim
59
66
  A: :search_title,
60
67
  datetime: :published_at
61
68
  },
62
- index_on_create: false,
69
+ index_on_create: ->(proposal) { proposal.official? },
63
70
  index_on_update: ->(proposal) { proposal.visible? })
64
71
 
65
72
  def self.order_randomly(seed)
@@ -159,6 +166,11 @@ module Decidim
159
166
  authors.first.is_a?(Decidim::Organization)
160
167
  end
161
168
 
169
+ # Public: Whether the proposal is created in a meeting or not.
170
+ def official_meeting?
171
+ authors.first.class.name == "Decidim::Meetings::Meeting"
172
+ end
173
+
162
174
  # Public: The maximum amount of votes allowed for this proposal.
163
175
  #
164
176
  # Returns an Integer with the maximum amount of votes, nil otherwise.
@@ -190,7 +202,7 @@ module Decidim
190
202
  # user - the user to check for authorship
191
203
  def editable_by?(user)
192
204
  return true if draft?
193
- authored_by?(user) && !answered? && within_edit_time_limit? && !copied_from_other_component?
205
+ !answered? && within_edit_time_limit? && !copied_from_other_component? && created_by?(user)
194
206
  end
195
207
 
196
208
  # Checks whether the user can withdraw the given proposal.
@@ -208,12 +220,12 @@ module Decidim
208
220
  # method for sort_link by number of comments
209
221
  ransacker :commentable_comments_count do
210
222
  query = <<-SQL
211
- (SELECT COUNT(decidim_comments_comments.id)
212
- FROM decidim_comments_comments
213
- WHERE decidim_comments_comments.decidim_commentable_id = decidim_proposals_proposals.id
214
- AND decidim_comments_comments.decidim_commentable_type = 'Decidim::Proposals::Proposal'
215
- GROUP BY decidim_comments_comments.decidim_commentable_id
216
- )
223
+ (SELECT COUNT(decidim_comments_comments.id)
224
+ FROM decidim_comments_comments
225
+ WHERE decidim_comments_comments.decidim_commentable_id = decidim_proposals_proposals.id
226
+ AND decidim_comments_comments.decidim_commentable_type = 'Decidim::Proposals::Proposal'
227
+ GROUP BY decidim_comments_comments.decidim_commentable_id
228
+ )
217
229
  SQL
218
230
  Arel.sql(query)
219
231
  end
@@ -61,7 +61,7 @@ module Decidim
61
61
 
62
62
  def admin_edition_is_available?
63
63
  return unless proposal
64
- proposal.official? && proposal.votes.empty?
64
+ (proposal.official? || proposal.official_meeting?) && proposal.votes.empty?
65
65
  end
66
66
 
67
67
  def admin_proposal_answering_is_enabled?
@@ -7,8 +7,9 @@ module Decidim
7
7
  class ProposalTitleBodyPresenter < Decidim::Log::ValueTypes::DefaultPresenter
8
8
  def present
9
9
  return unless value
10
+
10
11
  renderer = Decidim::ContentRenderers::HashtagRenderer.new(value)
11
- renderer.render_without_link.html_safe
12
+ renderer.render(links: false).html_safe
12
13
  end
13
14
  end
14
15
  end