decidim-initiatives 0.30.1 → 0.31.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +46 -9
  3. data/app/cells/decidim/initiatives/content_blocks/highlighted_initiatives_settings_form/show.erb +7 -2
  4. data/app/cells/decidim/initiatives/initiative_g_cell.rb +5 -1
  5. data/app/commands/decidim/initiatives/admin/publish_initiative.rb +1 -5
  6. data/app/commands/decidim/initiatives/admin/update_initiative.rb +1 -2
  7. data/app/commands/decidim/initiatives/create_initiative.rb +0 -1
  8. data/app/commands/decidim/initiatives/update_initiative.rb +1 -3
  9. data/app/commands/decidim/initiatives/vote_initiative.rb +1 -11
  10. data/app/controllers/concerns/decidim/initiatives/has_signature_workflow.rb +36 -0
  11. data/app/controllers/concerns/decidim/initiatives/needs_initiative.rb +1 -12
  12. data/app/controllers/decidim/initiatives/admin/initiatives_controller.rb +2 -2
  13. data/app/controllers/decidim/initiatives/admin/initiatives_settings_controller.rb +1 -1
  14. data/app/controllers/decidim/initiatives/admin/initiatives_type_scopes_controller.rb +2 -2
  15. data/app/controllers/decidim/initiatives/admin/initiatives_types_controller.rb +2 -2
  16. data/app/controllers/decidim/initiatives/committee_requests_controller.rb +10 -2
  17. data/app/controllers/decidim/initiatives/create_initiative_controller.rb +84 -18
  18. data/app/controllers/decidim/initiatives/initiative_signatures_controller.rb +133 -42
  19. data/app/controllers/decidim/initiatives/initiative_votes_controller.rb +3 -2
  20. data/app/controllers/decidim/initiatives/initiatives_controller.rb +21 -2
  21. data/app/forms/decidim/initiatives/admin/initiative_form.rb +0 -1
  22. data/app/forms/decidim/initiatives/initiative_form.rb +0 -3
  23. data/app/helpers/decidim/initiatives/application_helper.rb +2 -0
  24. data/app/helpers/decidim/initiatives/initiatives_helper.rb +0 -1
  25. data/app/models/decidim/initiative.rb +7 -31
  26. data/app/models/decidim/initiatives_committee_member.rb +1 -1
  27. data/app/models/decidim/initiatives_type.rb +5 -2
  28. data/app/models/decidim/initiatives_vote.rb +2 -2
  29. data/app/packs/entrypoints/decidim_initiatives.js +1 -1
  30. data/app/packs/entrypoints/decidim_initiatives_admin.scss +1 -1
  31. data/app/packs/src/decidim/initiatives/admin/initiatives_types.js +2 -11
  32. data/app/packs/src/decidim/initiatives/admin/invite_users.js +1 -1
  33. data/app/packs/src/decidim/initiatives/application.js +1 -1
  34. data/app/packs/src/decidim/initiatives/check_code.js +114 -0
  35. data/app/packs/src/decidim/initiatives/initiative_creation_wizard.js +16 -0
  36. data/app/packs/src/decidim/initiatives/scoped_type.js +1 -1
  37. data/app/packs/stylesheets/initiatives.scss +16 -2
  38. data/app/permissions/decidim/initiatives/admin/permissions.rb +4 -7
  39. data/app/permissions/decidim/initiatives/permissions.rb +26 -16
  40. data/app/presenters/decidim/initiative_presenter.rb +12 -6
  41. data/app/presenters/decidim/initiatives/admin_log/initiative_presenter.rb +1 -2
  42. data/app/queries/decidim/initiatives/initiatives_stats_followers_count.rb +14 -0
  43. data/app/queries/decidim/initiatives/initiatives_stats_participants_count.rb +14 -0
  44. data/app/serializers/decidim/initiatives/open_data_initiative_serializer.rb +0 -1
  45. data/app/services/decidim/initiatives/data_encryptor.rb +1 -1
  46. data/app/services/decidim/initiatives/legacy_signature_handler.rb +25 -0
  47. data/app/services/decidim/initiatives/progress_notifier.rb +1 -7
  48. data/app/services/decidim/initiatives/signature_handler.rb +248 -0
  49. data/app/services/decidim/initiatives/status_change_notifier.rb +1 -7
  50. data/app/views/decidim/initiatives/admin/committee_requests/index.html.erb +29 -11
  51. data/app/views/decidim/initiatives/admin/exports/_dropdown.html.erb +17 -20
  52. data/app/views/decidim/initiatives/admin/initiatives/_form.html.erb +7 -13
  53. data/app/views/decidim/initiatives/admin/initiatives/_initiative_attachments.erb +2 -2
  54. data/app/views/decidim/initiatives/admin/initiatives/index.html.erb +76 -47
  55. data/app/views/decidim/initiatives/admin/initiatives_types/_form.html.erb +13 -21
  56. data/app/views/decidim/initiatives/admin/initiatives_types/_initiative_type_scopes.html.erb +28 -12
  57. data/app/views/decidim/initiatives/admin/initiatives_types/index.html.erb +33 -15
  58. data/app/views/decidim/initiatives/create_initiative/_committee_member.html.erb +27 -0
  59. data/app/views/decidim/initiatives/create_initiative/_return_to_initiatives_button.html.erb +3 -0
  60. data/app/views/decidim/initiatives/create_initiative/_send_to_technical_validation_button.html.erb +10 -0
  61. data/app/views/decidim/initiatives/create_initiative/_share_committee_link.html.erb +5 -1
  62. data/app/views/decidim/initiatives/create_initiative/fill_data.html.erb +7 -11
  63. data/app/views/decidim/initiatives/create_initiative/finish.html.erb +16 -13
  64. data/app/views/decidim/initiatives/create_initiative/promotal_committee.html.erb +33 -6
  65. data/app/views/decidim/initiatives/create_initiative/select_initiative_type.html.erb +40 -26
  66. data/app/views/decidim/initiatives/initiative_signatures/_sms_code_form.html.erb +22 -0
  67. data/app/views/decidim/initiatives/initiative_signatures/_sms_phone_number_form.html.erb +13 -0
  68. data/app/views/decidim/initiatives/initiative_signatures/fill_personal_data.html.erb +23 -22
  69. data/app/views/decidim/initiatives/initiative_signatures/finish.html.erb +17 -5
  70. data/app/views/decidim/initiatives/initiative_signatures/sms_code.html.erb +6 -8
  71. data/app/views/decidim/initiatives/initiative_signatures/sms_phone_number.html.erb +3 -8
  72. data/app/views/decidim/initiatives/initiative_signatures/update_buttons_and_counters.js.erb +3 -14
  73. data/app/views/decidim/initiatives/initiative_votes/update_buttons_and_counters.js.erb +3 -14
  74. data/app/views/decidim/initiatives/initiatives/_committee_members.html.erb +1 -1
  75. data/app/views/decidim/initiatives/initiatives/_form.html.erb +1 -3
  76. data/app/views/decidim/initiatives/initiatives/_new_initiative_button.html.erb +10 -3
  77. data/app/views/decidim/initiatives/initiatives/_pending_initiatives.html.erb +5 -0
  78. data/app/views/decidim/initiatives/initiatives/index.html.erb +8 -0
  79. data/app/views/decidim/initiatives/initiatives/show.html.erb +2 -2
  80. data/app/views/layouts/decidim/_initiative_signature_creation_header.html.erb +20 -2
  81. data/app/views/layouts/decidim/admin/_manage_initiatives.html.erb +1 -1
  82. data/app/views/layouts/decidim/initiative_signature_creation.html.erb +3 -1
  83. data/config/assets.rb +2 -2
  84. data/config/locales/ar.yml +0 -45
  85. data/config/locales/bg.yml +0 -54
  86. data/config/locales/ca-IT.yml +99 -51
  87. data/config/locales/ca.yml +99 -51
  88. data/config/locales/cs.yml +93 -54
  89. data/config/locales/de.yml +100 -52
  90. data/config/locales/el.yml +0 -45
  91. data/config/locales/en.yml +99 -51
  92. data/config/locales/es-MX.yml +99 -51
  93. data/config/locales/es-PY.yml +99 -51
  94. data/config/locales/es.yml +99 -51
  95. data/config/locales/eu.yml +120 -72
  96. data/config/locales/fi-plain.yml +99 -51
  97. data/config/locales/fi.yml +99 -51
  98. data/config/locales/fr-CA.yml +44 -51
  99. data/config/locales/fr.yml +44 -51
  100. data/config/locales/ga-IE.yml +0 -17
  101. data/config/locales/gl.yml +0 -41
  102. data/config/locales/hu.yml +0 -54
  103. data/config/locales/id-ID.yml +0 -40
  104. data/config/locales/is-IS.yml +0 -22
  105. data/config/locales/it.yml +0 -53
  106. data/config/locales/ja.yml +98 -49
  107. data/config/locales/lb.yml +0 -50
  108. data/config/locales/lt.yml +0 -56
  109. data/config/locales/lv.yml +0 -46
  110. data/config/locales/nl.yml +0 -47
  111. data/config/locales/no.yml +0 -53
  112. data/config/locales/pl.yml +0 -56
  113. data/config/locales/pt-BR.yml +0 -53
  114. data/config/locales/pt.yml +0 -53
  115. data/config/locales/ro-RO.yml +92 -50
  116. data/config/locales/ru.yml +0 -25
  117. data/config/locales/sk.yml +0 -43
  118. data/config/locales/sl.yml +0 -1
  119. data/config/locales/sv.yml +10 -53
  120. data/config/locales/tr-TR.yml +0 -53
  121. data/config/locales/uk.yml +0 -25
  122. data/config/locales/zh-CN.yml +0 -45
  123. data/config/locales/zh-TW.yml +0 -53
  124. data/db/migrate/20250605104500_remove_hashtag_column_initiatives.rb +7 -0
  125. data/lib/decidim/api/initiative_api_type.rb +3 -0
  126. data/lib/decidim/api/initiative_type.rb +23 -4
  127. data/lib/decidim/exporters/initiative_votes_pdf.rb +1 -1
  128. data/lib/decidim/initiatives/default_signature_authorizer.rb +17 -0
  129. data/lib/decidim/initiatives/engine.rb +17 -14
  130. data/lib/decidim/initiatives/menu.rb +1 -1
  131. data/lib/decidim/initiatives/participatory_space.rb +15 -1
  132. data/lib/decidim/initiatives/seeds.rb +1 -2
  133. data/lib/decidim/initiatives/signature_workflow_manifest.rb +176 -0
  134. data/lib/decidim/initiatives/signatures.rb +12 -0
  135. data/lib/decidim/initiatives/test/factories.rb +7 -7
  136. data/lib/decidim/initiatives/test/initiatives_signatures_test_helpers.rb +19 -0
  137. data/lib/decidim/initiatives/validatable_authorizations.rb +83 -0
  138. data/lib/decidim/initiatives/version.rb +1 -1
  139. data/lib/decidim/initiatives.rb +23 -12
  140. metadata +33 -21
  141. data/app/events/decidim/initiatives/endorse_initiative_event.rb +0 -13
  142. data/app/forms/decidim/initiatives/vote_form.rb +0 -208
  143. data/app/packs/src/decidim/initiatives/identity_selector_dialog.js +0 -14
  144. data/app/services/decidim/initiatives/pdf_signature_example.rb +0 -110
  145. data/app/views/decidim/initiatives/initiative_signatures/_wizard_steps.html.erb +0 -15
  146. data/app/views/decidim/initiatives/initiatives/_interactions.html.erb +0 -10
  147. data/app/views/layouts/decidim/_initiative_header.html.erb +0 -27
