decidim-initiatives 0.30.2 → 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 +1 -4
- 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 +99 -51
- 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 +99 -51
- 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/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
@@ -22,6 +22,7 @@ module Decidim
|
|
22
22
|
|
23
23
|
resources :create_initiative do
|
24
24
|
collection do
|
25
|
+
get :load_initiative_draft
|
25
26
|
get :select_initiative_type
|
26
27
|
put :select_initiative_type, to: "create_initiative#store_initiative_type"
|
27
28
|
get :fill_data
|
@@ -60,6 +61,7 @@ module Decidim
|
|
60
61
|
get :authorization_create_modal, to: "authorization_create_modals#show"
|
61
62
|
get :print, to: "initiatives#print", as: "print"
|
62
63
|
get :send_to_technical_validation, to: "initiatives#send_to_technical_validation"
|
64
|
+
delete :discard, to: "initiatives#discard"
|
63
65
|
end
|
64
66
|
|
65
67
|
resource :initiative_vote, only: [:create, :destroy]
|
@@ -99,6 +101,15 @@ module Decidim
|
|
99
101
|
Decidim.icons.register(name: "forbid-line", icon: "forbid-line", category: "system", description: "", engine: :initiatives)
|
100
102
|
end
|
101
103
|
|
104
|
+
initializer "decidim_initiatives.stats" do
|
105
|
+
Decidim.stats.register :initiatives_count,
|
106
|
+
priority: StatsRegistry::HIGH_PRIORITY,
|
107
|
+
icon_name: "lightbulb-flash-line",
|
108
|
+
tooltip_key: "initiatives_count_tooltip" do |organization, _start_at, _end_at|
|
109
|
+
Decidim::Initiative.where(organization:).public_spaces.count
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
102
113
|
initializer "decidim_initiatives.content_blocks" do
|
103
114
|
Decidim::Initiatives::ContentBlocks::RegistryManager.register!
|
104
115
|
end
|
@@ -118,20 +129,12 @@ module Decidim
|
|
118
129
|
Decidim::Gamification.register_badge(:initiatives) do |badge|
|
119
130
|
badge.levels = [1, 5, 15, 30, 50]
|
120
131
|
|
121
|
-
badge.valid_for = [:user
|
132
|
+
badge.valid_for = [:user]
|
122
133
|
|
123
134
|
badge.reset = lambda { |model|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
author: model,
|
128
|
-
user_group: nil
|
129
|
-
).published.count
|
130
|
-
when UserGroup
|
131
|
-
Decidim::Initiative.where(
|
132
|
-
user_group: model
|
133
|
-
).published.count
|
134
|
-
end
|
135
|
+
Decidim::Initiative.where(
|
136
|
+
author: model
|
137
|
+
).published.count
|
135
138
|
}
|
136
139
|
end
|
137
140
|
end
|
@@ -140,7 +143,7 @@ module Decidim
|
|
140
143
|
Decidim::Api::QueryType.include QueryExtensions
|
141
144
|
end
|
142
145
|
|
143
|
-
initializer "decidim_initiatives.
|
146
|
+
initializer "decidim_initiatives.shakapacker.assets_path" do
|
144
147
|
Decidim.register_assets_path File.expand_path("app/packs", root)
|
145
148
|
end
|
146
149
|
|
@@ -149,7 +152,7 @@ module Decidim
|
|
149
152
|
# We need to make sure we call `Preview.all` before requiring our
|
150
153
|
# previews, otherwise any previews the app attempts to add need to be
|
151
154
|
# manually required.
|
152
|
-
if Rails.env.
|
155
|
+
if Rails.env.local?
|
153
156
|
ActionMailer::Preview.all
|
154
157
|
|
155
158
|
Dir[root.join("spec/mailers/previews/**/*_preview.rb")].each do |file|
|
@@ -32,7 +32,21 @@ Decidim.register_participatory_space(:initiatives) do |participatory_space|
|
|
32
32
|
|
33
33
|
participatory_space.register_resource(:initiatives_type) do |resource|
|
34
34
|
resource.model_class_name = "Decidim::InitiativesType"
|
35
|
-
resource.actions = %w(
|
35
|
+
resource.actions = %w(create)
|
36
|
+
end
|
37
|
+
|
38
|
+
participatory_space.register_stat :followers_count,
|
39
|
+
priority: Decidim::StatsRegistry::MEDIUM_PRIORITY,
|
40
|
+
icon_name: "user-follow-line",
|
41
|
+
tooltip_key: "followers_count_tooltip" do
|
42
|
+
Decidim::Initiatives::InitiativesStatsFollowersCount.for(participatory_space)
|
43
|
+
end
|
44
|
+
|
45
|
+
participatory_space.register_stat :participants_count,
|
46
|
+
priority: Decidim::StatsRegistry::MEDIUM_PRIORITY,
|
47
|
+
icon_name: "user-line",
|
48
|
+
tooltip_key: "participants_count_tooltip" do
|
49
|
+
Decidim::Initiatives::InitiativesStatsParticipantsCount.for(participatory_space)
|
36
50
|
end
|
37
51
|
|
38
52
|
participatory_space.model_class_name = "Decidim::Initiative"
|
@@ -9,7 +9,7 @@ module Decidim
|
|
9
9
|
def call
|
10
10
|
create_content_block!
|
11
11
|
|
12
|
-
|
12
|
+
number_of_records.times do |_n|
|
13
13
|
type = create_initiative_type!
|
14
14
|
|
15
15
|
organization.top_scopes.each do |scope|
|
@@ -19,7 +19,6 @@ module Decidim
|
|
19
19
|
|
20
20
|
Decidim::Initiative.states.keys.each do |state|
|
21
21
|
Decidim::Initiative.skip_callback(:save, :after, :notify_state_change, raise: false)
|
22
|
-
Decidim::Initiative.skip_callback(:create, :after, :notify_creation, raise: false)
|
23
22
|
|
24
23
|
initiative = create_initiative!(state:)
|
25
24
|
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# require "decidim/settings_manifest"
|
4
|
+
require "decidim/initiatives/default_signature_authorizer"
|
5
|
+
|
6
|
+
module Decidim
|
7
|
+
module Initiatives
|
8
|
+
# This class serves as a DSL to declaratively specify a signature method.
|
9
|
+
#
|
10
|
+
# To define a direct signature method, you need to specify the `form`
|
11
|
+
# attribute as a `Decidim::Form` that will be valid if the signature
|
12
|
+
# process is valid. If no form is provided the application assumes that the
|
13
|
+
# form class is `Decidim::Initiatives::SignatureHandler`
|
14
|
+
#
|
15
|
+
# All the attributes except the name are optional. If no attributes are set
|
16
|
+
# there are default values for them and the signature flow will be direct
|
17
|
+
# without steps and metadata stored in the initiatives_vote
|
18
|
+
#
|
19
|
+
# Signature workflow attributes:
|
20
|
+
# - :form (String) (optional) The name of the form object class responsible
|
21
|
+
# for collecting and validating the data to create the initiative votes.
|
22
|
+
# This class should be inherited from
|
23
|
+
# Decidim::Initiatives::SignatureHandler and can define a set of
|
24
|
+
# attributes to collect user personal data. If extra attributes are
|
25
|
+
# defined a collect personal data step will be enabled. This class also
|
26
|
+
# can define an unique_id to avoid duplicated votes based on the
|
27
|
+
# personal data and a metadata hash that will be encrypted in the vote
|
28
|
+
# creation. The class can also collect a hash of metadata that will be
|
29
|
+
# passed to an authorization handler if defined in the workflow. The
|
30
|
+
# class is also responsible to define the scopes associated with the
|
31
|
+
# votes. The main class by default detects the scopes candidates and
|
32
|
+
# the inherited class can define a signature_scope_id based on the data
|
33
|
+
# provided by the user.
|
34
|
+
# (default: "Decidim::Initiatives::SignatureHandler")
|
35
|
+
# - :authorization_handler_form (String) (optional) If this authorization
|
36
|
+
# handler class name is set the previous form will create and validate
|
37
|
+
# an instance of it from the params defined in it (by default the
|
38
|
+
# collected metadata and the user). If the authorization is invalid the
|
39
|
+
# signature is blocked. (default: nil)
|
40
|
+
# - :save_authorizations (Boolean) (optional) This option allows the
|
41
|
+
# workflow to save or update if already exist the authorization
|
42
|
+
# associated to the previous authorization handler. Note that if this
|
43
|
+
# option is set to false the user will be required to have been
|
44
|
+
# previously authorized with the method associated to the authorization
|
45
|
+
# handler. The authorization is searched by the organization, the user
|
46
|
+
# and the authorization handler name. If this class is not defined,
|
47
|
+
# class Decidim::Initiatives::DefaultSignatureAuthorizer is used,
|
48
|
+
# which inherits from Decidim::Verifications::DefaultActionAuthorizer
|
49
|
+
# and checks the authorization status. (default: true)
|
50
|
+
# - :ephemeral (Boolean) (optional) This option enables the possibility for
|
51
|
+
# users to sign without prior registration through an ephemeral session.
|
52
|
+
# To allow ephemeral sessions to be recovered o transferred to regular
|
53
|
+
# users authorizations must be stored in the process so an
|
54
|
+
# authorization_handler_form must be defined and the save_authorizations
|
55
|
+
# option must not be set to false. If those settings are not properly
|
56
|
+
# configured this option will be ignored and the workflow will not
|
57
|
+
# allow ephemeral sessions. (default: false)
|
58
|
+
# - :promote_authorization_validation_errors (Boolean) (optional) If set
|
59
|
+
# to true, errors in the personal data passed to the authorization
|
60
|
+
# handler form will be displayed next to the corresponding fields
|
61
|
+
# in the collection of personal data. Note that this option may provide
|
62
|
+
# information about personal data to the user. (default: false)
|
63
|
+
# - :action_authorizer (String) This is the name of the action authorizer
|
64
|
+
# class responsible for checking the status of the authorization
|
65
|
+
# associated to the signature. If this class is not defined, the
|
66
|
+
# authorization status will be ignored. You can define a handler
|
67
|
+
# inherited from Decidim::Initiatives::DefaultSignatureAuthorizer which
|
68
|
+
# inherits from Decidim::Verifications::DefaultActionAuthorizer and
|
69
|
+
# checks the authorization status with an instance initialized only
|
70
|
+
# with the authorization (without a component or a resource).
|
71
|
+
# (default: nil)
|
72
|
+
# - :sms_verification (Boolean) (optional) This option enables an
|
73
|
+
# additional SMS verification step. It uses by default the sms
|
74
|
+
# verification flow defined in decidim_verifications and expects the
|
75
|
+
# user to have previously created an SMS authorization validating
|
76
|
+
# their phone number. This behaviour can be changed defining the
|
77
|
+
# following attributes. (default: false)
|
78
|
+
# - :sms_mobile_phone_form_class (String) (optional) The name of the class
|
79
|
+
# responsible for starting the users phone verification. It uses the
|
80
|
+
# default form defined in decidim_initiatives.
|
81
|
+
# (default: "Decidim::Verifications::Sms::MobilePhoneForm")
|
82
|
+
# - :sms_mobile_phone_validator (String) (optional) The name of the command
|
83
|
+
# class responsible for checking if the mobile phone provided by the
|
84
|
+
# user has an authorization associated to the sms_mobile_form_class
|
85
|
+
# and delivering the sms code
|
86
|
+
# (default: "Decidim::Initiatives::ValidateMobilePhone")
|
87
|
+
# - :sms_code_validator_class (String) (optional) The name of the command
|
88
|
+
# class responsible for checking if the SMS code provided by the user
|
89
|
+
# is valid. (default: "Decidim::Initiatives::ValidateSmsCode")
|
90
|
+
#
|
91
|
+
# An example of declaration of a workflow:
|
92
|
+
#
|
93
|
+
# Decidim::Initiatives::Signatures.register_workflow(:dummy_signature_handler) do |workflow|
|
94
|
+
# workflow.form = "DummySignatureHandler"
|
95
|
+
# workflow.authorization_handler_form = "DummyAuthorizationHandler"
|
96
|
+
# workflow.action_authorizer = "DummySignatureHandler::DummySignatureActionAuthorizer"
|
97
|
+
# workflow.promote_authorization_validation_errors = true
|
98
|
+
# workflow.sms_verification = true
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
class SignatureWorkflowManifest
|
102
|
+
include ActiveModel::Model
|
103
|
+
include Decidim::AttributeObject::Model
|
104
|
+
|
105
|
+
attribute :name, String
|
106
|
+
attribute :form, String
|
107
|
+
attribute :authorization_handler_form, String, default: nil
|
108
|
+
attribute :action_authorizer, String
|
109
|
+
attribute :save_authorizations, Boolean, default: true
|
110
|
+
attribute :promote_authorization_validation_errors, Boolean, default: false
|
111
|
+
attribute :ephemeral, Boolean, default: false
|
112
|
+
attribute :sms_verification, Boolean, default: false
|
113
|
+
attribute :sms_mobile_phone_form, String, default: nil
|
114
|
+
attribute :sms_mobile_phone_validator, String, default: nil
|
115
|
+
attribute :sms_code_validator, String, default: nil
|
116
|
+
|
117
|
+
validates :name, presence: true
|
118
|
+
validate :ephemeral_configuration
|
119
|
+
|
120
|
+
alias key name
|
121
|
+
|
122
|
+
def fullname
|
123
|
+
I18n.t("#{key}.name", scope: "decidim.signature_workflows", default: name.humanize)
|
124
|
+
end
|
125
|
+
|
126
|
+
def signature_form_class
|
127
|
+
form&.safe_constantize || Decidim::Initiatives::SignatureHandler
|
128
|
+
end
|
129
|
+
|
130
|
+
def action_authorizer_class
|
131
|
+
return if action_authorizer.blank?
|
132
|
+
|
133
|
+
action_authorizer.safe_constantize || DefaultSignatureAuthorizer
|
134
|
+
end
|
135
|
+
|
136
|
+
def authorization_handler_form_class
|
137
|
+
authorization_handler_form&.safe_constantize
|
138
|
+
end
|
139
|
+
|
140
|
+
# If no authorization handler is set or the save_authorizations option
|
141
|
+
# is disabled the workflow will not be able to save the user verification
|
142
|
+
# attributes necessary to recover the user session or transfer their
|
143
|
+
# activities
|
144
|
+
def ephemeral?
|
145
|
+
return if authorization_handler_form_class.blank? || !save_authorizations
|
146
|
+
|
147
|
+
ephemeral
|
148
|
+
end
|
149
|
+
|
150
|
+
def sms_mobile_phone_form_class
|
151
|
+
return unless sms_verification
|
152
|
+
|
153
|
+
sms_mobile_phone_form&.safe_constantize || Decidim::Verifications::Sms::MobilePhoneForm
|
154
|
+
end
|
155
|
+
|
156
|
+
def sms_mobile_phone_validator_class
|
157
|
+
return unless sms_verification
|
158
|
+
|
159
|
+
sms_mobile_phone_validator&.safe_constantize || Decidim::Initiatives::ValidateMobilePhone
|
160
|
+
end
|
161
|
+
|
162
|
+
def sms_code_validator_class
|
163
|
+
return unless sms_verification
|
164
|
+
|
165
|
+
sms_code_validator&.safe_constantize || Decidim::Initiatives::ValidateSmsCode
|
166
|
+
end
|
167
|
+
|
168
|
+
def ephemeral_configuration
|
169
|
+
return unless Rails.env.development?
|
170
|
+
return unless ephemeral
|
171
|
+
|
172
|
+
raise StandardError, "Wrong configuration of ephemeral signature workflow #{fullname}" if !save_authorizations || authorization_handler_form.blank?
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Initiatives
|
5
|
+
module Signatures
|
6
|
+
autoload :SignatureWorkflowManifest, "decidim/initiatives/signature_workflow_manifest"
|
7
|
+
include Decidim::HasWorkflows
|
8
|
+
|
9
|
+
def self.workflow_manifest_class = SignatureWorkflowManifest
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -84,13 +84,17 @@ FactoryBot.define do
|
|
84
84
|
end
|
85
85
|
|
86
86
|
trait :with_user_extra_fields_collection do
|
87
|
-
collect_user_extra_fields { true }
|
88
87
|
extra_fields_legal_information { generate_localized_description(:initiatives_type_extra_fields_legal_information, skip_injection:) }
|
89
|
-
document_number_authorization_handler { "
|
88
|
+
document_number_authorization_handler { "dummy_signature_with_personal_data_handler" }
|
90
89
|
end
|
91
90
|
|
92
91
|
trait :with_sms_code_validation do
|
93
|
-
|
92
|
+
document_number_authorization_handler { "dummy_signature_with_sms_handler" }
|
93
|
+
end
|
94
|
+
|
95
|
+
trait :with_sms_code_validation_and_user_extra_fields_collection do
|
96
|
+
extra_fields_legal_information { generate_localized_description(:initiatives_type_extra_fields_legal_information, skip_injection:) }
|
97
|
+
document_number_authorization_handler { "dummy_signature_handler" }
|
94
98
|
end
|
95
99
|
|
96
100
|
trait :child_scope_threshold_enabled do
|
@@ -268,10 +272,6 @@ FactoryBot.define do
|
|
268
272
|
end
|
269
273
|
initiative { create(:initiative, skip_injection:) }
|
270
274
|
author { create(:user, :confirmed, organization: initiative.organization, skip_injection:) }
|
271
|
-
decidim_user_group_id { create(:user_group, skip_injection:).id }
|
272
|
-
after(:create) do |support, evaluator|
|
273
|
-
create(:user_group_membership, user: support.author, user_group: Decidim::UserGroup.find(support.decidim_user_group_id), skip_injection: evaluator.skip_injection)
|
274
|
-
end
|
275
275
|
end
|
276
276
|
|
277
277
|
factory :initiatives_committee_member, class: "Decidim::InitiativesCommitteeMember" do
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Initiatives
|
5
|
+
module InitiativesSignaturesTestHelpers
|
6
|
+
def fill_signature_date(date)
|
7
|
+
[date.year, date.month, date.day].each_with_index do |value, i|
|
8
|
+
within "select[name='dummy_signature_handler[date_of_birth(#{i + 1}i)]']" do
|
9
|
+
find("option[value='#{value}']").select_option
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec.configure do |config|
|
18
|
+
config.include Decidim::Initiatives::InitiativesSignaturesTestHelpers, type: :system
|
19
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Initiatives
|
5
|
+
# Concern to search for authorizations or try to create them and
|
6
|
+
# validate their status. If the authorization cannot be created and the
|
7
|
+
# workflow sets save_authorizations to false a new invalid authorization is
|
8
|
+
# used. This validation is not performed if no action_authorizer class name
|
9
|
+
# is set in the workflow.
|
10
|
+
module ValidatableAuthorizations
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
validate :valid_authorization
|
15
|
+
|
16
|
+
delegate :action_authorizer, :save_authorizations, :action_authorizer_class, to: :workflow_manifest
|
17
|
+
|
18
|
+
def authorization_status
|
19
|
+
return unless authorization && action_authorizer_class
|
20
|
+
|
21
|
+
@authorization_status ||= action_authorizer_class.new(authorization, {}).authorize
|
22
|
+
end
|
23
|
+
|
24
|
+
def authorization
|
25
|
+
return unless user && authorization_handler_form_class
|
26
|
+
|
27
|
+
persisted_authorization = authorization_query.first
|
28
|
+
@authorization ||= if persisted_authorization.present? && persisted_authorization.unique_id == authorization_handler.unique_id
|
29
|
+
persisted_authorization
|
30
|
+
elsif save_authorizations
|
31
|
+
create_authorization
|
32
|
+
else
|
33
|
+
new_authorization
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def valid_authorization
|
40
|
+
return if authorization_status.blank?
|
41
|
+
return if authorization_status.first == :ok
|
42
|
+
|
43
|
+
errors.add(:base, I18n.t("invalid_authorization", scope: "decidim.initiatives.initiative_signatures.fill_personal_data"))
|
44
|
+
end
|
45
|
+
|
46
|
+
def create_authorization
|
47
|
+
Decidim::Verifications::AuthorizeUser.call(authorization_handler, initiative.organization) do
|
48
|
+
on(:transferred) do |transfer|
|
49
|
+
self.transfer_status = transfer
|
50
|
+
end
|
51
|
+
|
52
|
+
on(:transfer_user) do |authorized_user|
|
53
|
+
self.user = authorized_user
|
54
|
+
self.transfer_status = :transfer_user
|
55
|
+
end
|
56
|
+
|
57
|
+
on(:invalid) do
|
58
|
+
return Decidim::Authorization.new
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
authorization_query.first
|
63
|
+
end
|
64
|
+
|
65
|
+
def authorization_query
|
66
|
+
Verifications::Authorizations.new(**authorization_params)
|
67
|
+
end
|
68
|
+
|
69
|
+
def new_authorization
|
70
|
+
Decidim::Authorization.new(created_at: Time.current, **authorization_params)
|
71
|
+
end
|
72
|
+
|
73
|
+
def authorization_params
|
74
|
+
{
|
75
|
+
organization: initiative.organization,
|
76
|
+
user:,
|
77
|
+
name: authorization_handler_form_class.handler_name
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/decidim/initiatives.rb
CHANGED
@@ -5,6 +5,7 @@ require "decidim/initiatives/api"
|
|
5
5
|
require "decidim/initiatives/engine"
|
6
6
|
require "decidim/initiatives/admin_engine"
|
7
7
|
require "decidim/initiatives/participatory_space"
|
8
|
+
require "decidim/initiatives/signatures"
|
8
9
|
|
9
10
|
module Decidim
|
10
11
|
module Exporters
|
@@ -14,79 +15,89 @@ module Decidim
|
|
14
15
|
# Base module for the initiatives engine.
|
15
16
|
module Initiatives
|
16
17
|
autoload :ApplicationFormPDF, "decidim/initiatives/application_form_pdf"
|
18
|
+
autoload :ValidatableAuthorizations, "decidim/initiatives/validatable_authorizations"
|
17
19
|
|
18
20
|
include ActiveSupport::Configurable
|
19
21
|
|
20
22
|
# Public setting that defines whether creation is allowed to any validated
|
21
23
|
# user or not. Defaults to true.
|
22
24
|
config_accessor :creation_enabled do
|
23
|
-
|
25
|
+
Decidim::Env.new("INITIATIVES_CREATION_ENABLED", "auto").present?
|
24
26
|
end
|
25
27
|
|
26
28
|
# Minimum number of committee members required to pass the initiative to
|
27
29
|
# technical validation phase. Only applies to initiatives created by
|
28
30
|
# individuals.
|
29
31
|
config_accessor :minimum_committee_members do
|
30
|
-
2
|
32
|
+
Decidim::Env.new("INITIATIVES_MINIMUM_COMMITTEE_MEMBERS", 2).to_i
|
31
33
|
end
|
32
34
|
|
33
35
|
# Number of days available to collect supports after an initiative has been
|
34
36
|
# published.
|
35
37
|
config_accessor :default_signature_time_period_length do
|
36
|
-
120
|
38
|
+
Decidim::Env.new("INITIATIVES_DEFAULT_SIGNATURE_TIME_PERIOD_LENGTH", 120).to_i
|
37
39
|
end
|
38
40
|
|
39
41
|
# Components enabled for a new initiative
|
40
42
|
config_accessor :default_components do
|
41
|
-
|
43
|
+
Decidim::Env.new("INITIATIVES_DEFAULT_COMPONENTS", "pages, meetings, blogs").to_array
|
42
44
|
end
|
43
45
|
|
44
46
|
# Notifies when the given percentage of supports is reached for an
|
45
47
|
# initiative.
|
46
48
|
config_accessor :first_notification_percentage do
|
47
|
-
33
|
49
|
+
Decidim::Env.new("INITIATIVES_FIRST_NOTIFICATION_PERCENTAGE", 33).to_i
|
48
50
|
end
|
49
51
|
|
50
52
|
# Notifies when the given percentage of supports is reached for an
|
51
53
|
# initiative.
|
52
54
|
config_accessor :second_notification_percentage do
|
53
|
-
66
|
55
|
+
Decidim::Env.new("INITIATIVES_SECOND_NOTIFICATION_PERCENTAGE", 66).to_i
|
54
56
|
end
|
55
57
|
|
56
58
|
# Sets the expiration time for the statistic data.
|
57
59
|
config_accessor :stats_cache_expiration_time do
|
58
|
-
5.minutes
|
60
|
+
Decidim::Env.new("INITIATIVES_STATS_CACHE_EXPIRATION_TIME", 5).to_i.minutes
|
59
61
|
end
|
60
62
|
|
61
63
|
# Maximum amount of time in validating state.
|
62
64
|
# After this time the initiative will be moved to
|
63
65
|
# discarded state.
|
64
66
|
config_accessor :max_time_in_validating_state do
|
65
|
-
60.days
|
67
|
+
Decidim::Env.new("INITIATIVES_MAX_TIME_IN_VALIDATING_STATE", 60).to_i.days
|
66
68
|
end
|
67
69
|
|
68
70
|
# Print functionality enabled. Allows the user to get
|
69
71
|
# a printed version of the initiative from the administration
|
70
72
|
# panel.
|
71
73
|
config_accessor :print_enabled do
|
72
|
-
|
74
|
+
Decidim::Env.new("INITIATIVES_PRINT_ENABLED", "auto").to_s == "true"
|
73
75
|
end
|
74
76
|
|
75
77
|
# Set a service to generate a timestamp on each vote. The
|
76
78
|
# attribute is the name of a class whose instances are
|
77
79
|
# initialized with a string containing the data to be
|
78
80
|
# timestamped and respond to a timestamp method
|
79
|
-
config_accessor :timestamp_service
|
81
|
+
config_accessor :timestamp_service do
|
82
|
+
Decidim::Env.new("DECIDIM_TIMESTAMP_SERVICE", nil).value
|
83
|
+
end
|
80
84
|
|
81
85
|
# Set a service to add a signature to pdf of signatures.
|
82
86
|
# The attribute is the name of a class whose instances are
|
83
87
|
# initialized with the document to be signed and respond to a
|
84
88
|
# signed_pdf method with the signature added
|
85
|
-
config_accessor :pdf_signature_service
|
89
|
+
config_accessor :pdf_signature_service do
|
90
|
+
Decidim::Env.new("DECIDIM_PDF_SIGNATURE_SERVICE", nil).value
|
91
|
+
end
|
86
92
|
|
87
93
|
# This flag allows creating authorizations to unauthorized users.
|
88
94
|
config_accessor :do_not_require_authorization do
|
89
|
-
|
95
|
+
Decidim::Env.new("INITIATIVES_DO_NOT_REQUIRE_AUTHORIZATION").present?
|
96
|
+
end
|
97
|
+
|
98
|
+
# Encryption secret to use with signatures metadata
|
99
|
+
config_accessor :signature_handler_encryption_secret do
|
100
|
+
Decidim::Env.new("INITIATIVES_SIGNATURE_HANDLER_ENCRYPTION_SECRET", "personal user metadata").to_s
|
90
101
|
end
|
91
102
|
end
|
92
103
|
end
|