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.
- checksums.yaml +4 -4
- data/README.md +46 -9
- data/app/cells/decidim/initiatives/content_blocks/highlighted_initiatives_settings_form/show.erb +7 -2
- data/app/cells/decidim/initiatives/initiative_g_cell.rb +5 -1
- data/app/commands/decidim/initiatives/admin/publish_initiative.rb +1 -5
- data/app/commands/decidim/initiatives/admin/update_initiative.rb +1 -2
- data/app/commands/decidim/initiatives/create_initiative.rb +0 -1
- data/app/commands/decidim/initiatives/update_initiative.rb +1 -3
- data/app/commands/decidim/initiatives/vote_initiative.rb +1 -11
- data/app/controllers/concerns/decidim/initiatives/has_signature_workflow.rb +36 -0
- data/app/controllers/concerns/decidim/initiatives/needs_initiative.rb +1 -12
- data/app/controllers/decidim/initiatives/admin/initiatives_controller.rb +2 -2
- data/app/controllers/decidim/initiatives/admin/initiatives_settings_controller.rb +1 -1
- data/app/controllers/decidim/initiatives/admin/initiatives_type_scopes_controller.rb +2 -2
- data/app/controllers/decidim/initiatives/admin/initiatives_types_controller.rb +2 -2
- data/app/controllers/decidim/initiatives/committee_requests_controller.rb +10 -2
- data/app/controllers/decidim/initiatives/create_initiative_controller.rb +84 -18
- data/app/controllers/decidim/initiatives/initiative_signatures_controller.rb +133 -42
- data/app/controllers/decidim/initiatives/initiative_votes_controller.rb +3 -2
- data/app/controllers/decidim/initiatives/initiatives_controller.rb +21 -2
- data/app/forms/decidim/initiatives/admin/initiative_form.rb +0 -1
- data/app/forms/decidim/initiatives/initiative_form.rb +0 -3
- data/app/helpers/decidim/initiatives/application_helper.rb +2 -0
- data/app/helpers/decidim/initiatives/initiatives_helper.rb +0 -1
- data/app/models/decidim/initiative.rb +7 -31
- data/app/models/decidim/initiatives_committee_member.rb +1 -1
- data/app/models/decidim/initiatives_type.rb +5 -2
- data/app/models/decidim/initiatives_vote.rb +2 -2
- data/app/packs/entrypoints/decidim_initiatives.js +1 -1
- data/app/packs/entrypoints/decidim_initiatives_admin.scss +1 -1
- data/app/packs/src/decidim/initiatives/admin/initiatives_types.js +2 -11
- data/app/packs/src/decidim/initiatives/admin/invite_users.js +1 -1
- data/app/packs/src/decidim/initiatives/application.js +1 -1
- data/app/packs/src/decidim/initiatives/check_code.js +114 -0
- data/app/packs/src/decidim/initiatives/initiative_creation_wizard.js +16 -0
- data/app/packs/src/decidim/initiatives/scoped_type.js +1 -1
- data/app/packs/stylesheets/initiatives.scss +16 -2
- data/app/permissions/decidim/initiatives/admin/permissions.rb +4 -7
- data/app/permissions/decidim/initiatives/permissions.rb +26 -16
- data/app/presenters/decidim/initiative_presenter.rb +12 -6
- data/app/presenters/decidim/initiatives/admin_log/initiative_presenter.rb +1 -2
- data/app/queries/decidim/initiatives/initiatives_stats_followers_count.rb +14 -0
- data/app/queries/decidim/initiatives/initiatives_stats_participants_count.rb +14 -0
- data/app/serializers/decidim/initiatives/open_data_initiative_serializer.rb +0 -1
- data/app/services/decidim/initiatives/data_encryptor.rb +1 -1
- data/app/services/decidim/initiatives/legacy_signature_handler.rb +25 -0
- data/app/services/decidim/initiatives/progress_notifier.rb +1 -7
- data/app/services/decidim/initiatives/signature_handler.rb +248 -0
- data/app/services/decidim/initiatives/status_change_notifier.rb +1 -7
- data/app/views/decidim/initiatives/admin/committee_requests/index.html.erb +29 -11
- data/app/views/decidim/initiatives/admin/exports/_dropdown.html.erb +17 -20
- data/app/views/decidim/initiatives/admin/initiatives/_form.html.erb +7 -13
- data/app/views/decidim/initiatives/admin/initiatives/_initiative_attachments.erb +2 -2
- data/app/views/decidim/initiatives/admin/initiatives/index.html.erb +76 -47
- data/app/views/decidim/initiatives/admin/initiatives_types/_form.html.erb +13 -21
- data/app/views/decidim/initiatives/admin/initiatives_types/_initiative_type_scopes.html.erb +28 -12
- data/app/views/decidim/initiatives/admin/initiatives_types/index.html.erb +33 -15
- data/app/views/decidim/initiatives/create_initiative/_committee_member.html.erb +27 -0
- data/app/views/decidim/initiatives/create_initiative/_return_to_initiatives_button.html.erb +3 -0
- data/app/views/decidim/initiatives/create_initiative/_send_to_technical_validation_button.html.erb +10 -0
- data/app/views/decidim/initiatives/create_initiative/_share_committee_link.html.erb +5 -1
- data/app/views/decidim/initiatives/create_initiative/fill_data.html.erb +7 -11
- data/app/views/decidim/initiatives/create_initiative/finish.html.erb +16 -13
- data/app/views/decidim/initiatives/create_initiative/promotal_committee.html.erb +33 -6
- data/app/views/decidim/initiatives/create_initiative/select_initiative_type.html.erb +40 -26
- data/app/views/decidim/initiatives/initiative_signatures/_sms_code_form.html.erb +22 -0
- data/app/views/decidim/initiatives/initiative_signatures/_sms_phone_number_form.html.erb +13 -0
- data/app/views/decidim/initiatives/initiative_signatures/fill_personal_data.html.erb +23 -22
- data/app/views/decidim/initiatives/initiative_signatures/finish.html.erb +17 -5
- data/app/views/decidim/initiatives/initiative_signatures/sms_code.html.erb +6 -8
- data/app/views/decidim/initiatives/initiative_signatures/sms_phone_number.html.erb +3 -8
- data/app/views/decidim/initiatives/initiative_signatures/update_buttons_and_counters.js.erb +3 -14
- data/app/views/decidim/initiatives/initiative_votes/update_buttons_and_counters.js.erb +3 -14
- data/app/views/decidim/initiatives/initiatives/_committee_members.html.erb +1 -1
- data/app/views/decidim/initiatives/initiatives/_form.html.erb +1 -3
- data/app/views/decidim/initiatives/initiatives/_new_initiative_button.html.erb +10 -3
- data/app/views/decidim/initiatives/initiatives/_pending_initiatives.html.erb +5 -0
- data/app/views/decidim/initiatives/initiatives/index.html.erb +8 -0
- data/app/views/decidim/initiatives/initiatives/show.html.erb +2 -2
- data/app/views/layouts/decidim/_initiative_signature_creation_header.html.erb +20 -2
- data/app/views/layouts/decidim/admin/_manage_initiatives.html.erb +1 -1
- data/app/views/layouts/decidim/initiative_signature_creation.html.erb +3 -1
- data/config/assets.rb +2 -2
- data/config/locales/ar.yml +0 -45
- data/config/locales/bg.yml +0 -54
- data/config/locales/ca-IT.yml +99 -51
- data/config/locales/ca.yml +99 -51
- data/config/locales/cs.yml +93 -54
- data/config/locales/de.yml +100 -52
- data/config/locales/el.yml +0 -45
- data/config/locales/en.yml +99 -51
- data/config/locales/es-MX.yml +99 -51
- data/config/locales/es-PY.yml +99 -51
- data/config/locales/es.yml +99 -51
- data/config/locales/eu.yml +120 -72
- data/config/locales/fi-plain.yml +99 -51
- data/config/locales/fi.yml +99 -51
- data/config/locales/fr-CA.yml +44 -51
- data/config/locales/fr.yml +44 -51
- data/config/locales/ga-IE.yml +0 -17
- data/config/locales/gl.yml +0 -41
- data/config/locales/hu.yml +0 -54
- data/config/locales/id-ID.yml +0 -40
- data/config/locales/is-IS.yml +0 -22
- data/config/locales/it.yml +0 -53
- data/config/locales/ja.yml +98 -49
- data/config/locales/lb.yml +0 -50
- data/config/locales/lt.yml +0 -56
- data/config/locales/lv.yml +0 -46
- data/config/locales/nl.yml +0 -47
- data/config/locales/no.yml +0 -53
- data/config/locales/pl.yml +0 -56
- data/config/locales/pt-BR.yml +0 -53
- data/config/locales/pt.yml +0 -53
- data/config/locales/ro-RO.yml +92 -50
- data/config/locales/ru.yml +0 -25
- data/config/locales/sk.yml +0 -43
- data/config/locales/sl.yml +0 -1
- data/config/locales/sv.yml +10 -53
- data/config/locales/tr-TR.yml +0 -53
- data/config/locales/uk.yml +0 -25
- data/config/locales/zh-CN.yml +0 -45
- data/config/locales/zh-TW.yml +0 -53
- data/db/migrate/20250605104500_remove_hashtag_column_initiatives.rb +7 -0
- data/lib/decidim/api/initiative_api_type.rb +3 -0
- data/lib/decidim/api/initiative_type.rb +23 -4
- data/lib/decidim/exporters/initiative_votes_pdf.rb +1 -1
- data/lib/decidim/initiatives/default_signature_authorizer.rb +17 -0
- data/lib/decidim/initiatives/engine.rb +17 -14
- data/lib/decidim/initiatives/menu.rb +1 -1
- data/lib/decidim/initiatives/participatory_space.rb +15 -1
- data/lib/decidim/initiatives/seeds.rb +1 -2
- data/lib/decidim/initiatives/signature_workflow_manifest.rb +176 -0
- data/lib/decidim/initiatives/signatures.rb +12 -0
- data/lib/decidim/initiatives/test/factories.rb +7 -7
- data/lib/decidim/initiatives/test/initiatives_signatures_test_helpers.rb +19 -0
- data/lib/decidim/initiatives/validatable_authorizations.rb +83 -0
- data/lib/decidim/initiatives/version.rb +1 -1
- data/lib/decidim/initiatives.rb +23 -12
- metadata +33 -21
- data/app/events/decidim/initiatives/endorse_initiative_event.rb +0 -13
- data/app/forms/decidim/initiatives/vote_form.rb +0 -208
- data/app/packs/src/decidim/initiatives/identity_selector_dialog.js +0 -14
- data/app/services/decidim/initiatives/pdf_signature_example.rb +0 -110
- data/app/views/decidim/initiatives/initiative_signatures/_wizard_steps.html.erb +0 -15
- data/app/views/decidim/initiatives/initiatives/_interactions.html.erb +0 -10
- data/app/views/layouts/decidim/_initiative_header.html.erb +0 -27
@@ -0,0 +1,248 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Initiatives
|
5
|
+
# This is the base class for signature handlers, all implementations
|
6
|
+
# should inherit from it.
|
7
|
+
# Each SignatureHandler is a form that will be used to check if the
|
8
|
+
# signature is valid or not. When it is valid the initiatives votes
|
9
|
+
# defined by the initiative type will be created for the user.
|
10
|
+
#
|
11
|
+
# Feel free to use validations to assert fields against a remote API,
|
12
|
+
# local database, or whatever.
|
13
|
+
#
|
14
|
+
# It also sets two default attributes, `user` and `initiative`.
|
15
|
+
class SignatureHandler < Form
|
16
|
+
include ValidatableAuthorizations
|
17
|
+
|
18
|
+
mimic :initiatives_vote
|
19
|
+
|
20
|
+
# The user that is trying to sign, it is initialized with the
|
21
|
+
# `current_user` from the controller.
|
22
|
+
attribute :user, Decidim::User
|
23
|
+
|
24
|
+
# The initiative to be signed
|
25
|
+
attribute :initiative, Decidim::Initiative
|
26
|
+
|
27
|
+
attribute :tos_agreement, if: :ephemeral_tos_pending?
|
28
|
+
validates :tos_agreement, presence: true, if: :ephemeral_tos_pending?
|
29
|
+
validate :tos_agreement_acceptance, if: :ephemeral_tos_pending?
|
30
|
+
|
31
|
+
attribute :transfer_status
|
32
|
+
|
33
|
+
validates :initiative, :user, presence: true
|
34
|
+
validate :uniqueness
|
35
|
+
validate :valid_metadata
|
36
|
+
validate :valid_authorized_scopes
|
37
|
+
|
38
|
+
delegate :promote_authorization_validation_errors, :authorization_handler_form_class, :ephemeral?, to: :workflow_manifest
|
39
|
+
delegate :scope, to: :initiative
|
40
|
+
|
41
|
+
# A unique ID to be implemented by the signature handler that ensures
|
42
|
+
# no duplicates are created.
|
43
|
+
def unique_id
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def encrypted_metadata
|
48
|
+
return if metadata.blank?
|
49
|
+
|
50
|
+
@encrypted_metadata ||= encryptor.encrypt(metadata)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Public: Builds the list of scopes where the user is authorized to vote in. This is used when
|
54
|
+
# the initiative allows also voting on child scopes, not only the main scope.
|
55
|
+
#
|
56
|
+
# Instead of just listing the children of the main scope, we just want to select the ones that
|
57
|
+
# have been added to the InitiativeType with its voting settings.
|
58
|
+
#
|
59
|
+
def authorized_scopes
|
60
|
+
initiative.votable_initiative_type_scopes.select do |initiative_type_scope|
|
61
|
+
initiative_type_scope.global_scope? ||
|
62
|
+
initiative_type_scope.scope == user_signature_scope ||
|
63
|
+
initiative_type_scope.scope.ancestor_of?(user_signature_scope)
|
64
|
+
end.flat_map(&:scope)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Public: Finds the scope the user has an authorization for, this way the user can vote
|
68
|
+
# on that scope and its parents.
|
69
|
+
#
|
70
|
+
# This is can be used to allow users that are authorized with a children
|
71
|
+
# scope to sign an initiative with a parent scope.
|
72
|
+
#
|
73
|
+
# As an example: A city (global scope) has many districts (scopes with
|
74
|
+
# parent nil), and each district has different neighbourhoods (with its
|
75
|
+
# parent as a district). If we setup the authorization handler to match
|
76
|
+
# a neighbourhood, the same authorization can be used to participate
|
77
|
+
# in district, neighbourhoods or city initiatives.
|
78
|
+
#
|
79
|
+
# Returns a Decidim::Scope.
|
80
|
+
def user_signature_scope
|
81
|
+
return if signature_scope_id.blank?
|
82
|
+
|
83
|
+
@user_signature_scope ||= signature_scope_candidates.find do |scope_candidate|
|
84
|
+
scope_candidate&.id == signature_scope_id
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Public: Builds a list of Decidim::Scopes where the user could have a
|
89
|
+
# valid authorization.
|
90
|
+
#
|
91
|
+
# If the initiative is set with a global scope (meaning the scope is nil),
|
92
|
+
# all the scopes in the organization are valid.
|
93
|
+
#
|
94
|
+
# Returns an array of Decidim::Scopes.
|
95
|
+
def signature_scope_candidates
|
96
|
+
signature_scope_candidates = [initiative.scope]
|
97
|
+
signature_scope_candidates += if initiative.scope.present?
|
98
|
+
initiative.scope.descendants
|
99
|
+
else
|
100
|
+
initiative.organization.scopes
|
101
|
+
end
|
102
|
+
signature_scope_candidates.uniq
|
103
|
+
end
|
104
|
+
|
105
|
+
# Any data that the developer would like to inject to the `metadata` field
|
106
|
+
# of a vote when it is created. Can be useful if some of the params the
|
107
|
+
# user sent with the signature form want to be persisted for future use.
|
108
|
+
#
|
109
|
+
# Returns a Hash.
|
110
|
+
def metadata
|
111
|
+
{}
|
112
|
+
end
|
113
|
+
|
114
|
+
# Params to be sent to the authorization handler. By default consists on
|
115
|
+
# the metadata hash including the signer user
|
116
|
+
def authorization_handler_params
|
117
|
+
params = metadata.merge(user:)
|
118
|
+
params = params.merge(tos_agreement:) if ephemeral_tos_pending?
|
119
|
+
params
|
120
|
+
end
|
121
|
+
|
122
|
+
# The signature_scope_id can be defined in the signature workflow to be
|
123
|
+
# used by the author scope feature
|
124
|
+
def signature_scope_id
|
125
|
+
scope.id
|
126
|
+
end
|
127
|
+
|
128
|
+
def authorization_handler
|
129
|
+
return if authorization_handler_form_class.blank?
|
130
|
+
|
131
|
+
@authorization_handler ||= authorization_handler_form_class.from_params(authorization_handler_params)
|
132
|
+
end
|
133
|
+
|
134
|
+
def signature_workflow_name
|
135
|
+
@signature_workflow_name ||= initiative&.type&.document_number_authorization_handler
|
136
|
+
end
|
137
|
+
|
138
|
+
def hash_id
|
139
|
+
return unless initiative && (unique_id || user)
|
140
|
+
|
141
|
+
@hash_id ||= Digest::SHA256.hexdigest(
|
142
|
+
[
|
143
|
+
initiative.id,
|
144
|
+
unique_id || user.id,
|
145
|
+
Rails.application.secret_key_base
|
146
|
+
].compact.join("-")
|
147
|
+
)
|
148
|
+
end
|
149
|
+
|
150
|
+
# The attributes of the handler that should be exposed as form input when
|
151
|
+
# rendering the handler in a form.
|
152
|
+
#
|
153
|
+
# Returns an Array of Strings.
|
154
|
+
def form_attributes
|
155
|
+
attributes.except("id", "user", "initiative", "tos_agreement", "transfer_status").keys
|
156
|
+
end
|
157
|
+
|
158
|
+
# The String partial path so Rails can render the handler as a form. This
|
159
|
+
# is useful if you want to have a custom view to render the form instead of
|
160
|
+
# the default view.
|
161
|
+
#
|
162
|
+
# Example:
|
163
|
+
#
|
164
|
+
# A handler named Decidim::CensusHandler would look for its partial in:
|
165
|
+
# decidim/census/form
|
166
|
+
#
|
167
|
+
# Returns a String.
|
168
|
+
def to_partial_path
|
169
|
+
"decidim/initiatives/initiative_signatures/#{signature_workflow_name.sub(/_handler$/, "")}/form"
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.requires_extra_attributes?
|
173
|
+
new.form_attributes.present?
|
174
|
+
end
|
175
|
+
|
176
|
+
def already_voted?
|
177
|
+
Decidim::InitiativesVote.exists?(author: user, initiative:)
|
178
|
+
end
|
179
|
+
|
180
|
+
private
|
181
|
+
|
182
|
+
# It is expected to validate that no other user has voted with the same
|
183
|
+
# unique_id and scope. The unique_id should be defined by the classes
|
184
|
+
# inherited from this taking a personal data attribute like a document
|
185
|
+
# number. If not defined the user id is used
|
186
|
+
def uniqueness
|
187
|
+
add_invalid_base_error if Decidim::InitiativesVote.exists?(scope:, hash_id:)
|
188
|
+
end
|
189
|
+
|
190
|
+
def valid_metadata
|
191
|
+
return if authorization_handler_errors.blank?
|
192
|
+
|
193
|
+
keys = attributes.except("tos_agreement").keys.map(&:to_sym) & authorization_handler_errors.attribute_names
|
194
|
+
|
195
|
+
return if keys.blank? && authorization_handler_errors[:base].blank?
|
196
|
+
|
197
|
+
# Promote errors
|
198
|
+
if promote_authorization_validation_errors
|
199
|
+
keys.each do |attribute|
|
200
|
+
errors.add(attribute, authorization_handler_errors[attribute])
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
add_invalid_base_error
|
205
|
+
end
|
206
|
+
|
207
|
+
def tos_agreement_acceptance
|
208
|
+
return if (error_message = authorization_handler_errors[:tos_agreement]).blank?
|
209
|
+
|
210
|
+
errors.add(:tos_agreement, error_message)
|
211
|
+
end
|
212
|
+
|
213
|
+
def valid_authorized_scopes
|
214
|
+
return if authorized_scopes.present?
|
215
|
+
|
216
|
+
add_invalid_base_error
|
217
|
+
end
|
218
|
+
|
219
|
+
def add_invalid_base_error
|
220
|
+
errors.delete(:base)
|
221
|
+
errors.add(:base, I18n.t("invalid_data", scope: "decidim.initiatives.initiative_signatures.fill_personal_data"))
|
222
|
+
end
|
223
|
+
|
224
|
+
def encryptor
|
225
|
+
@encryptor ||= DataEncryptor.new(secret: Decidim::Initiatives.signature_handler_encryption_secret)
|
226
|
+
end
|
227
|
+
|
228
|
+
def workflow_manifest
|
229
|
+
@workflow_manifest ||= Decidim::Initiatives::Signatures.find_workflow_manifest(signature_workflow_name) || Decidim::Initiatives::SignatureWorkflowManifest.new
|
230
|
+
end
|
231
|
+
|
232
|
+
def ephemeral_tos_pending?
|
233
|
+
return unless ephemeral? && user.ephemeral?
|
234
|
+
|
235
|
+
!user.tos_accepted?
|
236
|
+
end
|
237
|
+
|
238
|
+
def authorization_handler_errors
|
239
|
+
@authorization_handler_errors ||= if authorization_handler.blank?
|
240
|
+
ActiveModel::Errors.new(nil)
|
241
|
+
else
|
242
|
+
authorization_handler.validate
|
243
|
+
authorization_handler.errors
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
@@ -21,7 +21,7 @@ module Decidim
|
|
21
21
|
# * published, discarded: Initiative authors will be notified about the
|
22
22
|
# result of the technical validation process.
|
23
23
|
#
|
24
|
-
# * rejected, accepted: Initiative
|
24
|
+
# * rejected, accepted: Initiative authors and committee members will be
|
25
25
|
# notified about the result of the initiative.
|
26
26
|
def notify
|
27
27
|
notify_initiative_creation if initiative.created?
|
@@ -58,12 +58,6 @@ module Decidim
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def notify_support_result
|
61
|
-
initiative.followers.each do |follower|
|
62
|
-
Decidim::Initiatives::InitiativesMailer
|
63
|
-
.notify_state_change(initiative, follower)
|
64
|
-
.deliver_later
|
65
|
-
end
|
66
|
-
|
67
61
|
initiative.committee_members.approved.each do |committee_member|
|
68
62
|
Decidim::Initiatives::InitiativesMailer
|
69
63
|
.notify_state_change(initiative, committee_member.user)
|
@@ -20,12 +20,12 @@
|
|
20
20
|
</div>
|
21
21
|
</div>
|
22
22
|
|
23
|
-
<div class="table-
|
23
|
+
<div class="table-stacked mt-4">
|
24
24
|
<table class="table-list">
|
25
25
|
<thead>
|
26
26
|
<tr>
|
27
27
|
<th><%= t "user", scope: "activemodel.attributes.initiatives_committee_member" %></th>
|
28
|
-
<th
|
28
|
+
<th><%= t "actions", scope: "decidim.admin.models.initiatives_committee_member.fields" %></th>
|
29
29
|
</tr>
|
30
30
|
</thead>
|
31
31
|
<tbody>
|
@@ -38,17 +38,35 @@
|
|
38
38
|
|
39
39
|
<% current_initiative.committee_members.each do |request| %>
|
40
40
|
<tr data-id="<%= request.id %>">
|
41
|
-
<td>
|
41
|
+
<td data-label="<%= t "user", scope: "activemodel.attributes.initiatives_committee_member" %>">
|
42
42
|
<%= link_to request.user.name, "mailto:#{request.user.email}" %>
|
43
43
|
</td>
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
44
|
+
|
45
|
+
<td class="table-list__actions" data-label="<%= t "actions", scope: "decidim.admin.models.initiatives_committee_member.fields" %>">
|
46
|
+
<button type="button" data-controller="dropdown" data-target="actions-initiative-committee-request-<%= request.id %>" aria-label="<%= t("decidim.admin.actions.actions_label", resource: request.user.name) %>">
|
47
|
+
<%= icon "more-fill", class: "text-secondary" %>
|
48
|
+
</button>
|
49
|
+
|
50
|
+
<div class="inline-block relative">
|
51
|
+
<ul id="actions-initiative-committee-request-<%= request.id %>" class="dropdown dropdown__action" aria-hidden="true">
|
52
|
+
<% if allowed_to? :approve, :initiative_committee_member, request: request %>
|
53
|
+
<li class="dropdown__item">
|
54
|
+
<%= link_to approve_initiative_committee_request_path(current_initiative, request), class: "dropdown__button" do %> <%= icon "check-line" %>
|
55
|
+
<%= t(".approve") %>
|
56
|
+
<% end %>
|
57
|
+
</li>
|
58
|
+
<% end %>
|
59
|
+
|
60
|
+
<% if allowed_to? :revoke, :initiative_committee_member, request: request %>
|
61
|
+
<li class="dropdown__item">
|
62
|
+
<%= link_to revoke_initiative_committee_request_path(current_initiative, request), method: :delete, data: { confirm: t(".confirm_revoke") }, class: "dropdown__button" do %>
|
63
|
+
<%= icon "delete-bin-line" %>
|
64
|
+
<%= t(".revoke") %>
|
65
|
+
<% end %>
|
66
|
+
</li>
|
67
|
+
<% end %>
|
68
|
+
</ul>
|
69
|
+
</div>
|
52
70
|
</td>
|
53
71
|
</tr>
|
54
72
|
<% end %>
|
@@ -1,25 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
data-auto-focus="true"
|
15
|
-
data-close-on-click="true">
|
16
|
-
<ul class="vertical menu add-components">
|
1
|
+
<% menu_id = "top-#{SecureRandom.uuid}" %>
|
2
|
+
<div class="relative">
|
3
|
+
<button class="button button__sm button__transparent-secondary" data-controller="dropdown" data-target="dropdown-exports-<%= menu_id %>-<%= dropdown_id(collection_ids) %>">
|
4
|
+
<% if collection_ids.present? %>
|
5
|
+
<%= t("actions.export-selection", scope: "decidim.admin") %>
|
6
|
+
<% else %>
|
7
|
+
<%= t("actions.export", scope: "decidim.admin") %>
|
8
|
+
<% end %>
|
9
|
+
<%= icon "arrow-down-s-line" %>
|
10
|
+
<%= icon "arrow-down-s-line" %>
|
11
|
+
</button>
|
12
|
+
|
13
|
+
<ul id="dropdown-exports-<%= menu_id %>-<%= dropdown_id(collection_ids) %>" class="dropdown dropdown__bottom" aria-hidden="true">
|
17
14
|
<% %w(CSV JSON).each do |format| %>
|
18
|
-
|
19
|
-
|
15
|
+
<li class="dropdown__item">
|
16
|
+
<%= link_to export_initiatives_path(format:, collection_ids:), class: "dropdown__button" do %>
|
20
17
|
<%= t("decidim.admin.exports.export_as", name: t("decidim.initiatives.admin.exports.initiatives"), export_format: format.upcase) %>
|
21
|
-
|
22
|
-
|
18
|
+
<% end %>
|
19
|
+
</li>
|
23
20
|
<% end %>
|
24
21
|
</ul>
|
25
22
|
</div>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<div class="form__wrapper">
|
2
|
-
<div class="card" data-
|
2
|
+
<div class="card" data-controller="accordion" id="accordion-title">
|
3
3
|
<div class="card-divider">
|
4
4
|
<button class="card-divider-button" data-open="true" data-controls="panel-title" type="button">
|
5
5
|
<%= icon "arrow-right-s-line" %>
|
@@ -17,16 +17,10 @@
|
|
17
17
|
<div class="row column">
|
18
18
|
<%= form.translated :editor, :description, lines: 8, disabled: !allowed_to?(:update, :initiative, initiative: current_initiative), aria: { label: :description } %>
|
19
19
|
</div>
|
20
|
-
|
21
|
-
<div class="row column">
|
22
|
-
<div class="columns">
|
23
|
-
<%= form.text_field :hashtag, disabled: !allowed_to?(:update, :initiative, initiative: current_initiative) %>
|
24
|
-
</div>
|
25
|
-
</div>
|
26
20
|
</div>
|
27
21
|
</div>
|
28
22
|
|
29
|
-
<div class="card" data-
|
23
|
+
<div class="card" data-controller="accordion" id="accordion-settings">
|
30
24
|
<div class="card-divider">
|
31
25
|
<button class="card-divider-button" data-open="true" data-controls="panel-settings" type="button">
|
32
26
|
<%= icon "arrow-right-s-line" %>
|
@@ -116,17 +110,17 @@
|
|
116
110
|
<% end %>
|
117
111
|
</div>
|
118
112
|
</div>
|
119
|
-
<div class="card" data-
|
113
|
+
<div class="card" data-controller="accordion" id="accordion-homepage_attachments">
|
120
114
|
<div class="card-divider">
|
121
|
-
<button class="card-divider-button" data-open="true" data-controls="panel-
|
115
|
+
<button class="card-divider-button" data-open="true" data-controls="panel-homepage_attachments" type="button">
|
122
116
|
<%= icon "arrow-right-s-line" %>
|
123
|
-
<h2 class="card-title" id="
|
124
|
-
<%= t("
|
117
|
+
<h2 class="card-title" id="homepage_attachments">
|
118
|
+
<%= t(".attachments_title") %>
|
125
119
|
</h2>
|
126
120
|
</button>
|
127
121
|
</div>
|
128
122
|
|
129
|
-
<div id="panel-
|
123
|
+
<div id="panel-homepage_attachments" class="card-section">
|
130
124
|
<div class="row">
|
131
125
|
<% if allowed_to?(:read, :attachment, initiative: current_participatory_space) %>
|
132
126
|
<%= render partial: "initiative_attachments", locals: { current_initiative:, current_participatory_space: } %>
|
@@ -31,10 +31,10 @@
|
|
31
31
|
<% if allowed_to?(:update, :initiative, initiative: current_initiative) %>
|
32
32
|
<%= aria_selected_link_to t(".edit"),
|
33
33
|
decidim_admin_initiatives.initiative_attachments_path(current_participatory_space),
|
34
|
-
class: "button button__sm
|
34
|
+
class: "button button__sm button__transparent-secondary" %>
|
35
35
|
<%= aria_selected_link_to t(".new"),
|
36
36
|
decidim_admin_initiatives.new_initiative_attachment_path(current_participatory_space),
|
37
|
-
class: "button button__sm
|
37
|
+
class: "button button__sm button__transparent-secondary" %>
|
38
38
|
<% else %>
|
39
39
|
<%= link_to t(".edit"), "#", class: "button button__sm button__secondary muted disabled" %>
|
40
40
|
<%= link_to t(".new"), "#", class: "button button__sm button__secondary muted disabled" %>
|
@@ -15,7 +15,7 @@
|
|
15
15
|
<% link = link_to(t("button", scope:"decidim.initiatives.admin.index.initiatives_types"), new_initiatives_type_path, class: "button button__sm button__secondary mt-4") %>
|
16
16
|
<%= cell("decidim/announcement", t("alert_html", scope:"decidim.initiatives.admin.index.initiatives_types", link:), callout_class: "alert") %>
|
17
17
|
<% else %>
|
18
|
-
<div class="table-
|
18
|
+
<div class="table-stacked">
|
19
19
|
<table class="table-list">
|
20
20
|
<thead>
|
21
21
|
<tr>
|
@@ -31,8 +31,8 @@
|
|
31
31
|
<tbody>
|
32
32
|
<% @initiatives.each do |initiative| %>
|
33
33
|
<tr>
|
34
|
-
<td><%= initiative.id %></td>
|
35
|
-
<td class="!text-left">
|
34
|
+
<td data-label="<%= t("models.initiatives.fields.id", scope: "decidim.admin") %>"><%= initiative.id %></td>
|
35
|
+
<td class="!text-left" data-label="<%= t("models.initiatives.fields.title", scope: "decidim.admin") %>">
|
36
36
|
<% if allowed_to? :edit, :initiative, initiative: initiative %>
|
37
37
|
<%= link_to translated_attribute(initiative.title),
|
38
38
|
decidim_admin_initiatives.edit_initiative_path(initiative.to_param) %>
|
@@ -40,56 +40,85 @@
|
|
40
40
|
<%= translated_attribute(initiative.title) %>
|
41
41
|
<% end %>
|
42
42
|
</td>
|
43
|
-
<td><%= humanize_admin_state initiative.state %></td>
|
44
|
-
<td><%= initiative.supports_count %>/<%= initiative.scoped_type.supports_required %></td>
|
45
|
-
<td class="table-list__date"><%= l initiative.created_at, format: :short %></td>
|
46
|
-
<td class="table-list__date"><%= initiative.published_at? ? l(initiative.published_at, format: :short) : "" %></td>
|
47
|
-
<td class="table-list__actions">
|
43
|
+
<td data-label="<%= t("models.initiatives.fields.state", scope: "decidim.admin") %>"><%= humanize_admin_state initiative.state %></td>
|
44
|
+
<td data-label="<%= t("models.initiatives.fields.supports_count", scope: "decidim.admin") %>"><%= initiative.supports_count %>/<%= initiative.scoped_type.supports_required %></td>
|
45
|
+
<td class="table-list__date" data-label="<%= t("models.initiatives.fields.created_at", scope: "decidim.admin") %>"><%= l initiative.created_at, format: :short %></td>
|
46
|
+
<td class="table-list__date" data-label="<%= t("models.initiatives.fields.published_at", scope: "decidim.admin") %>"><%= initiative.published_at? ? l(initiative.published_at, format: :short) : "" %></td>
|
47
|
+
<td class="table-list__actions" data-label="<%= t(".actions_title") %>">
|
48
|
+
<button type="button" data-controller="dropdown" data-target="actions-initiative-<%= initiative.id %>" aria-label="<%= t("decidim.admin.actions.actions_label", resource: translated_attribute(initiative.title)) %>">
|
49
|
+
<%= icon "more-fill", class: "text-secondary" %>
|
50
|
+
</button>
|
48
51
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
<div class="inline-block relative">
|
53
|
+
<ul id="actions-initiative-<%= initiative.id %>" class="dropdown dropdown__action" aria-hidden="true">
|
54
|
+
<% if allowed_to? :edit, :initiative, initiative: initiative %>
|
55
|
+
<li class="dropdown__item">
|
56
|
+
<%= link_to decidim_admin_initiatives.edit_initiative_path(initiative.to_param), class: "dropdown__button" do %>
|
57
|
+
<%= icon "pencil-line" %>
|
58
|
+
<%= t("actions.edit", scope: "decidim.admin") %>
|
59
|
+
<% end %>
|
60
|
+
</li>
|
61
|
+
<% end %>
|
54
62
|
|
55
|
-
|
56
|
-
<%= icon_link_to "pencil-line",
|
57
|
-
decidim_admin_initiatives.edit_initiative_path(initiative.to_param),
|
58
|
-
t("actions.configure", scope: "decidim.admin"),
|
59
|
-
class: "action-icon--edit" %>
|
60
|
-
<% else %>
|
61
|
-
<span class="action-space icon"></span>
|
62
|
-
<% end %>
|
63
|
+
<hr>
|
63
64
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
65
|
+
<% if allowed_to?(:answer, :initiative, initiative: initiative) %>
|
66
|
+
<li class="dropdown__item">
|
67
|
+
<%= link_to edit_initiative_answer_path(initiative.slug), class: "dropdown__button" do %>
|
68
|
+
<%= icon "chat-1-line" %>
|
69
|
+
<%= t("actions.answer", scope: "decidim.initiatives") %>
|
70
|
+
<% end %>
|
71
|
+
</li>
|
72
|
+
<% else %>
|
73
|
+
<li class="dropdown__item">
|
74
|
+
<div class="dropdown__button-disabled">
|
75
|
+
<%= with_tooltip(t("actions.cannot_answer", scope: "decidim.admin")) do %>
|
76
|
+
<%= icon "chat-1-line", class: "text-gray" %>
|
77
|
+
<span><%= t("actions.answer", scope: "decidim.initiatives") %></span>
|
78
|
+
<% end %>
|
79
|
+
</div>
|
80
|
+
</li>
|
81
|
+
<% end %>
|
69
82
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
<span class="action-space icon"></span>
|
79
|
-
<% end %>
|
83
|
+
<% if allowed_to? :print, :initiative, initiative: initiative %>
|
84
|
+
<li class="dropdown__item">
|
85
|
+
<%= link_to decidim_initiatives.print_initiative_path(initiative), class: "dropdown__button", target: "_blank", data: { "external-link": false } do %>
|
86
|
+
<%= icon "printer-line" %>
|
87
|
+
<%= t(".print") %>
|
88
|
+
<% end %>
|
89
|
+
</li>
|
90
|
+
<% end %>
|
80
91
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
92
|
+
<hr>
|
93
|
+
|
94
|
+
<% if allowed_to? :preview, :initiative, initiative: initiative %>
|
95
|
+
<li class="dropdown__item">
|
96
|
+
<%= link_to decidim_initiatives.initiative_path(initiative.to_param), class: "dropdown__button", target: "_blank", data: { "external-link": false } do %>
|
97
|
+
<%= icon "eye-line" %>
|
98
|
+
<%= t(".preview") %>
|
99
|
+
<% end %>
|
100
|
+
</li>
|
101
|
+
<% end %>
|
102
|
+
|
103
|
+
<% if allowed_to? :read, :share_token, current_participatory_space: initiative %>
|
104
|
+
<li class="dropdown__item">
|
105
|
+
<%= link_to decidim_admin_initiatives.initiative_share_tokens_path(initiative), class: "dropdown__button" do %>
|
106
|
+
<%= icon "share-line" %>
|
107
|
+
<%= t("actions.share_tokens", scope: "decidim.admin") %>
|
108
|
+
<% end %>
|
109
|
+
</li>
|
110
|
+
|
111
|
+
<hr>
|
112
|
+
<% end %>
|
113
|
+
|
114
|
+
<% if (link = free_resource_permissions_link(initiative)) %>
|
115
|
+
<li class="dropdown__item">
|
116
|
+
<%= link %>
|
117
|
+
</li>
|
118
|
+
<% end %>
|
119
|
+
</ul>
|
120
|
+
</div>
|
91
121
|
|
92
|
-
<%= free_resource_permissions_link(initiative) || content_tag(:span, nil, class: "action-space icon") %>
|
93
122
|
</td>
|
94
123
|
</tr>
|
95
124
|
<% end %>
|