@@ -1,19 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # i18n-tasks-use t('layouts.decidim.initiative_signature_creation_header.fill_personal_data')
4
- # i18n-tasks-use t('layouts.decidim.initiative_signature_creation_header.finish')
5
- # i18n-tasks-use t('layouts.decidim.initiative_signature_creation_header.sms_code')
6
- # i18n-tasks-use t('layouts.decidim.initiative_signature_creation_header.sms_phone_number')
7
- # i18n-tasks-use t('layouts.decidim.initiative_signature_creation_header.finish')
8
3
  module Decidim
9
4
  module Initiatives
10
5
  class InitiativeSignaturesController < Decidim::Initiatives::ApplicationController
11
6
  layout "layouts/decidim/initiative_signature_creation"
12
7
  include Decidim::Initiatives::NeedsInitiative
13
8
  include Decidim::FormFactory
9
+ include Decidim::Initiatives::HasSignatureWorkflow
14
10
 
15
11
  prepend_before_action :set_wizard_steps
16
- before_action :authenticate_user!
12
+ before_action :authenticate_user!, unless: :ephemeral_signature_workflow?
13
+ skip_before_action :check_ephemeral_user_session
14
+
17
15
  before_action :authorize_wizard_step, only: [
18
16
  :fill_personal_data,
19
17
  :store_personal_data,
@@ -24,6 +22,8 @@ module Decidim
24
22
  :finish
25
23
  ]
