decidim-proposals 0.25.1 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) 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/cost_report_cell.rb +3 -3
  4. data/app/cells/decidim/proposals/participatory_text_proposal_cell.rb +1 -1
  5. data/app/cells/decidim/proposals/proposal_m_cell.rb +4 -5
  6. data/app/cells/decidim/proposals/proposals_picker_cell.rb +8 -5
  7. data/app/commands/decidim/proposals/update_proposal.rb +3 -2
  8. data/app/controllers/concerns/decidim/proposals/orderable.rb +21 -8
  9. data/app/controllers/decidim/proposals/admin/proposals_merges_controller.rb +4 -1
  10. data/app/controllers/decidim/proposals/admin/proposals_splits_controller.rb +4 -1
  11. data/app/controllers/decidim/proposals/proposals_controller.rb +2 -2
  12. data/app/events/decidim/proposals/admin/proposal_note_created_event.rb +1 -1
  13. data/app/events/decidim/proposals/proposal_mentioned_event.rb +8 -0
  14. data/app/events/decidim/proposals/publish_proposal_event.rb +26 -0
  15. data/app/forms/decidim/proposals/admin/proposals_file_import_form.rb +31 -0
  16. data/app/forms/decidim/proposals/admin/proposals_fork_form.rb +8 -3
  17. data/app/helpers/decidim/proposals/application_helper.rb +1 -6
  18. data/app/helpers/decidim/proposals/map_helper.rb +1 -1
  19. data/app/helpers/decidim/proposals/proposals_helper.rb +1 -1
  20. data/app/models/decidim/proposals/proposal.rb +3 -2
  21. data/app/packs/src/decidim/proposals/admin/proposals_picker.js +15 -0
  22. data/app/presenters/decidim/proposals/proposal_presenter.rb +2 -48
  23. data/app/queries/decidim/proposals/similar_proposals.rb +1 -1
  24. data/app/services/decidim/proposals/proposal_search.rb +9 -4
  25. data/app/views/decidim/proposals/admin/imports/_proposals_fields.html.erb +11 -0
  26. data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +7 -2
  27. data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +1 -1
  28. data/app/views/decidim/proposals/collaborative_drafts/_filters_small_view.html.erb +3 -3
  29. data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +2 -2
  30. data/app/views/decidim/proposals/proposals/_filters.html.erb +2 -0
  31. data/app/views/decidim/proposals/proposals/_filters_small_view.html.erb +3 -3
  32. data/app/views/decidim/proposals/proposals/_proposals.html.erb +18 -0
  33. data/app/views/decidim/proposals/proposals/index.html.erb +0 -5
  34. data/app/views/decidim/proposals/proposals/participatory_texts/_index.html.erb +2 -2
  35. data/config/brakeman.ignore +88 -0
  36. data/config/locales/ar.yml +0 -5
  37. data/config/locales/bg.yml +0 -2
  38. data/config/locales/ca.yml +58 -7
  39. data/config/locales/cs.yml +60 -5
  40. data/config/locales/de.yml +0 -5
  41. data/config/locales/el.yml +0 -5
  42. data/config/locales/en.yml +57 -6
  43. data/config/locales/es-MX.yml +56 -5
  44. data/config/locales/es-PY.yml +56 -5
  45. data/config/locales/es.yml +56 -5
  46. data/config/locales/eu.yml +38 -5
  47. data/config/locales/fi-plain.yml +56 -5
  48. data/config/locales/fi.yml +56 -5
  49. data/config/locales/fr-CA.yml +56 -5
  50. data/config/locales/fr.yml +59 -8
  51. data/config/locales/gl.yml +55 -5
  52. data/config/locales/hu.yml +1 -5
  53. data/config/locales/id-ID.yml +0 -4
  54. data/config/locales/is-IS.yml +0 -2
  55. data/config/locales/it.yml +13 -5
  56. data/config/locales/ja.yml +79 -30
  57. data/config/locales/lv.yml +0 -5
  58. data/config/locales/nl.yml +57 -5
  59. data/config/locales/no.yml +132 -5
  60. data/config/locales/pl.yml +5 -10
  61. data/config/locales/pt-BR.yml +1 -6
  62. data/config/locales/pt.yml +37 -5
  63. data/config/locales/ro-RO.yml +86 -33
  64. data/config/locales/ru.yml +0 -2
  65. data/config/locales/sk.yml +0 -5
  66. data/config/locales/sr-CS.yml +0 -1
  67. data/config/locales/sv.yml +56 -5
  68. data/config/locales/tr-TR.yml +0 -5
  69. data/config/locales/uk.yml +0 -2
  70. data/config/locales/val-ES.yml +1 -0
  71. data/config/locales/zh-CN.yml +0 -5
  72. data/lib/decidim/proposals/component.rb +37 -4
  73. data/lib/decidim/proposals/import/proposal_answer_creator.rb +95 -0
  74. data/lib/decidim/proposals/import/proposal_creator.rb +124 -0
  75. data/lib/decidim/proposals/import/proposals_answers_verifier.rb +29 -0
  76. data/lib/decidim/proposals/import/proposals_verifier.rb +16 -0
  77. data/lib/decidim/proposals/import.rb +12 -0
  78. data/lib/decidim/proposals/proposal_serializer.rb +6 -3
  79. data/lib/decidim/proposals/test/factories.rb +1 -9
  80. data/lib/decidim/proposals/version.rb +1 -1
  81. data/lib/decidim/proposals.rb +1 -1
  82. metadata +33 -25
  83. data/lib/decidim/proposals/proposal_creator.rb +0 -98
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 55c259beae9fa79f1a0c93000a53a032af8538025a154fedfdc0a1b273965d5b
4
- data.tar.gz: 2bd5eff8fa4f65df3e4c1ded51db2a9c0937b8b8b730c4df45ec946c6b3f71d9
3
+ metadata.gz: c38f3f49f8f2faf7009488fd029ead96309aee1e36a9deadfe98b629da781113
4
+ data.tar.gz: 68997b38f3851b3cdb308f1a613088caf23502a0e3efb0e33b1b631e554413d4
5
5
  SHA512:
6
- metadata.gz: e2dafbbaf79c82e48d2e84ba609733b83c1f9b634baa642ee9a4e31cf31d9593379e598549d74787a51ea9231c16ad116699840dc73f949d72377ce6dc157f1d
7
- data.tar.gz: bdffc9889742538195e18b7d182a8626cf0e81cf21d2d046b06391a8c6470cd02742f7880cfc14d21f967d51f60227b0b905247856475dc5c96a3148a52e8893
6
+ metadata.gz: fbf1fba0cc32479cba82cd9fa9adb7d2e2a7cf4e7c5aff2dfc5c8053a86194d967f74903bacba3b29a200603bd74dd82a38ebd82b45449ec3f87f11588d78741
7
+ data.tar.gz: f32885a1e51562bb44a0aba83aaa2ff76d1b55fcde574b439b5eeae32fdd72e6941f8c1889e3deb0c96a415144233a549ee3e49b91620dbd3d70877fa563fbdf
@@ -23,7 +23,7 @@ module Decidim
23
23
  end
24
24
 
25
25
  def description
26
- decidim_sanitize(present(model).body.truncate(100, separator: /\s/))
26
+ decidim_sanitize_editor(present(model).body.truncate(100, separator: /\s/))
27
27
  end
28
28
 
29
29
  def has_badge?
@@ -18,7 +18,7 @@ module Decidim
18
18
  end
19
19
 
20
20
  def cost_report
21
- decidim_sanitize(translated_attribute(model.cost_report).html_safe)
21
+ decidim_sanitize_editor(translated_attribute(model.cost_report).html_safe)
22
22
  end
23
23
 
24
24
  def needs_text_toggle?
@@ -26,7 +26,7 @@ module Decidim
26
26
  end
27
27
 
28
28
  def cost_report_short
