decidim-proposals 0.25.2 → 0.26.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/proposals/collaborative_draft_m_cell.rb +1 -1
- data/app/cells/decidim/proposals/cost_report_cell.rb +3 -3
- data/app/cells/decidim/proposals/participatory_text_proposal_cell.rb +1 -1
- data/app/cells/decidim/proposals/proposal_m_cell.rb +4 -5
- data/app/cells/decidim/proposals/proposals_picker_cell.rb +7 -5
- data/app/commands/decidim/proposals/update_proposal.rb +3 -2
- data/app/controllers/concerns/decidim/proposals/orderable.rb +21 -8
- data/app/controllers/decidim/proposals/admin/proposals_merges_controller.rb +4 -1
- data/app/controllers/decidim/proposals/admin/proposals_splits_controller.rb +4 -1
- data/app/controllers/decidim/proposals/proposals_controller.rb +2 -2
- data/app/events/decidim/proposals/proposal_mentioned_event.rb +8 -0
- data/app/events/decidim/proposals/publish_proposal_event.rb +26 -0
- data/app/forms/decidim/proposals/admin/proposals_file_import_form.rb +31 -0
- data/app/forms/decidim/proposals/admin/proposals_fork_form.rb +8 -3
- data/app/helpers/decidim/proposals/application_helper.rb +1 -6
- data/app/helpers/decidim/proposals/map_helper.rb +1 -1
- data/app/helpers/decidim/proposals/proposals_helper.rb +1 -1
- data/app/models/decidim/proposals/proposal.rb +3 -2
- data/app/packs/src/decidim/proposals/admin/proposals_picker.js +15 -0
- data/app/presenters/decidim/proposals/proposal_presenter.rb +2 -48
- data/app/queries/decidim/proposals/similar_proposals.rb +1 -1
- data/app/services/decidim/proposals/proposal_search.rb +9 -4
- data/app/views/decidim/proposals/admin/imports/_proposals_fields.html.erb +11 -0
- data/app/views/decidim/proposals/admin/proposals/_bulk-actions.html.erb +7 -2
- data/app/views/decidim/proposals/collaborative_drafts/_edit_form_fields.html.erb +1 -1
- data/app/views/decidim/proposals/collaborative_drafts/_filters_small_view.html.erb +3 -3
- data/app/views/decidim/proposals/proposals/_edit_form_fields.html.erb +2 -2
- data/app/views/decidim/proposals/proposals/_filters.html.erb +2 -0
- data/app/views/decidim/proposals/proposals/_filters_small_view.html.erb +3 -3
- data/app/views/decidim/proposals/proposals/_proposals.html.erb +18 -0
- data/app/views/decidim/proposals/proposals/index.html.erb +0 -5
- data/app/views/decidim/proposals/proposals/participatory_texts/_index.html.erb +2 -2
- data/config/brakeman.ignore +88 -0
- data/config/locales/ar.yml +0 -5
- data/config/locales/bg.yml +0 -2
- data/config/locales/ca.yml +1 -5
- data/config/locales/cs.yml +60 -5
- data/config/locales/de.yml +0 -5
- data/config/locales/el.yml +0 -5
- data/config/locales/en.yml +57 -6
- data/config/locales/es-MX.yml +0 -5
- data/config/locales/es-PY.yml +0 -5
- data/config/locales/es.yml +56 -5
- data/config/locales/eu.yml +38 -5
- data/config/locales/fi-plain.yml +54 -5
- data/config/locales/fi.yml +56 -5
- data/config/locales/fr-CA.yml +55 -5
- data/config/locales/fr.yml +55 -5
- data/config/locales/gl.yml +53 -5
- data/config/locales/hu.yml +0 -5
- data/config/locales/id-ID.yml +0 -4
- data/config/locales/is-IS.yml +0 -2
- data/config/locales/it.yml +13 -5
- data/config/locales/ja.yml +66 -18
- data/config/locales/lv.yml +0 -5
- data/config/locales/nl.yml +57 -5
- data/config/locales/no.yml +0 -5
- data/config/locales/pl.yml +0 -5
- data/config/locales/pt-BR.yml +1 -6
- data/config/locales/pt.yml +37 -5
- data/config/locales/ro-RO.yml +57 -6
- data/config/locales/ru.yml +0 -2
- data/config/locales/sk.yml +0 -5
- data/config/locales/sr-CS.yml +0 -1
- data/config/locales/sv.yml +54 -5
- data/config/locales/tr-TR.yml +0 -5
- data/config/locales/uk.yml +0 -2
- data/config/locales/val-ES.yml +1 -0
- data/config/locales/zh-CN.yml +0 -5
- data/lib/decidim/proposals/component.rb +37 -4
- data/lib/decidim/proposals/import/proposal_answer_creator.rb +95 -0
- data/lib/decidim/proposals/import/proposal_creator.rb +124 -0
- data/lib/decidim/proposals/import/proposals_answers_verifier.rb +29 -0
- data/lib/decidim/proposals/import/proposals_verifier.rb +16 -0
- data/lib/decidim/proposals/import.rb +12 -0
- data/lib/decidim/proposals/proposal_serializer.rb +6 -3
- data/lib/decidim/proposals/test/factories.rb +1 -9
- data/lib/decidim/proposals/version.rb +1 -1
- data/lib/decidim/proposals.rb +1 -1
- metadata +32 -24
- data/lib/decidim/proposals/proposal_creator.rb +0 -98
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8de38df4a849390c5b32f623bcb64dd19a8b7a2c0b5288cede2039427f56573f
|
4
|
+
data.tar.gz: 9eb48ff93ba9103e5333597021ce93473e27d1991615093e78990de9449dae9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed5bf7b607c3e1bc2aa24bbf4cf4cd520c03b225820d2e686d7753592f75ded0b7b18fc2dff65a1f7a2d86cd75c19e87544eacb5e7c57fd68e163f30a6030945
|
7
|
+
data.tar.gz: dafd27dba1795532f61bce6a956d6b552d0a024949b5dfb9bf01ac4d36b6e1531e861ea16f342c821123afcd4482b46b0593c2ddba6f5f9a8bd9934308050458
|
@@ -18,7 +18,7 @@ module Decidim
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def cost_report
|
21
|
-
|
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
|
-
|
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
|
-
|
38
|
+
decidim_sanitize_editor(translated_attribute(model.execution_period).html_safe)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -25,7 +25,7 @@ module Decidim
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def body
|
28
|
-
|
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.
|
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.
|
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
|
-
|
54
|
-
|
55
|
-
.or(proposals.where("
|
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,9 @@ module Decidim
|
|
60
61
|
|
61
62
|
def proposals
|
62
63
|
@proposals ||= Decidim.find_resource_manifest(:proposals).try(:resource_scope, component)
|
63
|
-
|
64
|
-
|
64
|
+
&.includes(:component)
|
65
|
+
&.published
|
66
|
+
&.order(id: :asc)
|
65
67
|
end
|
66
68
|
|
67
69
|
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 ||=
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
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[:
|
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
|
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
|
@@ -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
|
-
|
37
|
-
|
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(:
|
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
|
-
|
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(
|
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
|
)
|
@@ -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
|
-
|
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
|
-
|
16
|
-
|
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
|
-
|
16
|
-
|
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">×</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 %>
|
@@ -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">×</span>
|
13
13
|
</button>
|