26
24
 
25
+ before_action :set_ephemeral_user, if: :ephemeral_signature_workflow?, only: :index
26
+
27
27
  helper InitiativeHelper
28
28
 
29
29
  helper_method :initiative_type, :extra_data_legal_information, :sms_step?, :fill_personal_data_step?
@@ -36,11 +36,10 @@ module Decidim
36
36
  def create
37
37
  enforce_permission_to :vote, :initiative, initiative: current_initiative
38
38
 
39
- @form = form(Decidim::Initiatives::VoteForm)
40
- .from_params(
41
- initiative: current_initiative,
42
- signer: current_user
43
- )
39
+ @form = form(signature_form_class).from_params(
40
+ initiative: current_initiative,
41
+ user: current_user
42
+ )
44
43
 
45
44
  VoteInitiative.call(@form) do
46
45
  on(:ok) do
@@ -57,11 +56,10 @@ module Decidim
57
56
  def fill_personal_data
58
57
  redirect_to(sms_phone_number_path) && return unless fill_personal_data_step?
59
58
 
60
- @form = form(Decidim::Initiatives::VoteForm)
61
- .from_params(
62
- initiative: current_initiative,
63
- signer: current_user
64
- )
59
+ @form = form(signature_form_class).from_params(
60
+ initiative: current_initiative,
61
+ user: current_user
62
+ )
65
63
  end