29
- decidim_sanitize(
29
+ decidim_sanitize_editor(
30
30
  html_truncate(
31
31
  translated_attribute(model.cost_report).html_safe,
32
32
  length: 200
@@ -35,7 +35,7 @@ module Decidim
35
35
  end
36
36
 
37
37
  def execution_period
38
- decidim_sanitize(translated_attribute(model.execution_period).html_safe)
38
+ decidim_sanitize_editor(translated_attribute(model.execution_period).html_safe)
39
39
  end
40
40
  end
41
41
  end
@@ -35,7 +35,7 @@ module Decidim
35
35
  return unless model.participatory_text_level == "article"
36
36
 
37
37
  formatted = simple_format(present(model).body)
38
- decidim_sanitize(strip_links(formatted))
38
+ decidim_sanitize_editor(strip_links(formatted))
39
39
  end
40
40
 
41
41
  def resource_path
@@ -25,7 +25,7 @@ module Decidim
25
25
  end
26
26
 
27
27
  def body
28
- decidim_sanitize(present(model).body)
28
+ decidim_sanitize_editor(present(model).body)
29
29
  end
30
30
 
31
31
  def has_state?
@@ -118,7 +118,7 @@ module Decidim
118
118
  end
119
119
 
120
120
  def has_image?
121
- @has_image ||= model.component.settings.allow_card_image && model.attachments.find_by("content_type like '%image%'").present?
121
+ @has_image ||= model.attachments.map(&:image?).any?
122
122
  end
123
123
 
124
124
  def resource_image_path
@@ -127,7 +127,6 @@ module Decidim
127
127
 
128
128
  def cache_hash
129
129
  hash = []
130
- hash << "decidim/proposals/proposal_m"
131
130
  hash << I18n.locale.to_s
132
131
  hash << model.cache_key_with_version
133
132
  hash << model.proposal_votes_count
@@ -143,9 +142,9 @@ module Decidim
143
142
  hash << model.follows_count
144
143
  hash << Digest::MD5.hexdigest(model.authors.map(&:cache_key_with_version).to_s)
145
144
  hash << (model.must_render_translation?(model.organization) ? 1 : 0) if model.respond_to?(:must_render_translation?)
146
- hash << model.component.participatory_space.active_step.id if model.component.participatory_space.has_steps?
145
+ hash << model.component.participatory_space.active_step.id if model.component.participatory_space.try(:active_step)
147
146
 
148
- hash.join("/")
147
+ hash.join(Decidim.cache_key_separator)
149
148
  end
150
149
  end
151
150
  end
@@ -50,9 +50,10 @@ module Decidim
50
50
 
51
51
  def filtered_proposals
52
52
  @filtered_proposals ||= if filtered?
53
- proposals.where("title::text ILIKE ?", "%#{search_text}%")
54
- .or(proposals.where("reference ILIKE ?", "%#{search_text}%"))
55
- .or(proposals.where("id::text ILIKE ?", "%#{search_text}%"))
53
+ table_name = Decidim::Proposals::Proposal.table_name
54
+ proposals.where(%("#{table_name}"."title"::text ILIKE ?), "%#{search_text}%")
55
+ .or(proposals.where(%("#{table_name}"."reference" ILIKE ?), "%#{search_text}%"))
56
+ .or(proposals.where(%("#{table_name}"."id"::text ILIKE ?), "%#{search_text}%"))
56
57
  else
57
58
  proposals
58
59
  end
@@ -60,8 +61,10 @@ module Decidim
60
61
 
61
62
  def proposals
62
63
  @proposals ||= Decidim.find_resource_manifest(:proposals).try(:resource_scope, component)
63
- &.published
64
- &.order(id: :asc)
64
+ &.includes(:component)
65
+ &.published
66
+ &.not_hidden
67
+ &.order(id: :asc)
65
68
  end
66
69
 
67
70
  def proposals_collection_name
@@ -45,11 +45,12 @@ module Decidim
45
45
  else
46
46
  update_proposal
47
47
  end
48
- create_gallery if process_gallery?
49
- create_attachments if process_attachments?
50
48
 
51
49
  photo_cleanup!
52
50
  document_cleanup!
51
+
52
+ create_gallery if process_gallery?
53
+ create_attachments if process_attachments?
53
54
  end
54
55
 
55
56
  broadcast(:ok, proposal)
@@ -15,19 +15,32 @@ module Decidim
15
15
 
16
16
  # Available orders based on enabled settings
17
17
  def available_orders
18
- @available_orders ||= begin
19
- available_orders = %w(random recent)
20
- available_orders << "most_voted" if most_voted_order_available?
21
- available_orders << "most_endorsed" if current_settings.endorsements_enabled?
22
- available_orders << "most_commented" if component_settings.comments_enabled?
23
- available_orders << "most_followed" << "with_more_authors"
24
- available_orders
18
+ @available_orders ||= [default_order] + possible_orders.excluding(default_order)
19
+ end
20
+
21
+ def possible_orders
22
+ @possible_orders ||= begin
23
+ possible_orders = %w(random recent)
24
+ possible_orders << "most_voted" if most_voted_order_available?
25
+ possible_orders << "most_endorsed" if current_settings.endorsements_enabled?
26
+ possible_orders << "most_commented" if component_settings.comments_enabled?
27
+ possible_orders << "most_followed" << "with_more_authors"
28
+ possible_orders
25
29
  end
26
30
  end
27
31
 
28
32
  def default_order
33
+ @default_order ||= begin
34
+ default_order = current_settings.default_sort_order.presence || component_settings.default_sort_order
35
+ return order_by_default if default_order == "default"
36
+
37
+ possible_orders.include?(default_order) ? default_order : order_by_default
38
+ end
39
+ end
40
+
41
+ def order_by_default
29
42
  if order_by_votes?
30
- detect_order("most_voted")
43
+ "most_voted"
31
44
  else
32
45
  "random"
33
46
  end
@@ -16,7 +16,10 @@ module Decidim
16
16
  end
17
17
 
18
18
  on(:invalid) do
19
- flash[:alert] = I18n.t("proposals_merges.create.invalid", scope: "decidim.proposals.admin")
19
+ flash[:alert_html] = Decidim::ValidationErrorsPresenter.new(
20
+ I18n.t("proposals_merges.create.invalid", scope: "decidim.proposals.admin"),
21
+ @form
22
+ ).message
20
23
  redirect_to EngineRouter.admin_proxy(current_component).root_path
21
24
  end
22
25
  end
@@ -16,7 +16,10 @@ module Decidim
16
16
  end
17
17
 
18
18
  on(:invalid) do
19
- flash.now[:alert] = I18n.t("proposals_splits.create.invalid", scope: "decidim.proposals.admin")
19
+ flash[:alert_html] = Decidim::ValidationErrorsPresenter.new(
20
+ I18n.t("proposals_splits.create.invalid", scope: "decidim.proposals.admin"),
21
+ @form
22
+ ).message
20
23
  redirect_to EngineRouter.admin_proxy(current_component).root_path
21
24
  end
22
25
  end
@@ -32,7 +32,7 @@ module Decidim
32
32
  .published
33
33
  .not_hidden
34
34
  .only_amendables
35
- .includes(:category, :scope)
35
+ .includes(:category, :scope, :attachments, :coauthorships)
36
36
  .order(position: :asc)
37
37
  render "decidim/proposals/proposals/participatory_texts/participatory_text"
38
38
  else
@@ -41,7 +41,7 @@ module Decidim
41
41
  .published
42
42
  .not_hidden
43
43
 
44
- @proposals = @base_query.includes(:component, :coauthorships)
44
+ @proposals = @base_query.includes(:component, :coauthorships, :attachments)
45
45
  @all_geocoded_proposals = @base_query.geocoded
46
46
 
47
47
  @voted_proposals = if current_user
@@ -13,7 +13,7 @@ module Decidim
13
13
  end
14
14
 
15
15
  def admin_proposal_info_url
16
- decidim_admin_participatory_process_proposals.proposal_url(resource, resource.component.mounted_params)
16
+ send(resource.component.mounted_admin_engine).proposal_url(resource, resource.component.mounted_params)
17
17
  end
18
18
 
19
19
  private
@@ -7,6 +7,14 @@ module Decidim
7
7
 
8
8
  i18n_attributes :mentioned_proposal_title
9
9
 
10
+ def safe_resource_translated_text
11
+ resource_text
12
+ end
13
+
14
+ def perform_translation?
15
+ false
16
+ end
17
+
10
18
  private
11
19
 
12
20
  def mentioned_proposal_title
@@ -4,11 +4,37 @@ module Decidim
4
4
  module Proposals
5
5
  class PublishProposalEvent < Decidim::Events::SimpleEvent
6
6
  include Decidim::Events::CoauthorEvent
7
+ include Decidim::Core::Engine.routes.url_helpers
8
+ include ActionView::Helpers::UrlHelper
9
+ include Decidim::Events::MachineTranslatedEvent
7
10
 
8
11
  def resource_text
9
12
  resource.body
10
13
  end
11
14
 
15
+ def i18n_options
16
+ author_path = link_to("@#{author.nickname}", profile_path(author.nickname))
17
+ author_string = "#{author.name} #{author_path}"
18
+ super.merge({ author: author_string })
19
+ end
20
+
21
+ def translatable_resource
22
+ resource
23
+ end
24
+
25
+ def translatable_text
26
+ resource.body
27
+ end
28
+
29
+ def safe_resource_text
30
+ locale = resource.respond_to?(:content_original_language) ? resource.content_original_language : I18n.locale
31
+ I18n.with_locale(locale) { translated_attribute(resource_text).to_s.html_safe }
32
+ end
33
+
34
+ def safe_resource_translated_text
35
+ I18n.with_locale(I18n.locale) { translated_attribute(resource_text, nil, true).to_s.html_safe }
36
+ end
37
+
12
38
  private
13
39
 
14
40
  def i18n_scope
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Proposals
5
+ module Admin
6
+ # A form object to be used when admin users want to import proposals from
7
+ # a file.
8
+ class ProposalsFileImportForm < Decidim::Admin::ImportForm
9
+ attribute :user_group_id, Integer
10
+
11
+ def user_groups
12
+ Decidim::UserGroups::ManageableUserGroups.for(current_user).verified
13
+ end
14
+
15
+ protected
16
+
17
+ def user_group
18
+ @user_group ||= Decidim::UserGroup.find_by(
19
+ organization: current_organization,
20
+ id: user_group_id.to_i
21
+ )
22
+ end
23
+
24
+ def importer_context
25
+ context[:user_group] = user_group
26
+ context
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -30,14 +30,19 @@ module Decidim
30
30
 
31
31
  private
32
32
 
33
+ def errors_set
34
+ @errors_set ||= Set[]
35
+ end
36
+
33
37
  def mergeable_to_same_component
34
38
  return true unless same_component?
35
39
 
36
- public_proposals = proposals.any? do |proposal|
37
- !proposal.official? || proposal.votes.any? || proposal.endorsements.any?
40
+ proposals.each do |proposal|
41
+ errors_set << :not_official unless proposal.official?
42
+ errors_set << :supported if proposal.votes.any? || proposal.endorsements.any?
38
43
  end
39
44
 
40
- errors.add(:proposal_ids, :invalid) if public_proposals
45
+ errors_set.each { |error| errors.add(:base, error) } if errors_set.any?
41
46
  end
42
47
 
43
48
  def same_participatory_space
@@ -102,12 +102,7 @@ module Decidim
102
102
 
103
103
  # If the content is safe, HTML tags are sanitized, otherwise, they are stripped.
104
104
  def render_proposal_body(proposal)
105
- body = present(proposal).body(links: true, strip_tags: !safe_content?)
106
- body = simple_format(body, {}, sanitize: false)
107
-
108
- return body unless safe_content?
109
-
110
- decidim_sanitize(body)
105
+ render_sanitized_content(proposal, :body)
111
106
  end
112
107
 
113
108
  # Returns :text_area or :editor based on the organization' settings.
@@ -19,7 +19,7 @@ module Decidim
19
19
  .slice(:latitude, :longitude, :address)
20
20
  .merge(
21
21
  title: decidim_html_escape(present(proposal).title),
22
- body: html_truncate(decidim_sanitize(present(proposal).body), length: 100),
22
+ body: html_truncate(decidim_sanitize_editor(present(proposal).body), length: 100),
23
23
  icon: icon("proposals", width: 40, height: 70, remove_icon_class: true),
24
24
  link: proposal_path(proposal)
25
25
  )
@@ -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(translated_attribute(@proposal.answer))
10
+ body: decidim_sanitize_editor(translated_attribute(@proposal.answer))
11
11
  }
12
12
  end
13
13
 
@@ -70,12 +70,13 @@ module Decidim
70
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 :sort_by_valuation_assignments_count_asc, lambda {
74
- order("#{sort_by_valuation_assignments_count_nulls_last_query}ASC NULLS FIRST")
75
+ order(Arel.sql("#{sort_by_valuation_assignments_count_nulls_last_query} ASC NULLS FIRST").to_s)
75
76
  }
76
77
 
77
78
  scope :sort_by_valuation_assignments_count_desc, lambda {
78
- order("#{sort_by_valuation_assignments_count_nulls_last_query}DESC NULLS LAST")
79
+ order(Arel.sql("#{sort_by_valuation_assignments_count_nulls_last_query} DESC NULLS LAST").to_s)
79
80
  }
80
81
 
81
82
  def self.with_valuation_assigned_to(user, space)
@@ -8,6 +8,7 @@ $(() => {
8
8
  }
9
9
 
10
10
  let jqxhr = null
11
+ let filterBuffer = ""
11
12
 
12
13
  toggleNoProposals()
13
14
 
@@ -15,15 +16,29 @@ $(() => {
15
16
  const filter = event.target.value.toLowerCase()
16
17
 
17
18
  if (pickerMore) {
19
+ if (filter.length < 3) {
20
+ return
21
+ }
22
+
23
+ if (filter === filterBuffer) {
24
+ return
25
+ }
26
+
18
27
  if (jqxhr !== null) {
19
28
  jqxhr.abort()
20
29
  }
21
30
 
22
31
  $content.html("<div class='loading-spinner'></div>")
23
32
  jqxhr = $.get(`${pickerPath}?q=${filter}`, (data) => {
33
+ filterBuffer = filter
24
34
  $content.html(data)
25
35
  jqxhr = null
26
36
  toggleNoProposals()
37
+
38
+ if (typeof window.theDataPicker === "object" && window.theDataPicker.current !== null) {
39
+ window.theDataPicker._handleCheckboxes($content);
40
+ window.theDataPicker._handleLinks($content);
41
+ }
27
42
  })
28
43
  } else {
29
44
  $("#proposals_list li").each((index, li) => {
@@ -8,6 +8,7 @@ module Decidim
8
8
  class ProposalPresenter < Decidim::ResourcePresenter
9
9
  include Rails.application.routes.mounted_helpers
10
10
  include ActionView::Helpers::UrlHelper
11
+ include Decidim::SanitizeHelper
11
12
 
12
13
  def author
13
14
  @author ||= if official?
@@ -49,15 +50,7 @@ module Decidim
49
50
  def body(links: false, extras: true, strip_tags: false, all_locales: false)
50
51
  return unless proposal
51
52
 
52
- handle_locales(proposal.body, all_locales) do |content|
53
- content = strip_tags(sanitize_text(content)) if strip_tags
54
-
55
- renderer = Decidim::ContentRenderers::HashtagRenderer.new(content)
56
- content = renderer.render(links: links, extras: extras).html_safe
57
-
58
- content = Decidim::ContentRenderers::LinkRenderer.new(content).render if links
59
- content
60
- end
53
+ content_handle_locale(proposal.body, all_locales, extras, links, strip_tags)
61
54
  end
62
55
 
63
56
  # Returns the proposal versions, hiding not published answers
@@ -89,45 +82,6 @@ module Decidim
89
82
  def resource_manifest
90
83
  proposal.class.resource_manifest
91
84
  end
92
-
93
- private
94
-
95
- def sanitize_unordered_lists(text)
96
- text.gsub(%r{(?=.*</ul>)(?!.*?<li>.*?</ol>.*?</ul>)<li>}) { |li| "#{li}• " }
97
- end
98
-
99
- def sanitize_ordered_lists(text)
100
- i = 0
101
-
102
- text.gsub(%r{(?=.*</ol>)(?!.*?<li>.*?</ul>.*?</ol>)<li>}) do |li|
103
- i += 1
104
-
105
- li + "#{i}. "
106
- end
107
- end
108
-
109
- def add_line_feeds_to_paragraphs(text)
110
- text.gsub("</p>") { |p| "#{p}\n\n" }
111
- end
112
-
113
- def add_line_feeds_to_list_items(text)
114
- text.gsub("</li>") { |li| "#{li}\n" }
115
- end
116
-
117
- # Adds line feeds after the paragraph and list item closing tags.
118
- #
119
- # Returns a String.
120
- def add_line_feeds(text)
121
- add_line_feeds_to_paragraphs(add_line_feeds_to_list_items(text))
122
- end
123
-
124
- # Maintains the paragraphs and lists separations with their bullet points and
125
- # list numberings where appropriate.
126
- #
127
- # Returns a String.
128
- def sanitize_text(text)
129
- add_line_feeds(sanitize_ordered_lists(sanitize_unordered_lists(text)))
130
- end
131
85
  end
132
86
  end
133
87
  end
@@ -31,7 +31,7 @@ module Decidim
31
31
  .published
32
32
  .not_hidden
33
33
  .where(
34
- "GREATEST(#{title_similarity}, #{body_similarity}) >= ?",
34
+ Arel.sql("GREATEST(#{title_similarity}, #{body_similarity}) >= ?").to_s,
35
35
  *similarity_params,
36
36
  Decidim::Proposals.similarity_threshold
37
37
  )
@@ -12,8 +12,9 @@ module Decidim
12
12
  # page - The page number to paginate the results.
13
13
  # per_page - The number of proposals to return per page.
14
14
  def initialize(options = {})
15
- base = options[:state]&.member?("withdrawn") ? Proposal.withdrawn : Proposal.except_withdrawn
16
- super(base, options)
15
+ options[:scope] = options.fetch(:scope, Proposal)
16
+ options[:scope] = options[:state_withdraw] == "withdrawn" ? options[:scope].withdrawn : options[:scope].except_withdrawn
17
+ super(options[:scope], options)
17
18
  end
18
19
 
19
20
  # Handle the activity filter
@@ -34,10 +35,14 @@ module Decidim
34
35
  end
35
36
  end
36
37
 
38
+ def search_state_withdraw
39
+ return query if state_withdraw == "withdrawn"
40
+
41
+ query.except_withdrawn
42
+ end
43
+
37
44
  # Handle the state filter
38
45
  def search_state
39
- return query if state.member? "withdrawn"
40
-
41
46
  apply_scopes(%w(accepted rejected evaluating state_not_published), state)
42
47
  end
43
48
 
@@ -0,0 +1,11 @@
1
+ <% if current_organization.user_groups_enabled? && form.object.user_groups.any? %>
2
+ <div class="field">
3
+ <%= form.select(
4
+ :user_group_id,
5
+ form.object.user_groups.map { |g| [g.name, g.id] },
6
+ selected: form.object.user_group_id.presence,
7
+ include_blank: current_user.name,
8
+ label: true
9
+ ) %>
10
+ </div>
11
+ <% end %>
@@ -12,8 +12,13 @@
12
12
 
13
13
  <% if allowed_to? :import, :proposals %>
14
14
  <%= import_dropdown do %>
15
- <% content_tag :li do %>
16
- <% link_to t("actions.import", scope: "decidim.proposals", name: t("models.proposal.name", scope: "decidim.proposals.admin")), new_proposals_import_path %>
15
+ <li class="imports--component imports--proposals">
16
+ <%= link_to t("actions.import", scope: "decidim.proposals", name: t("models.proposal.name", scope: "decidim.proposals.admin")), new_proposals_import_path %>
17
+ </li>
18
+ <% current_component.manifest.import_manifests.each do |import_manifest| %>
19
+ <li class="imports--file imports--<%= import_manifest.name %>">
20
+ <%= link_to import_manifest.message(:label, self), admin_imports_path(current_component, name: import_manifest.name) %>
21
+ </li>
17
22
  <% end %>
18
23
  <% end %>
19
24
  <% end %>
@@ -61,7 +61,7 @@
61
61
  <% end %>
62
62
 
63
63
  <% if component_settings.attachments_allowed? %>
64
- <fieldset>
64
+ <fieldset class="attachments_container">
65
65
  <legend><%= t("attachment_legend", scope: "decidim.proposals.collaborative_drafts.edit") %></legend>
66
66
  <%= form.fields_for :attachment, @form.attachment do |nested_form| %>
67
67
  <div class="field">
@@ -1,13 +1,13 @@
1
1
  <div class="filters-controls hide-for-mediumlarge">
2
- <button data-open="filter-box" class="filters-controls__trigger">
2
+ <button data-open="filter-box" class="filters-controls__trigger" aria-controls="filter-box" aria-haspopup="dialog">
3
3
  <%= t ".filter" %>
4
4
  <%= icon "caret-bottom", class: "icon--small float-right", aria_label: t(".unfold"), role: "img" %>
5
5
  </button>
6
6
  </div>
7
7
 
8
- <div class="reveal" id="filter-box" data-reveal>
8
+ <div class="reveal" id="filter-box" data-reveal role="dialog" aria-modal="true" aria-labelledby="filter-box-label">
9
9
  <div class="reveal__header">
10
- <h3 class="reveal__title"><%= t ".filter_by" %>:</h3>
10
+ <h3 id="filter-box-label" class="reveal__title"><%= t ".filter_by" %>:</h3>
11
11
  <button class="close-button" data-close aria-label="<%= t(".close_modal") %>" type="button">
12
12
  <span aria-hidden="true">&times;</span>
13
13
  </button>
@@ -65,7 +65,7 @@
65
65
  <% end %>
66
66
 
67
67
  <% if component_settings.attachments_allowed? && @proposal %>
68
- <fieldset class="gallery__container">
68
+ <fieldset class="gallery__container photos_container">
69
69
  <legend><%= t("gallery_legend", scope: "decidim.proposals.proposals.edit") %></legend>
70
70
 
71
71
  <% if @form.photos.any? %>
@@ -89,7 +89,7 @@
89
89
  </div>
90
90
  </fieldset>
91
91
 
92
- <fieldset class="gallery__container">
92
+ <fieldset class="attachments_container gallery__container documents_container">
93
93
  <legend><%= t("attachment_legend", scope: "decidim.proposals.proposals.edit") %></legend>
94
94
 
95
95
  <% if @form.documents.any? %>
@@ -14,6 +14,8 @@
14
14
  </div>
15
15
  </div>
16
16
 
17
+ <%= form.hidden_field "state_withdraw", value: params.dig("filter", "state_withdraw") %>
18
+
17
19
  <% if component_settings.proposal_answering_enabled && current_settings.proposal_answering_enabled %>
18
20
  <%= form.check_boxes_tree :state, filter_proposals_state_values, legend_title: t(".state"), "aria-controls": "proposals" %>
19
21
  <% end %>