decidim-proposals 0.16.0 → 0.16.1
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/participatory_text_proposal_cell.rb +3 -1
- data/app/cells/decidim/proposals/proposal_activity_cell.rb +9 -1
- data/app/commands/decidim/proposals/admin/discard_participatory_text.rb +40 -0
- data/app/commands/decidim/proposals/admin/import_participatory_text.rb +5 -1
- data/app/commands/decidim/proposals/admin/publish_participatory_text.rb +6 -18
- data/app/commands/decidim/proposals/admin/update_participatory_text.rb +56 -0
- data/app/commands/decidim/proposals/create_proposal.rb +21 -22
- data/app/commands/decidim/proposals/publish_collaborative_draft.rb +1 -0
- data/app/commands/decidim/proposals/publish_proposal.rb +25 -3
- data/app/commands/decidim/proposals/update_proposal.rb +19 -23
- data/app/controllers/concerns/decidim/proposals/orderable.rb +1 -1
- data/app/controllers/decidim/proposals/admin/participatory_texts_controller.rb +46 -14
- data/app/forms/decidim/proposals/admin/import_participatory_text_form.rb +1 -2
- data/app/forms/decidim/proposals/admin/proposal_form.rb +1 -1
- data/app/helpers/decidim/proposals/application_helper.rb +0 -4
- data/app/permissions/decidim/proposals/admin/permissions.rb +2 -4
- data/app/views/decidim/proposals/admin/participatory_texts/_article-preview.html.erb +1 -1
- data/app/views/decidim/proposals/admin/participatory_texts/_bulk-actions.html.erb +1 -0
- data/app/views/decidim/proposals/admin/participatory_texts/index.html.erb +8 -5
- data/app/views/decidim/proposals/proposals/show.html.erb +9 -0
- data/config/locales/ar-SA.yml +667 -0
- data/config/locales/ca.yml +28 -21
- data/config/locales/cs-CZ.yml +775 -0
- data/config/locales/de.yml +7 -0
- data/config/locales/en.yml +7 -0
- data/config/locales/es-MX.yml +751 -0
- data/config/locales/es-PY.yml +7 -0
- data/config/locales/es.yml +21 -14
- data/config/locales/eu.yml +10 -3
- data/config/locales/fi-pl.yml +8 -1
- data/config/locales/fi.yml +11 -4
- data/config/locales/fr.yml +7 -0
- data/config/locales/gl.yml +7 -0
- data/config/locales/hu.yml +21 -14
- data/config/locales/id-ID.yml +7 -0
- data/config/locales/it.yml +8 -1
- data/config/locales/nl.yml +10 -3
- data/config/locales/pl.yml +8 -1
- data/config/locales/pt-BR.yml +7 -0
- data/config/locales/pt.yml +7 -0
- data/config/locales/ru.yml +6 -0
- data/config/locales/sv.yml +7 -0
- data/config/locales/tr-TR.yml +8 -0
- data/config/locales/uk.yml +6 -0
- data/db/migrate/20190215113158_use_md5_indexes.rb +17 -0
- data/lib/decidim/content_parsers/proposal_parser.rb +2 -2
- data/lib/decidim/proposals/admin_engine.rb +4 -2
- data/lib/decidim/proposals/markdown_to_proposals.rb +49 -4
- data/lib/decidim/proposals/proposal_serializer.rb +3 -2
- data/lib/decidim/proposals/version.rb +1 -1
- metadata +26 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f545c292413c69159509938ffa3e0a7a442eaec96770e465b405d709ab0db976
|
4
|
+
data.tar.gz: 90b940f6ce3c968772548d40a04a7c47d7491c340c2a407b78a6013ccdf903c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e12c387014c567aee0ca73e133357c74621e49dcd49b305ecda4bac2e231e215273d15b30a7d3e0e61772ba6dea2163b3baaf459781aa4a595ba100dcefcf086
|
7
|
+
data.tar.gz: 7dde2bc4a1920813acf8fee2bde644f1d7b80b58c056bab12f720ff2df246e376b401e83418d6a51475ba4190e1147f3beadb651a6be12bf90216fc38e5b5c3c
|
@@ -10,6 +10,7 @@ module Decidim
|
|
10
10
|
include ProposalCellsHelper
|
11
11
|
include Cell::ViewModel::Partial
|
12
12
|
include Messaging::ConversationHelper
|
13
|
+
include Decidim::SanitizeHelper
|
13
14
|
|
14
15
|
delegate :current_organization, to: :controller
|
15
16
|
|
@@ -30,7 +31,8 @@ module Decidim
|
|
30
31
|
|
31
32
|
def body
|
32
33
|
return unless model.participatory_text_level == "article"
|
33
|
-
present(model).body
|
34
|
+
formatted = simple_format(present(model).body)
|
35
|
+
decidim_sanitize(strip_links(formatted))
|
34
36
|
end
|
35
37
|
|
36
38
|
def current_user
|
@@ -12,7 +12,15 @@ module Decidim
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def resource_link_text
|
15
|
-
|
15
|
+
presenter.title
|
16
|
+
end
|
17
|
+
|
18
|
+
def description
|
19
|
+
presenter.body(links: true)
|
20
|
+
end
|
21
|
+
|
22
|
+
def presenter
|
23
|
+
@presenter ||= Decidim::Proposals::ProposalPresenter.new(resource)
|
16
24
|
end
|
17
25
|
end
|
18
26
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
module Admin
|
6
|
+
# A command with all the business logic related with an admin discarding participatory text proposals.
|
7
|
+
class DiscardParticipatoryText < Rectify::Command
|
8
|
+
# Public: Initializes the command.
|
9
|
+
#
|
10
|
+
# form - A PreviewParticipatoryTextForm form object with the params.
|
11
|
+
def initialize(component)
|
12
|
+
@component = component
|
13
|
+
end
|
14
|
+
|
15
|
+
# Executes the command. Broadcasts these events:
|
16
|
+
#
|
17
|
+
# - :ok when everything is valid.
|
18
|
+
# - :invalid if the form wasn't valid and we couldn't proceed.
|
19
|
+
#
|
20
|
+
# Returns nothing.
|
21
|
+
def call
|
22
|
+
transaction do
|
23
|
+
discard_drafts
|
24
|
+
end
|
25
|
+
|
26
|
+
broadcast(:ok)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :form
|
32
|
+
|
33
|
+
def discard_drafts
|
34
|
+
proposals = Decidim::Proposals::Proposal.drafts.where(component: @component)
|
35
|
+
proposals.destroy_all
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -39,7 +39,11 @@ module Decidim
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def parse_participatory_text_doc(form)
|
42
|
-
|
42
|
+
return if form.document.blank?
|
43
|
+
|
44
|
+
document = form.document_text
|
45
|
+
document = Decidim::IoEncoder.to_standard_encoding(document)
|
46
|
+
markdown = DocToMarkdown.new(document, form.document_type).to_md
|
43
47
|
parser = MarkdownToProposals.new(form.current_component, form.current_user)
|
44
48
|
parser.parse(markdown)
|
45
49
|
end
|
@@ -5,7 +5,7 @@ module Decidim
|
|
5
5
|
module Admin
|
6
6
|
# A command with all the business logic when an admin imports proposals from
|
7
7
|
# a participatory text.
|
8
|
-
class PublishParticipatoryText <
|
8
|
+
class PublishParticipatoryText < UpdateParticipatoryText
|
9
9
|
# Public: Initializes the command.
|
10
10
|
#
|
11
11
|
# form - A PreviewParticipatoryTextForm form object with the params.
|
@@ -21,13 +21,13 @@ module Decidim
|
|
21
21
|
# Returns nothing.
|
22
22
|
def call
|
23
23
|
transaction do
|
24
|
-
@
|
24
|
+
@failures = {}
|
25
25
|
update_contents_and_resort_proposals(form)
|
26
26
|
publish_drafts
|
27
27
|
end
|
28
28
|
|
29
|
-
if @
|
30
|
-
broadcast(:invalid, @
|
29
|
+
if @failures.any?
|
30
|
+
broadcast(:invalid, @failures)
|
31
31
|
else
|
32
32
|
broadcast(:ok)
|
33
33
|
end
|
@@ -37,27 +37,15 @@ module Decidim
|
|
37
37
|
|
38
38
|
attr_reader :form
|
39
39
|
|
40
|
-
def update_contents_and_resort_proposals(form)
|
41
|
-
form.proposals.each do |prop_form|
|
42
|
-
proposal = Decidim::Proposals::Proposal.where(component: form.current_component).find(prop_form.id)
|
43
|
-
proposal.set_list_position(prop_form.position) if proposal.position != prop_form.position
|
44
|
-
proposal.title = prop_form.title
|
45
|
-
proposal.body = prop_form.body if proposal.participatory_text_level == Decidim::Proposals::ParticipatoryTextSection::LEVELS[:article]
|
46
|
-
|
47
|
-
add_failure(proposal) unless proposal.save
|
48
|
-
end
|
49
|
-
raise ActiveRecord::Rollback if @publish_failures.any?
|
50
|
-
end
|
51
|
-
|
52
40
|
def publish_drafts
|
53
41
|
Decidim::Proposals::Proposal.where(component: form.current_component).drafts.find_each do |proposal|
|
54
42
|
add_failure(proposal) unless proposal.update(published_at: Time.current)
|
55
43
|
end
|
56
|
-
raise ActiveRecord::Rollback if @
|
44
|
+
raise ActiveRecord::Rollback if @failures.any?
|
57
45
|
end
|
58
46
|
|
59
47
|
def add_failure(proposal)
|
60
|
-
@
|
48
|
+
@failures[proposal.id] = proposal.errors.full_messages
|
61
49
|
end
|
62
50
|
end
|
63
51
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Proposals
|
5
|
+
module Admin
|
6
|
+
# A command with all the business logic when an admin updates participatory text proposals.
|
7
|
+
class UpdateParticipatoryText < Rectify::Command
|
8
|
+
# Public: Initializes the command.
|
9
|
+
#
|
10
|
+
# form - A PreviewParticipatoryTextForm form object with the params.
|
11
|
+
def initialize(form)
|
12
|
+
@form = form
|
13
|
+
end
|
14
|
+
|
15
|
+
# Executes the command. Broadcasts these events:
|
16
|
+
#
|
17
|
+
# - :ok when everything is valid.
|
18
|
+
# - :invalid if the form wasn't valid and we couldn't proceed.
|
19
|
+
#
|
20
|
+
# Returns nothing.
|
21
|
+
def call
|
22
|
+
transaction do
|
23
|
+
@failures = {}
|
24
|
+
update_contents_and_resort_proposals(form)
|
25
|
+
end
|
26
|
+
|
27
|
+
if @failures.any?
|
28
|
+
broadcast(:invalid, @failures)
|
29
|
+
else
|
30
|
+
broadcast(:ok)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :form
|
37
|
+
|
38
|
+
def update_contents_and_resort_proposals(form)
|
39
|
+
form.proposals.each do |prop_form|
|
40
|
+
proposal = Decidim::Proposals::Proposal.where(component: form.current_component).find(prop_form.id)
|
41
|
+
proposal.set_list_position(prop_form.position) if proposal.position != prop_form.position
|
42
|
+
proposal.title = prop_form.title
|
43
|
+
proposal.body = prop_form.body if proposal.participatory_text_level == Decidim::Proposals::ParticipatoryTextSection::LEVELS[:article]
|
44
|
+
|
45
|
+
add_failure(proposal) unless proposal.save
|
46
|
+
end
|
47
|
+
raise ActiveRecord::Rollback if @failures.any?
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_failure(proposal)
|
51
|
+
@failures[proposal.id] = proposal.errors.full_messages
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -43,29 +43,28 @@ module Decidim
|
|
43
43
|
|
44
44
|
attr_reader :form, :proposal, :attachment
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
fields[:component] = form.component
|
52
|
-
|
53
|
-
fields
|
54
|
-
end
|
55
|
-
|
56
|
-
# This will be the PaperTrail version that is
|
57
|
-
# shown in the version control feature (1 of 1)
|
46
|
+
# Prevent PaperTrail from creating an additional version
|
47
|
+
# in the proposal multi-step creation process (step 1: create)
|
48
|
+
#
|
49
|
+
# A first version will be created in step 4: publish
|
50
|
+
# for diff rendering in the proposal version control
|
58
51
|
def create_proposal
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
52
|
+
PaperTrail.request(enabled: false) do
|
53
|
+
@proposal = Decidim.traceability.perform_action!(
|
54
|
+
:create,
|
55
|
+
Decidim::Proposals::Proposal,
|
56
|
+
@current_user,
|
57
|
+
visibility: "public-only"
|
58
|
+
) do
|
59
|
+
proposal = Proposal.new(
|
60
|
+
title: title_with_hashtags,
|
61
|
+
body: body_with_hashtags,
|
62
|
+
component: form.component
|
63
|
+
)
|
64
|
+
proposal.add_coauthor(@current_user, user_group: user_group)
|
65
|
+
proposal.save!
|
66
|
+
proposal
|
67
|
+
end
|
69
68
|
end
|
70
69
|
end
|
71
70
|
|
@@ -79,6 +79,7 @@ module Decidim
|
|
79
79
|
new_proposal = Proposal.new(proposal_attributes)
|
80
80
|
new_proposal.coauthorships = @collaborative_draft.coauthorships
|
81
81
|
new_proposal.category = @collaborative_draft.category
|
82
|
+
new_proposal.attachments = @collaborative_draft.attachments
|
82
83
|
new_proposal.save!
|
83
84
|
new_proposal
|
84
85
|
end
|
@@ -34,12 +34,34 @@ module Decidim
|
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
-
#
|
38
|
-
# in the
|
37
|
+
# This will be the PaperTrail version that is
|
38
|
+
# shown in the version control feature (1 of 1)
|
39
|
+
#
|
40
|
+
# For an attribute to appear in the new version it has to be reset
|
41
|
+
# and reassigned, as PaperTrail only keeps track of object CHANGES.
|
39
42
|
def publish_proposal
|
43
|
+
title = reset(:title)
|
44
|
+
body = reset(:body)
|
45
|
+
|
46
|
+
Decidim.traceability.perform_action!(
|
47
|
+
"publish",
|
48
|
+
@proposal,
|
49
|
+
@current_user,
|
50
|
+
visibility: "public-only"
|
51
|
+
) do
|
52
|
+
@proposal.update title: title, body: body, published_at: Time.current
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Reset the attribute to an empty string and return the old value
|
57
|
+
def reset(attribute)
|
58
|
+
attribute_value = @proposal[attribute]
|
40
59
|
PaperTrail.request(enabled: false) do
|
41
|
-
|
60
|
+
# rubocop:disable Rails/SkipsModelValidations
|
61
|
+
@proposal.update_attribute attribute, ""
|
62
|
+
# rubocop:enable Rails/SkipsModelValidations
|
42
63
|
end
|
64
|
+
attribute_value
|
43
65
|
end
|
44
66
|
|
45
67
|
def send_notification
|
@@ -53,41 +53,37 @@ module Decidim
|
|
53
53
|
|
54
54
|
attr_reader :form, :proposal, :current_user, :attachment
|
55
55
|
|
56
|
-
def proposal_attributes
|
57
|
-
fields = {}
|
58
|
-
|
59
|
-
fields[:title] = title_with_hashtags
|
60
|
-
fields[:body] = body_with_hashtags
|
61
|
-
fields[:category] = form.category
|
62
|
-
fields[:scope] = form.scope
|
63
|
-
fields[:address] = form.address
|
64
|
-
fields[:latitude] = form.latitude
|
65
|
-
fields[:longitude] = form.longitude
|
66
|
-
|
67
|
-
fields
|
68
|
-
end
|
69
|
-
|
70
56
|
# Prevent PaperTrail from creating an additional version
|
71
57
|
# in the proposal multi-step creation process (step 3: complete)
|
58
|
+
#
|
59
|
+
# A first version will be created in step 4: publish
|
60
|
+
# for diff rendering in the proposal control version
|
72
61
|
def update_draft
|
73
62
|
PaperTrail.request(enabled: false) do
|
74
|
-
@proposal.update(
|
63
|
+
@proposal.update(attributes)
|
75
64
|
@proposal.coauthorships.clear
|
76
65
|
@proposal.add_coauthor(current_user, user_group: user_group)
|
77
66
|
end
|
78
67
|
end
|
79
68
|
|
80
69
|
def update_proposal
|
81
|
-
@proposal
|
82
|
-
@proposal,
|
83
|
-
current_user,
|
84
|
-
proposal_attributes,
|
85
|
-
visibility: "public-only"
|
86
|
-
)
|
70
|
+
@proposal.update!(attributes)
|
87
71
|
@proposal.coauthorships.clear
|
88
72
|
@proposal.add_coauthor(current_user, user_group: user_group)
|
89
73
|
end
|
90
74
|
|
75
|
+
def attributes
|
76
|
+
{
|
77
|
+
title: title_with_hashtags,
|
78
|
+
body: body_with_hashtags,
|
79
|
+
category: form.category,
|
80
|
+
scope: form.scope,
|
81
|
+
address: form.address,
|
82
|
+
latitude: form.latitude,
|
83
|
+
longitude: form.longitude
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
91
87
|
def proposal_limit_reached?
|
92
88
|
proposal_limit = form.current_component.settings.proposal_limit
|
93
89
|
|
@@ -109,11 +105,11 @@ module Decidim
|
|
109
105
|
end
|
110
106
|
|
111
107
|
def current_user_proposals
|
112
|
-
Proposal.from_author(current_user).where(component: form.current_component).published.where.not(id: proposal.id)
|
108
|
+
Proposal.from_author(current_user).where(component: form.current_component).published.where.not(id: proposal.id).except_withdrawn
|
113
109
|
end
|
114
110
|
|
115
111
|
def user_group_proposals
|
116
|
-
Proposal.from_user_group(user_group).where(component: form.current_component).published.where.not(id: proposal.id)
|
112
|
+
Proposal.from_user_group(user_group).where(component: form.current_component).published.where.not(id: proposal.id).except_withdrawn
|
117
113
|
end
|
118
114
|
end
|
119
115
|
end
|
@@ -15,13 +15,13 @@ module Decidim
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def new_import
|
18
|
-
enforce_permission_to :
|
18
|
+
enforce_permission_to :manage, :participatory_texts
|
19
19
|
participatory_text = Decidim::Proposals::ParticipatoryText.find_by(component: current_component)
|
20
20
|
@import = form(Admin::ImportParticipatoryTextForm).from_model(participatory_text)
|
21
21
|
end
|
22
22
|
|
23
23
|
def import
|
24
|
-
enforce_permission_to :
|
24
|
+
enforce_permission_to :manage, :participatory_texts
|
25
25
|
@import = form(Admin::ImportParticipatoryTextForm).from_params(params)
|
26
26
|
|
27
27
|
Admin::ImportParticipatoryText.call(@import) do
|
@@ -37,23 +37,55 @@ module Decidim
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
# When `save_draft` param exists, proposals are only saved.
|
41
|
+
# When no `save_draft` param is set, proposals are saved and published.
|
42
|
+
def update
|
43
|
+
enforce_permission_to :manage, :participatory_texts
|
44
|
+
|
42
45
|
form_params = params.require(:preview_participatory_text).permit!
|
43
46
|
@preview_form = form(Admin::PreviewParticipatoryTextForm).from_params(proposals: form_params[:proposals_attributes]&.values)
|
44
47
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
if params.has_key?("save_draft")
|
49
|
+
UpdateParticipatoryText.call(@preview_form) do
|
50
|
+
on(:ok) do
|
51
|
+
flash[:notice] = I18n.t("participatory_texts.update.success", scope: "decidim.proposals.admin")
|
52
|
+
redirect_to participatory_texts_path(component_id: current_component.id, initiative_slug: "asdf")
|
53
|
+
end
|
54
|
+
|
55
|
+
on(:invalid) do |failures|
|
56
|
+
alert_msg = [I18n.t("participatory_texts.publish.invalid", scope: "decidim.proposals.admin")]
|
57
|
+
failures.each_pair { |id, msg| alert_msg << "ID:[#{id}] #{msg}" }
|
58
|
+
flash.now[:alert] = alert_msg.join("<br/>").html_safe
|
59
|
+
index
|
60
|
+
render action: "index"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
else
|
64
|
+
PublishParticipatoryText.call(@preview_form) do
|
65
|
+
on(:ok) do
|
66
|
+
flash[:notice] = I18n.t("participatory_texts.publish.success", scope: "decidim.proposals.admin")
|
67
|
+
redirect_to proposals_path
|
68
|
+
end
|
69
|
+
|
70
|
+
on(:invalid) do |failures|
|
71
|
+
alert_msg = [I18n.t("participatory_texts.publish.invalid", scope: "decidim.proposals.admin")]
|
72
|
+
failures.each_pair { |id, msg| alert_msg << "ID:[#{id}] #{msg}" }
|
73
|
+
flash.now[:alert] = alert_msg.join("<br/>").html_safe
|
74
|
+
index
|
75
|
+
render action: "index"
|
76
|
+
end
|
49
77
|
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Removes all the unpublished proposals (drafts).
|
82
|
+
def discard
|
83
|
+
enforce_permission_to :manage, :participatory_texts
|
50
84
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
index
|
56
|
-
render action: "index"
|
85
|
+
DiscardParticipatoryText.call(current_component) do
|
86
|
+
on(:ok) do
|
87
|
+
flash[:notice] = I18n.t("participatory_texts.discard.success", scope: "decidim.proposals.admin")
|
88
|
+
redirect_to participatory_texts_path(component_id: current_component.id, initiative_slug: "asdf")
|
57
89
|
end
|
58
90
|
end
|
59
91
|
end
|