66
64
 
67
65
  def store_personal_data
@@ -69,8 +67,11 @@ module Decidim
69
67
 
70
68
  build_vote_form(params)
71
69
 
72
- if @vote_form.invalid?
73
- flash[:alert] = I18n.t("personal_data.invalid", scope: "decidim.initiatives.initiative_votes")
70
+ if @vote_form.already_voted?
71
+ flash[:alert] = I18n.t("create.already_voted", scope: "decidim.initiatives.initiative_votes")
72
+ clear_authorization_path
73
+ redirect_to initiative_path(current_initiative)
74
+ elsif @vote_form.invalid?
74
75
  @form = @vote_form
75
76
 
76
77
  render :fill_personal_data
@@ -80,25 +81,26 @@ module Decidim
80
81
  end
81
82
 
82
83
  def sms_phone_number
83
- redirect_to(finish_path) && return unless sms_step?
84
+ return redirect_to fill_personal_data_path if fill_personal_data_step? && session[:initiative_vote_form].blank?
85
+ return redirect_to(finish_path) unless sms_step?
84
86
 
85
- @form = Decidim::Verifications::Sms::MobilePhoneForm.new
87
+ @form = sms_mobile_phone_form_class.new
86
88
  end
87
89
 
88
90
  def store_sms_phone_number
89
91
  redirect_to(finish_path) && return unless sms_step?
90
92
 
91
- @form = Decidim::Verifications::Sms::MobilePhoneForm.from_params(params.merge(user: current_user))
93
+ @form = sms_mobile_phone_form_class.from_params(params.merge(user: current_user))
92
94
 
93
- ValidateMobilePhone.call(@form, current_user) do
95
+ sms_mobile_phone_validator_class.call(@form, current_user) do
94
96
  on(:ok) do |metadata|
95
- store_session_sms_code(metadata)
97
+ store_session_sms_code(metadata, @form.mobile_phone_number)
96
98
  redirect_to sms_code_path
97
99
  end
98
100
 
99
101
  on(:invalid) do
100
102
  flash[:alert] = I18n.t("sms_phone.invalid", scope: "decidim.initiatives.initiative_votes")
101
- render :sms_phone_number
103
+ render :sms_phone_number, status: :unprocessable_entity
102
104
  end
103
105
  end
104
106
  end
@@ -106,24 +108,41 @@ module Decidim
106
108
  def sms_code
107
109
  redirect_to(finish_path) && return unless sms_step?
108
110
 
109
- redirect_to sms_phone_number_path && return if session_sms_code.blank?
111
+ return redirect_to sms_phone_number_path if session_sms_code.blank?
110
112
 
111
- @form = Decidim::Verifications::Sms::ConfirmationForm.new
113
+ @sms_code_form = Decidim::Verifications::Sms::ConfirmationForm.new
114
+ @phone_number_form = sms_mobile_phone_form_class.from_params(mobile_phone_number: session_sms_code[:phone_number], user: current_user)
112
115
  end
113
116
 
114
117
  def store_sms_code
115
118
  redirect_to(finish_path) && return unless sms_step?
116
119
 
117
- @form = Decidim::Verifications::Sms::ConfirmationForm.from_params(params)
118
- ValidateSmsCode.call(@form, session_sms_code) do
120
+ @sms_code_form = Decidim::Verifications::Sms::ConfirmationForm.from_params(params)
121
+ sms_code_validator_class.call(@sms_code_form, session_sms_code) do
119
122
  on(:ok) do
120
- clear_session_sms_code
121
- redirect_to finish_path
123
+ respond_to do |format|
124
+ format.js do
125
+ render json: { sms_code: "OK" }
126
+ end
127
+
128
+ format.html do
129
+ clear_session_sms_code
130
+ redirect_to finish_path
131
+ end
132
+ end
122
133
  end
123
134
 
124
135
  on(:invalid) do
125
- flash[:alert] = I18n.t("sms_code.invalid", scope: "decidim.initiatives.initiative_votes")
126
- render :sms_code
136
+ respond_to do |format|
137
+ format.js do
138
+ render json: { sms_code: "KO" }
139
+ end
140
+
141
+ format.html do
142
+ flash[:alert] = I18n.t("sms_code.invalid", scope: "decidim.initiatives.initiative_votes")
143
+ render :sms_code, status: :unprocessable_entity
144
+ end
145
+ end
127
146
  end
128
147
  end
129
148
  end
@@ -135,9 +154,12 @@ module Decidim
135
154
  check_session_personal_data
136
155
  end
137
156
 
157
+ return if @vote_form.blank?
158
+
138
159
  VoteInitiative.call(@vote_form) do
139
160
  on(:ok) do
140
161
  session[:initiative_vote_form] = {}
