decidim-elections 0.22.0 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/config/decidim_elections_manifest.js +2 -0
- data/app/assets/javascripts/decidim/elections/vote.js.es6 +170 -0
- data/app/assets/stylesheets/decidim/elections/elections.scss +10 -0
- data/app/assets/stylesheets/decidim/elections/focus/_evote.scss +279 -0
- data/app/assets/stylesheets/decidim/elections/focus/_focus.scss +128 -0
- data/app/cells/decidim/elections/election_cell.rb +22 -0
- data/app/cells/decidim/elections/election_m/data.erb +19 -0
- data/app/cells/decidim/elections/election_m/footer.erb +5 -0
- data/app/cells/decidim/elections/election_m_cell.rb +103 -0
- data/app/cells/decidim/elections/voting_step_navigation/show.erb +29 -0
- data/app/cells/decidim/elections/voting_step_navigation_cell.rb +42 -0
- data/app/commands/decidim/elections/admin/create_election.rb +14 -3
- data/app/commands/decidim/elections/admin/create_question.rb +2 -1
- data/app/commands/decidim/elections/admin/destroy_election.rb +4 -0
- data/app/commands/decidim/elections/admin/import_proposals_to_elections.rb +87 -0
- data/app/commands/decidim/elections/admin/publish_election.rb +54 -0
- data/app/commands/decidim/elections/admin/unpublish_election.rb +43 -0
- data/app/commands/decidim/elections/admin/update_election.rb +15 -3
- data/app/commands/decidim/elections/admin/update_question.rb +2 -1
- data/app/controllers/concerns/decidim/elections/orderable.rb +36 -0
- data/app/controllers/decidim/elections/admin/answers_controller.rb +9 -1
- data/app/controllers/decidim/elections/admin/elections_controller.rb +26 -0
- data/app/controllers/decidim/elections/admin/proposals_imports_controller.rb +53 -0
- data/app/controllers/decidim/elections/elections_controller.rb +68 -0
- data/app/controllers/decidim/elections/votes_controller.rb +50 -0
- data/app/events/decidim/elections/election_published_event.rb +8 -0
- data/app/forms/decidim/elections/admin/answer_import_proposals_form.rb +41 -0
- data/app/forms/decidim/elections/admin/election_form.rb +15 -2
- data/app/forms/decidim/elections/admin/question_form.rb +1 -0
- data/app/helpers/decidim/elections/application_helper.rb +12 -0
- data/app/helpers/decidim/elections/election_cells_helper.rb +12 -0
- data/app/helpers/decidim/elections/votes_helper.rb +21 -0
- data/app/models/decidim/elections/answer.rb +5 -1
- data/app/models/decidim/elections/election.rb +69 -0
- data/app/models/decidim/elections/question.rb +9 -2
- data/app/permissions/decidim/elections/admin/permissions.rb +13 -3
- data/app/permissions/decidim/elections/permissions.rb +35 -0
- data/app/presenters/decidim/elections/admin_log/election_presenter.rb +41 -0
- data/app/presenters/decidim/elections/election_presenter.rb +28 -0
- data/app/queries/decidim/elections/filtered_elections.rb +37 -0
- data/app/services/decidim/elections/election_search.rb +35 -0
- data/app/types/decidim/elections/election_question_type.rb +2 -2
- data/app/types/decidim/elections/election_type.rb +2 -1
- data/app/types/decidim/elections/elections_type.rb +1 -1
- data/app/views/decidim/elections/admin/answers/index.html.erb +2 -1
- data/app/views/decidim/elections/admin/elections/_form.html.erb +2 -4
- data/app/views/decidim/elections/admin/elections/index.html.erb +23 -1
- data/app/views/decidim/elections/admin/proposals_imports/new.html.erb +24 -0
- data/app/views/decidim/elections/admin/questions/_form.html.erb +4 -0
- data/app/views/decidim/elections/admin/questions/index.html.erb +3 -1
- data/app/views/decidim/elections/elections/_count.html.erb +1 -0
- data/app/views/decidim/elections/elections/_election.html.erb +1 -0
- data/app/views/decidim/elections/elections/_elections.html.erb +24 -0
- data/app/views/decidim/elections/elections/_filters.html.erb +24 -0
- data/app/views/decidim/elections/elections/_filters_small_view.html.erb +18 -0
- data/app/views/decidim/elections/elections/index.html.erb +24 -0
- data/app/views/decidim/elections/elections/index.js.erb +10 -0
- data/app/views/decidim/elections/elections/show.html.erb +62 -0
- data/app/views/decidim/elections/votes/_election_votes_confirm.html.erb +53 -0
- data/app/views/decidim/elections/votes/_election_votes_confirm_footer.html.erb +24 -0
- data/app/views/decidim/elections/votes/_election_votes_confirmed.html.erb +26 -0
- data/app/views/decidim/elections/votes/_election_votes_encrypting.html.erb +20 -0
- data/app/views/decidim/elections/votes/_election_votes_header.html.erb +8 -0
- data/app/views/decidim/elections/votes/_election_votes_modal.html.erb +46 -0
- data/app/views/decidim/elections/votes/_election_votes_question.html.erb +49 -0
- data/app/views/decidim/elections/votes/_election_votes_steps_header.html.erb +12 -0
- data/app/views/decidim/elections/votes/new.html.erb +44 -0
- data/app/views/layouts/decidim/_election_votes_header.html.erb +13 -0
- data/app/views/layouts/decidim/election_votes.html.erb +24 -0
- data/config/locales/am-ET.yml +1 -0
- data/config/locales/bg.yml +7 -0
- data/config/locales/ca.yml +136 -6
- data/config/locales/cs.yml +133 -1
- data/config/locales/da.yml +1 -0
- data/config/locales/de.yml +93 -1
- data/config/locales/el.yml +11 -1
- data/config/locales/en.yml +131 -1
- data/config/locales/eo.yml +1 -0
- data/config/locales/es-MX.yml +131 -1
- data/config/locales/es-PY.yml +131 -1
- data/config/locales/es.yml +134 -4
- data/config/locales/et.yml +1 -0
- data/config/locales/fi-plain.yml +131 -1
- data/config/locales/fi.yml +131 -1
- data/config/locales/fr-CA.yml +131 -1
- data/config/locales/fr.yml +131 -1
- data/config/locales/hr.yml +1 -0
- data/config/locales/hu.yml +18 -0
- data/config/locales/is.yml +1 -0
- data/config/locales/it.yml +88 -1
- data/config/locales/ja-JP.yml +95 -8
- data/config/locales/ja.yml +254 -0
- data/config/locales/ko-KR.yml +1 -0
- data/config/locales/ko.yml +1 -0
- data/config/locales/lt.yml +1 -0
- data/config/locales/{lv-LV.yml → lv.yml} +11 -1
- data/config/locales/mt.yml +1 -0
- data/config/locales/nl.yml +88 -1
- data/config/locales/no.yml +64 -0
- data/config/locales/om-ET.yml +1 -0
- data/config/locales/pl.yml +124 -1
- data/config/locales/pt.yml +84 -1
- data/config/locales/ro-RO.yml +85 -1
- data/config/locales/so-SO.yml +1 -0
- data/config/locales/sv.yml +121 -1
- data/config/locales/ti-ER.yml +1 -0
- data/config/locales/vi-VN.yml +1 -0
- data/config/locales/vi.yml +1 -0
- data/config/locales/zh-CN.yml +254 -0
- data/config/locales/zh-TW.yml +1 -0
- data/db/migrate/20200601141412_add_published_at_to_elections.rb +7 -0
- data/db/migrate/20200807125040_remove_subtitle_from_decidim_elections.rb +7 -0
- data/db/migrate/20200910103648_add_min_selections_to_decidim_elections_questions.rb +7 -0
- data/lib/decidim/elections.rb +5 -0
- data/lib/decidim/elections/admin_engine.rb +7 -0
- data/lib/decidim/elections/bulletin_board_client.rb +35 -0
- data/lib/decidim/elections/component.rb +17 -12
- data/lib/decidim/elections/engine.rb +8 -1
- data/lib/decidim/elections/test/factories.rb +59 -6
- data/lib/decidim/elections/version.rb +1 -1
- data/lib/tasks/decidim_elections.rake +16 -0
- metadata +79 -13
@@ -0,0 +1,128 @@
|
|
1
|
+
.focus{
|
2
|
+
$top-padding: .5rem;
|
3
|
+
|
4
|
+
display: flex;
|
5
|
+
flex-direction: column;
|
6
|
+
min-height: 100vh;
|
7
|
+
background-color: $light-gray;
|
8
|
+
|
9
|
+
&__top{
|
10
|
+
padding: $top-padding 1rem;
|
11
|
+
background-color: $white;
|
12
|
+
position: sticky;
|
13
|
+
top: 0;
|
14
|
+
z-index: 1;
|
15
|
+
display: flex;
|
16
|
+
}
|
17
|
+
|
18
|
+
&__top_warning{
|
19
|
+
background: $alert;
|
20
|
+
color: white;
|
21
|
+
text-align: center;
|
22
|
+
display: block;
|
23
|
+
padding: 2px 0;
|
24
|
+
}
|
25
|
+
|
26
|
+
&__brand{
|
27
|
+
display: flex;
|
28
|
+
align-items: center;
|
29
|
+
|
30
|
+
img{
|
31
|
+
max-height: 20px;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
&__user{
|
36
|
+
margin: 0 15px 0 auto;
|
37
|
+
padding-right: 0;
|
38
|
+
display: flex;
|
39
|
+
align-items: center;
|
40
|
+
}
|
41
|
+
|
42
|
+
&__exit{
|
43
|
+
display: flex;
|
44
|
+
align-items: center;
|
45
|
+
line-height: 1;
|
46
|
+
margin: -$top-padding 0;
|
47
|
+
padding: .5rem .25rem .5rem 1rem;
|
48
|
+
border-left: 1px solid rgba(black, .2);
|
49
|
+
}
|
50
|
+
|
51
|
+
&__x-icon{
|
52
|
+
font-size: 2rem;
|
53
|
+
margin-right: .5rem;
|
54
|
+
color: $muted;
|
55
|
+
|
56
|
+
a:hover &{
|
57
|
+
color: inherit;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
&__header{
|
62
|
+
background-color: $dark-gray;
|
63
|
+
color: $white;
|
64
|
+
padding: 1rem;
|
65
|
+
|
66
|
+
&-title{
|
67
|
+
margin-bottom: 0;
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
&__step{
|
72
|
+
display: flex;
|
73
|
+
flex-direction: column;
|
74
|
+
flex-grow: 1;
|
75
|
+
}
|
76
|
+
|
77
|
+
&__steps{
|
78
|
+
text-transform: uppercase;
|
79
|
+
font-size: 80%;
|
80
|
+
letter-spacing: .05em;
|
81
|
+
color: $light-gray;
|
82
|
+
}
|
83
|
+
|
84
|
+
&__content{
|
85
|
+
flex-grow: 1;
|
86
|
+
display: flex;
|
87
|
+
|
88
|
+
.row{
|
89
|
+
flex-grow: 1;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
&__footer{
|
94
|
+
margin-top: auto;
|
95
|
+
padding: 1rem;
|
96
|
+
background-color: $white;
|
97
|
+
|
98
|
+
.row{
|
99
|
+
display: flex;
|
100
|
+
align-items: baseline;
|
101
|
+
width: 100%;
|
102
|
+
}
|
103
|
+
|
104
|
+
.button{
|
105
|
+
margin-bottom: 0;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
&__back{
|
110
|
+
font-weight: 600;
|
111
|
+
|
112
|
+
svg{
|
113
|
+
font-size: .7em;
|
114
|
+
margin-right: .3em;
|
115
|
+
vertical-align: 0;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
&__next{
|
120
|
+
margin-left: auto;
|
121
|
+
|
122
|
+
svg{
|
123
|
+
font-size: .7em;
|
124
|
+
margin-left: .3em;
|
125
|
+
vertical-align: 0;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Elections
|
5
|
+
# This cell renders the election card for an instance of an election
|
6
|
+
# the default size is the Medium Card (:m)
|
7
|
+
class ElectionCell < Decidim::ViewModel
|
8
|
+
include ElectionCellsHelper
|
9
|
+
include Cell::ViewModel::Partial
|
10
|
+
|
11
|
+
def show
|
12
|
+
cell card_size, model, options
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def card_size
|
18
|
+
"decidim/elections/election_m"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<div class="card__icondata">
|
2
|
+
<ul class="card-data">
|
3
|
+
<li class="card-data__item">
|
4
|
+
<%= icon "datetime", class: "icon--big", role: "img", aria_label: t("decidim.elections.election_m.label.date") %>
|
5
|
+
</li>
|
6
|
+
<li class="card-data__item">
|
7
|
+
<div class="card-data__item--centerblock">
|
8
|
+
<strong><%= t("decidim.elections.election_m.start_date") %></strong>
|
9
|
+
<%= start_date ? l(start_date, format: :decidim_short) : t("decidim.elections.election_m.unspecified") %>
|
10
|
+
</div>
|
11
|
+
</li>
|
12
|
+
<li class="card-data__item">
|
13
|
+
<div class="card-data__item--centerblock">
|
14
|
+
<strong><%= t("decidim.elections.election_m.end_date") %></strong>
|
15
|
+
<%= end_date ? l(end_date, format: :decidim_short) : t("decidim.elections.election_m.unspecified") %>
|
16
|
+
</div>
|
17
|
+
</li>
|
18
|
+
</ul>
|
19
|
+
</div>
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Elections
|
5
|
+
# This cell renders the Medium (:m) election card
|
6
|
+
# for a given instance of an Election
|
7
|
+
class ElectionMCell < Decidim::CardMCell
|
8
|
+
include ElectionCellsHelper
|
9
|
+
|
10
|
+
def date
|
11
|
+
render
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def has_state?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def title
|
21
|
+
present(model).title
|
22
|
+
end
|
23
|
+
|
24
|
+
def resource_icon
|
25
|
+
icon "elections", class: "icon--big"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Even though we need to render the badge, we can't do it in the normal
|
29
|
+
# way, because the paragraph comes from a user input and contains HTML.
|
30
|
+
# This causes the badge and the paragraph to appear in different lines.
|
31
|
+
# In order to fix it, check the `description` method.
|
32
|
+
def has_badge?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
def badge_name
|
37
|
+
text = model.voting_period_status
|
38
|
+
return unless text
|
39
|
+
|
40
|
+
I18n.t(text, scope: "decidim.elections.election_m.badge_name")
|
41
|
+
end
|
42
|
+
|
43
|
+
# In order to render the badge inline with the paragraph text we need to
|
44
|
+
# find the opening `<p>` tag and include the badge right after it. This
|
45
|
+
# makes the layout look good.
|
46
|
+
def has_image?
|
47
|
+
model.photos.present?
|
48
|
+
end
|
49
|
+
|
50
|
+
def resource_image_path
|
51
|
+
model.photos.first.url if has_image?
|
52
|
+
end
|
53
|
+
|
54
|
+
def description
|
55
|
+
text = super
|
56
|
+
text.gsub!(/^<p>/, "<p>#{render :badge}")
|
57
|
+
html_truncate(text, length: 100)
|
58
|
+
end
|
59
|
+
|
60
|
+
def state_classes
|
61
|
+
case model.voting_period_status
|
62
|
+
when :ongoing
|
63
|
+
["success"]
|
64
|
+
when :upcoming
|
65
|
+
["warning"]
|
66
|
+
else
|
67
|
+
["muted"]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def start_date
|
72
|
+
return unless model.start_time
|
73
|
+
|
74
|
+
model.start_time.to_date
|
75
|
+
end
|
76
|
+
|
77
|
+
def end_date
|
78
|
+
return unless model.end_time
|
79
|
+
|
80
|
+
model.end_time.to_date
|
81
|
+
end
|
82
|
+
|
83
|
+
def questions_count_status
|
84
|
+
content_tag(
|
85
|
+
:strong,
|
86
|
+
t("decidim.elections.election_m.questions", count: model.questions.count)
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
def footer_button_text
|
91
|
+
if model.ongoing?
|
92
|
+
t("decidim.elections.election_m.footer.vote")
|
93
|
+
else
|
94
|
+
t("decidim.elections.election_m.footer.view")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def statuses
|
99
|
+
[:questions_count]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<div class="focus__footer">
|
2
|
+
<div class="row">
|
3
|
+
<% if first_step? %>
|
4
|
+
<a></a>
|
5
|
+
<% else %>
|
6
|
+
<%= link_to(
|
7
|
+
icon("chevron-left", class: "icon", role: "img") + " " + t("decidim.elections.votes.voting_step.back"),
|
8
|
+
"#",
|
9
|
+
class: "focus__back",
|
10
|
+
data: {
|
11
|
+
toggle: [previous_step_dom_id, current_step_dom_id].join(" ")
|
12
|
+
}
|
13
|
+
) %>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<span class="button focus__next disabled-continue disabled">
|
17
|
+
<%= button_continue_text %>
|
18
|
+
</span>
|
19
|
+
|
20
|
+
<%= link_to(
|
21
|
+
button_continue_text,
|
22
|
+
"#",
|
23
|
+
class: "button focus__next enabled-continue",
|
24
|
+
data: {
|
25
|
+
toggle: [next_step_dom_id, current_step_dom_id].join(" ")
|
26
|
+
}
|
27
|
+
) %>
|
28
|
+
</div>
|
29
|
+
</div>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Elections
|
5
|
+
# This cell renders the navigation of a questionnaire step.
|
6
|
+
class VotingStepNavigationCell < Decidim::ViewModel
|
7
|
+
include Decidim::LayoutHelper
|
8
|
+
|
9
|
+
def current_step_index
|
10
|
+
model
|
11
|
+
end
|
12
|
+
|
13
|
+
def first_step?
|
14
|
+
current_step_index.zero?
|
15
|
+
end
|
16
|
+
|
17
|
+
def last_step?
|
18
|
+
current_step_index + 1 == total_steps
|
19
|
+
end
|
20
|
+
|
21
|
+
def total_steps
|
22
|
+
options[:total_steps]
|
23
|
+
end
|
24
|
+
|
25
|
+
def button_continue_text
|
26
|
+
"#{t("decidim.elections.votes.voting_step.continue")} #{icon("chevron-right", class: "icon", role: "img")}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def previous_step_dom_id
|
30
|
+
"step-#{current_step_index - 1}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def next_step_dom_id
|
34
|
+
"step-#{current_step_index + 1}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def current_step_dom_id
|
38
|
+
"step-#{current_step_index}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -6,6 +6,9 @@ module Decidim
|
|
6
6
|
# This command is executed when the user creates an Election
|
7
7
|
# from the admin panel.
|
8
8
|
class CreateElection < Rectify::Command
|
9
|
+
include ::Decidim::AttachmentMethods
|
10
|
+
include ::Decidim::GalleryMethods
|
11
|
+
|
9
12
|
def initialize(form)
|
10
13
|
@form = form
|
11
14
|
end
|
@@ -16,19 +19,26 @@ module Decidim
|
|
16
19
|
def call
|
17
20
|
return broadcast(:invalid) if form.invalid?
|
18
21
|
|
19
|
-
|
22
|
+
if process_gallery?
|
23
|
+
build_gallery
|
24
|
+
return broadcast(:invalid) if gallery_invalid?
|
25
|
+
end
|
26
|
+
|
27
|
+
transaction do
|
28
|
+
create_election!
|
29
|
+
create_gallery if process_gallery?
|
30
|
+
end
|
20
31
|
|
21
32
|
broadcast(:ok, election)
|
22
33
|
end
|
23
34
|
|
24
35
|
private
|
25
36
|
|
26
|
-
attr_reader :form, :election
|
37
|
+
attr_reader :form, :election, :gallery
|
27
38
|
|
28
39
|
def create_election!
|
29
40
|
attributes = {
|
30
41
|
title: form.title,
|
31
|
-
subtitle: form.subtitle,
|
32
42
|
description: form.description,
|
33
43
|
start_time: form.start_time,
|
34
44
|
end_time: form.end_time,
|
@@ -41,6 +51,7 @@ module Decidim
|
|
41
51
|
attributes,
|
42
52
|
visibility: "all"
|
43
53
|
)
|
54
|
+
@attached_to = @election
|
44
55
|
end
|
45
56
|
end
|
46
57
|
end
|
@@ -36,7 +36,8 @@ module Decidim
|
|
36
36
|
description: form.description,
|
37
37
|
max_selections: form.max_selections,
|
38
38
|
weight: form.weight,
|
39
|
-
random_answers_order: form.random_answers_order
|
39
|
+
random_answers_order: form.random_answers_order,
|
40
|
+
min_selections: form.min_selections
|
40
41
|
}
|
41
42
|
|
42
43
|
@question = Decidim.traceability.create!(
|
@@ -6,9 +6,13 @@ module Decidim
|
|
6
6
|
# This command is executed when the user destroys an Election
|
7
7
|
# from the admin panel.
|
8
8
|
class DestroyElection < Rectify::Command
|
9
|
+
include ::Decidim::AttachmentMethods
|
10
|
+
include ::Decidim::GalleryMethods
|
11
|
+
|
9
12
|
def initialize(election, current_user)
|
10
13
|
@election = election
|
11
14
|
@current_user = current_user
|
15
|
+
@attached_to = election
|
12
16
|
end
|
13
17
|
|
14
18
|
# Destroys the election if valid.
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Elections
|
5
|
+
module Admin
|
6
|
+
# A command is executed when an admin imports proposals from
|
7
|
+
# one component to answers of elections component.
|
8
|
+
class ImportProposalsToElections < Rectify::Command
|
9
|
+
# Public: Initializes the command.
|
10
|
+
#
|
11
|
+
# form - A form object with the params.
|
12
|
+
def initialize(form)
|
13
|
+
@form = form
|
14
|
+
end
|
15
|
+
|
16
|
+
# Executes the command. Broadcasts these events:
|
17
|
+
#
|
18
|
+
# - :ok when everything is valid.
|
19
|
+
# - :invalid if the form wasn't valid and we couldn't proceed.
|
20
|
+
#
|
21
|
+
# Returns nothing.
|
22
|
+
def call
|
23
|
+
return broadcast(:invalid) if invalid?
|
24
|
+
|
25
|
+
broadcast(:ok, create_answers_from_accepted_proposals)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :form, :answer
|
31
|
+
|
32
|
+
def invalid?
|
33
|
+
form.election.started? || form.invalid?
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_answers_from_accepted_proposals
|
37
|
+
transaction do
|
38
|
+
proposals.map do |original_proposal|
|
39
|
+
next if proposal_already_copied?(original_proposal)
|
40
|
+
|
41
|
+
create_answer_from_proposal(original_proposal)
|
42
|
+
answer.link_resources([original_proposal], "related_proposals")
|
43
|
+
end.compact
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_answer_from_proposal(original_proposal)
|
48
|
+
params = {
|
49
|
+
question: form.question,
|
50
|
+
title: original_proposal.title,
|
51
|
+
description: original_proposal.body,
|
52
|
+
weight: form.weight
|
53
|
+
}
|
54
|
+
|
55
|
+
@answer = Decidim.traceability.create!(
|
56
|
+
Answer,
|
57
|
+
form.current_user,
|
58
|
+
params,
|
59
|
+
visibility: "all"
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
def proposals
|
64
|
+
@proposals ||= if @form.import_all_accepted_proposals?
|
65
|
+
Decidim::Proposals::Proposal.where(component: origin_component).where(state: "accepted")
|
66
|
+
else
|
67
|
+
Decidim::Proposals::Proposal.where(component: origin_component)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def origin_component
|
72
|
+
@form.origin_component
|
73
|
+
end
|
74
|
+
|
75
|
+
def target_question
|
76
|
+
@form.question
|
77
|
+
end
|
78
|
+
|
79
|
+
def proposal_already_copied?(original_proposal)
|
80
|
+
original_proposal.linked_resources(:answers, "related_proposals").any? do |answer|
|
81
|
+
answer.question == target_question
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|