162
+ clear_authorization_path
141
163
  end
142
164
 
143
165
  on(:invalid) do |vote|
@@ -169,13 +191,35 @@ module Decidim
169
191
  end
170
192
 
171
193
  def build_vote_form(parameters)
172
- @vote_form = form(Decidim::Initiatives::VoteForm).from_params(parameters).tap do |form|
194
+ @vote_form = form(signature_form_class).from_params(parameters).tap do |form|
173
195
  form.initiative = current_initiative
174
- form.signer = current_user
196
+ form.user = current_user
197
+ end
198
+
199
+ @vote_form.validate
200
+
201
+ if @vote_form.transfer_status == :transfer_user && @vote_form.user != current_user
202
+ new_user = @vote_form.user
203
+ new_user.update(last_sign_in_at: Time.current, deleted_at: nil)
204
+ sign_out(current_user)
205
+ sign_in(new_user)
206
+ elsif @vote_form.transfer_status.is_a?(Decidim::AuthorizationTransfer)
207
+ transfer = @vote_form.transfer_status
208
+
209
+ message = t("authorizations.create.success", scope: "decidim.verifications")
210
+ if transfer.records.any?
211
+ message = <<~HTML
212
+ <p>#{CGI.escapeHTML(message)}</p>
213
+ <p>#{CGI.escapeHTML(t("authorizations.create.transferred", scope: "decidim.verifications"))}</p>
214
+ #{transfer.presenter.records_list_html}
215
+ HTML
216
+ end
217
+
218
+ flash[:notice] = message
175
219
  end
176
220
 
177
221
  session[:initiative_vote_form] ||= {}
178
- session[:initiative_vote_form] = session[:initiative_vote_form].merge(@vote_form.attributes_with_values.except(:initiative, :signer))
222
+ session[:initiative_vote_form] = session[:initiative_vote_form].merge(@vote_form.attributes_with_values.except(:initiative, :user, :transfer_status))
179
223
  end
180
224
 
181
225
  def initiative_type
@@ -183,11 +227,11 @@ module Decidim
183
227
  end
184
228
 
185
229
  def sms_step?
186
- current_initiative.validate_sms_code_on_votes?
230
+ current_initiative.organization.available_authorizations.include?("sms") && signature_workflow_manifest.sms_verification
187
231
  end
188
232
 
189
233
  def fill_personal_data_step?
190
- initiative_type.collect_user_extra_fields?
234
+ signature_form_class.requires_extra_attributes?
191
235
  end
192
236
 
193
237
  def authorize_wizard_step
@@ -205,9 +249,9 @@ module Decidim
205
249
  end
206
250
 
207
251
  def session_vote_form
208
- attributes = session[:initiative_vote_form].merge(initiative: current_initiative, signer: current_user)
252
+ attributes = session[:initiative_vote_form].merge(initiative: current_initiative, user: current_user)
209
253
 
210
- @vote_form = form(Decidim::Initiatives::VoteForm).from_params(attributes)
254
+ @vote_form = form(signature_form_class).from_params(attributes)
211
255
  end
212
256
 
213
257
  def check_session_personal_data
@@ -221,12 +265,59 @@ module Decidim
221
265
  session[:initiative_sms_code] = {}
222
266
  end
223
267
 
224
- def store_session_sms_code(metadata)
225
- session[:initiative_sms_code] = metadata
268
+ def store_session_sms_code(metadata, phone_number)
269
+ session[:initiative_sms_code] = metadata.merge(phone_number:)
226
270
  end
227
271
 
228
272
  def session_sms_code
229
- session[:initiative_sms_code]
273
+ (session[:initiative_sms_code] || {}).symbolize_keys
274
+ end
275
+
276
+ def clear_authorization_path
277
+ return unless current_user.ephemeral? && onboarding_manager.authorization_path.present?
278
+
279
+ base_path = initiatives_path
280
+ return if onboarding_manager.authorization_path == base_path
281
+
282
+ current_user.update(extended_data: current_user.extended_data.deep_merge("onboarding" => { "authorization_path" => base_path }))
283
+ end
284
+
285
+ def set_ephemeral_user
286
+ if user_signed_in?
287
+ update_onboarding_data
288
+ else
289
+ create_ephemeral_user
290
+ end
291
+ end
292
+
293
+ def update_onboarding_data
294
+ return unless current_user.ephemeral?
295
+ return if onboarding_manager.model == current_initiative
296
+
297
+ current_user.update(extended_data: current_user.extended_data.deep_merge("onboarding" => current_initiative_onboarding_data))
298
+ end
299
+
300
+ def create_ephemeral_user
301
+ form = Decidim::EphemeralUserForm.new(
302
+ organization: current_organization,
303
+ locale: current_locale,
304
+ onboarding_data: current_initiative_onboarding_data
305
+ )
306
+ CreateEphemeralUser.call(form) do
307
+ on(:ok) do |ephemeral_user|
308
+ sign_in(ephemeral_user)
309
+ end
310
+ end
311
+ end
312
+
313
+ def current_initiative_onboarding_data
314
+ {
315
+ "model" => current_initiative.to_gid,
316
+ "permissions_holder" => initiative_type.to_gid,
317
+ "action" => "vote",
318
+ "redirect_path" => initiative_path(current_initiative),
319
+ "authorization_path" => initiative_signatures_path(current_initiative)
320
+ }
230
321
  end
231
322
  end
232
323
  end
@@ -6,6 +6,7 @@ module Decidim
6
6
  class InitiativeVotesController < Decidim::Initiatives::ApplicationController
7
7
  include Decidim::Initiatives::NeedsInitiative
8
8
  include Decidim::FormFactory
9
+ include Decidim::Initiatives::HasSignatureWorkflow
9
10
 
10
11
  before_action :authenticate_user!
11
12
 
@@ -15,9 +16,9 @@ module Decidim
15
16
  def create
16
17
  enforce_permission_to :vote, :initiative, initiative: current_initiative
17
18
 
18
- @form = form(Decidim::Initiatives::VoteForm).from_params(
19
+ @form = form(signature_form_class).from_params(
19
20
  initiative: current_initiative,
20
- signer: current_user
21
+ user: current_user
21
22
  )
22
23
 
23
24
  VoteInitiative.call(@form) do
@@ -26,13 +26,15 @@ module Decidim
26
26
  include Decidim::Initiatives::Orderable
27
27
  include TypeSelectorOptions
28
28
  include NeedsInitiative
29
+ include HasSignatureWorkflow
29
30
  include SingleInitiativeType
30
31
  include Decidim::IconHelper
31
32
 
32
- helper_method :collection, :initiatives, :filter, :stats, :tabs, :panels
33
+ helper_method :collection, :initiatives, :pending_initiatives, :filter, :stats, :tabs, :panels
33
34
  helper_method :initiative_type, :available_initiative_types
34
35
 
35
36
  before_action :authorize_participatory_space, only: [:show]
37
+ skip_before_action :check_ephemeral_user_session, only: [:index, :show]
36
38
 
37
39
  # GET /initiatives
38
40
  def index
@@ -102,11 +104,24 @@ module Decidim
102
104
 
103
105
  on(:invalid) do
104
106
  flash.now[:alert] = I18n.t("error", scope: "decidim.initiatives.update")
105
- render :edit, layout: "decidim/initiative"
107
+ render :edit, layout: "decidim/initiative", status: :unprocessable_entity
106
108
  end
107
109
  end
108
110
  end
109
111
 
112
+ # DELETE /initiatives/:id/discard
113
+ def discard
114
+ enforce_permission_to :discard, :initiative, initiative: current_initiative
115
+
116
+ Decidim.traceability.perform_action!(:discard, current_initiative, current_user) do
117
+ current_initiative.discarded!
118
+ current_initiative
119
+ end
120
+
121
+ flash[:notice] = I18n.t("initiatives.discard.success", scope: "decidim.initiatives.admin")
122
+ redirect_to decidim_initiatives.initiatives_path
123
+ end
124
+
110
125
  def print
111
126
  enforce_permission_to :print, :initiative, initiative: current_initiative
112
127
  output = Decidim::Initiatives::ApplicationFormPDF.new(current_initiative).render
@@ -133,6 +148,10 @@ module Decidim
133
148
  @initiatives = paginate(@initiatives)
134
149
  end
135
150
 
151
+ def pending_initiatives
152
+ @pending_initiatives ||= Initiative.where(state: %w(created validating)).where(author: current_user)
153
+ end
154
+
136
155
  alias collection initiatives
137
156
 
138
157
  def search_collection
@@ -18,7 +18,6 @@ module Decidim
18
18
  attribute :signature_type, String
19
19
  attribute :signature_start_date, Decidim::Attributes::LocalizedDate
20
20
  attribute :signature_end_date, Decidim::Attributes::LocalizedDate
21
- attribute :hashtag, String
22
21
  attribute :offline_votes, Hash
23
22
  attribute :state, String
24
23
  attribute :attachment, AttachmentForm
@@ -13,12 +13,10 @@ module Decidim
13
13
  attribute :description, String
14
14
  attribute :type_id, Integer
15
15
  attribute :area_id, Integer
16
- attribute :decidim_user_group_id, Integer
17
16
  attribute :signature_type, String
18
17
  attribute :signature_end_date, Date
19
18
  attribute :state, String
20
19
  attribute :attachment, AttachmentForm
21
- attribute :hashtag, String
22
20
  attribute :scope_id, Integer
23
21
 
24
22
  attachments_attribute :photos
@@ -39,7 +37,6 @@ module Decidim
39
37
  def map_model(model)
40
38
  self.type_id = model.type.id
41
39
  self.scope_id = model.scope&.id
42
- self.decidim_user_group_id = model.decidim_user_group_id
43
40
  self.signature_type = model.signature_type || initiative_type.signature_type
44
41
  self.title = translated_attribute(model.title)
45
42
  self.description = translated_attribute(model.description)
@@ -7,6 +7,8 @@ module Decidim
7
7
  module ApplicationHelper
8
8
  include Decidim::CheckBoxesTreeHelper
9
9
  include Decidim::DateRangeHelper
10
+ include Decidim::AnimationsHelper
11
+ include Decidim::Initiatives::ScopesHelper
10
12
  include InitiativesHelper
11
13
 
12
14
  def filter_states_values
@@ -34,7 +34,6 @@ module Decidim
34
34
  id: "type")
35
35
  end
36
36
  sections.append(method: :with_any_area, collection: filter_areas_values, label: t("decidim.initiatives.initiatives.filters.area"), id: "area")
37
- sections.append(method: :author, collection: filter_author_values, label: t("decidim.initiatives.initiatives.filters.author"), id: "author") if current_user
38
37
  sections.reject { |item| item[:collection].blank? }
39
38
  end
40
39
 
@@ -34,6 +34,7 @@ module Decidim
34
34
  delegate :document_number_authorization_handler, :promoting_committee_enabled?, :attachments_enabled?,
35
35
  :promoting_committee_enabled?, :custom_signature_end_date_enabled?, :area_enabled?, to: :type
36
36
  delegate :name, to: :area, prefix: true, allow_nil: true
37
+ delegate :name, to: :author, prefix: true
37
38
 
38
39
  belongs_to :organization,
39
40
  foreign_key: "decidim_organization_id",
@@ -65,12 +66,10 @@ module Decidim
65
66
  dependent: :destroy,
66
67
  as: :participatory_space
67
68
 
68
- enum signature_type: [:online, :offline, :any], _suffix: true
69
- enum state: [:created, :validating, :discarded, :open, :rejected, :accepted]
69
+ enum :signature_type, [:online, :offline, :any], suffix: true
70
+ enum :state, [:created, :validating, :discarded, :open, :rejected, :accepted]
70
71
 
71
72
  validates :title, :description, :state, :signature_type, presence: true
72
- validates :hashtag,
73
- uniqueness: { allow_blank: true, case_sensitive: false }
74
73
 
75
74
  validate :signature_type_allowed
76
75
 
@@ -146,7 +145,6 @@ module Decidim
146
145
 
147
146
  before_update :set_offline_votes_total
148
147
  after_commit :notify_state_change
149
- after_create :notify_creation
150
148
 
151
149
  searchable_fields({
152
150
  participatory_space: :itself,
@@ -166,6 +164,10 @@ module Decidim
166
164
  Decidim::Initiatives::AdminLog::InitiativePresenter
167
165
  end
168
166
 
167
+ def presenter
168
+ Decidim::InitiativePresenter.new(self)
169
+ end
170
+
169
171
  def self.ransackable_attributes(auth_object = nil)
170
172
  base = %w(search_text title description id id_string supports_count author_name author_nickname)
171
173
 
@@ -195,22 +197,6 @@ module Decidim
195
197
  type.comments_enabled?
196
198
  end
197
199
 
198
- # Public: Check if an initiative has been created by an individual person.
199
- # If it is false, then it has been created by an authorized organization.
200
- #
201
- # Returns a Boolean
202
- def created_by_individual?
203
- decidim_user_group_id.nil?
204
- end
205
-
206
- # Public: Returns the author name. If it has been created by an organization it will
207
- # return the organization's name. Otherwise it will return author's name.
208
- #
209
- # Returns a string
210
- def author_name
211
- user_group&.name || author.name
212
- end
213
-
214
200
  # Public: Overrides the `reported_attributes` Reportable concern method.
215
201
  def reported_attributes
216
202
  [:title, :description]
@@ -278,11 +264,6 @@ module Decidim
278
264
  signature_end_date.present? && signature_start_date.present?
279
265
  end
280
266
 
281
- # Public: Returns the hashtag for the initiative.
282
- def hashtag
283
- attributes["hashtag"].to_s.delete("#")
284
- end
285
-
286
267
  # Public: Calculates the number of total current supports.
287
268
  #
288
269
  # Returns an Integer.
@@ -504,11 +485,6 @@ module Decidim
504
485
  notifier.notify
505
486
  end
506
487
 
507
- def notify_creation
508
- notifier = Decidim::Initiatives::StatusChangeNotifier.new(initiative: self)
509
- notifier.notify
510
- end
511
-
512
488
  # Allow ransacker to search for a key in a hstore column (`title`.`en`)
513
489
  [:title, :description].each { |column| ransacker_i18n(column) }
514
490
 
@@ -12,7 +12,7 @@ module Decidim
12
12
  foreign_key: "decidim_users_id",
13
13
  class_name: "Decidim::User"
14
14
 
15
- enum state: [:requested, :rejected, :accepted]
15
+ enum :state, [:requested, :rejected, :accepted]
16
16
 
17
17
  validates :state, presence: true
18
18
  validates :user, uniqueness: { scope: :initiative }
@@ -24,10 +24,9 @@ module Decidim
24
24
  through: :scopes,
25
25
  class_name: "Decidim::Initiative"
26
26
 
27
- enum signature_type: [:online, :offline, :any], _suffix: true
27
+ enum :signature_type, [:online, :offline, :any], suffix: true
28
28
 
29
29
  validates :title, :description, :signature_type, presence: true
30
- validates :document_number_authorization_handler, presence: true, if: ->(form) { form.collect_user_extra_fields? }
31
30
 
32
31
  has_one_attached :banner_image
33
32
  validates_upload :banner_image, uploader: Decidim::BannerImageUploader
@@ -53,5 +52,9 @@ module Decidim
53
52
  def self.log_presenter_class_for(_log)
54
53
  Decidim::Initiatives::AdminLog::InitiativesTypePresenter
55
54
  end
55
+
56
+ def signature_workflow_manifest
57
+ Decidim::Initiatives::Signatures.find_workflow_manifest(document_number_authorization_handler)
58
+ end
56
59
  end
57
60
  end
@@ -39,13 +39,13 @@ module Decidim
39
39
  end
40
40
 
41
41
  def decrypted_metadata
42
- @decrypted_metadata ||= encrypted_metadata ? encryptor.decrypt(encrypted_metadata) : {}
42
+ @decrypted_metadata ||= (encrypted_metadata ? encryptor.decrypt(encrypted_metadata) : {}).with_indifferent_access
43
43
  end
44
44
 
45
45
  private
46
46
 
47
47
  def encryptor
48
- @encryptor ||= Decidim::Initiatives::DataEncryptor.new(secret: "personal user metadata")
48
+ @encryptor ||= Decidim::Initiatives::DataEncryptor.new(secret: Decidim::Initiatives.signature_handler_encryption_secret)
49
49
  end
50
50
 
51
51
  def authorization_unique_id
@@ -1,6 +1,6 @@
1
1
  import "src/decidim/initiatives/application"
2
- import "src/decidim/initiatives/identity_selector_dialog"
3
2
  import "src/decidim/initiatives/scoped_type"
3
+ import "src/decidim/initiatives/initiative_creation_wizard"
4
4
 
5
5
  // Images
6
6
  require.context("../images", true)
@@ -1 +1 @@
1
- @import "stylesheets/decidim/initiatives/admin/initiatives.scss";
1
+ @use "stylesheets/decidim/initiatives/admin/initiatives";
@@ -1,4 +1,4 @@
1
- (() => {
1
+ document.addEventListener("turbo:load", () => {
2
2
  const $scope = $("#promoting-committee-details");
3
3
 
4
4
  const $promotingCommitteeCheckbox = $(
@@ -8,8 +8,6 @@
8
8
 
9
9
  const $signatureType = $("#initiatives_type_signature_type");
10
10
 
11
- const $collectUserDataCheckbox = $("#initiatives_type_collect_user_extra_fields");
12
-
13
11
  const toggleVisibility = () => {
14
12
  if ($promotingCommitteeCheckbox.is(":checked")) {
15
13
  $(".minimum-committee-members-details", $scope).show();
@@ -22,17 +20,10 @@
22
20
  } else {
23
21
  $("#initiatives_type_undo_online_signatures_enabled").parent().parent().show();
24
22
  }
25
-
26
- if ($collectUserDataCheckbox.is(":checked")) {
27
- $("#initiatives_type-extra_fields_legal_information-tabs").parent().parent().show()
28
- } else {
29
- $("#initiatives_type-extra_fields_legal_information-tabs").parent().parent().hide()
30
- }
31
23
  };
32
24
 
33
25
  $($promotingCommitteeCheckbox).click(() => toggleVisibility());
34
26
  $($signatureType).change(() => toggleVisibility());
35
- $($collectUserDataCheckbox).click(() => toggleVisibility());
36
27
 
37
28
  toggleVisibility();
38
- })();
29
+ });
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable no-empty */
2
2
 
3
- $(() => {
3
+ document.addEventListener("turbo:load", () => {
4
4
  let inviteUsersButton = document.querySelector(".invite-users-link");
5
5
 
6
6
  if (inviteUsersButton !== null) {
@@ -1,2 +1,2 @@
1
+ import "src/decidim/initiatives/check_code"
1
2
  import "src/decidim/initiatives/scoped_type"
2
- import "src/decidim/initiatives/identity_selector_dialog"