decidim-verifications 0.15.2 → 0.16.0

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +37 -7
  3. data/app/commands/decidim/verifications/id_documents/admin/confirm_user_offline_authorization.rb +74 -0
  4. data/app/commands/decidim/verifications/id_documents/admin/update_config.rb +39 -0
  5. data/app/controllers/decidim/verifications/id_documents/admin/config_controller.rb +40 -0
  6. data/app/controllers/decidim/verifications/id_documents/admin/offline_confirmations_controller.rb +40 -0
  7. data/app/controllers/decidim/verifications/id_documents/admin/pending_authorizations_controller.rb +13 -2
  8. data/app/controllers/decidim/verifications/id_documents/authorizations_controller.rb +30 -2
  9. data/app/controllers/decidim/verifications/sms/authorizations_controller.rb +76 -0
  10. data/app/forms/decidim/verifications/id_documents/admin/config_form.rb +42 -0
  11. data/app/forms/decidim/verifications/id_documents/admin/offline_confirmation_form.rb +16 -0
  12. data/app/forms/decidim/verifications/id_documents/information_form.rb +12 -1
  13. data/app/forms/decidim/verifications/id_documents/upload_form.rb +2 -1
  14. data/app/forms/decidim/verifications/sms/confirmation_form.rb +19 -0
  15. data/app/forms/decidim/verifications/sms/mobile_phone_form.rb +59 -0
  16. data/app/views/decidim/verifications/id_documents/admin/config/edit.html.erb +26 -0
  17. data/app/views/decidim/verifications/id_documents/admin/confirmations/new.html.erb +1 -0
  18. data/app/views/decidim/verifications/id_documents/admin/offline_confirmations/new.html.erb +24 -0
  19. data/app/views/decidim/verifications/id_documents/admin/pending_authorizations/index.html.erb +3 -1
  20. data/app/views/decidim/verifications/id_documents/authorizations/_form.html.erb +17 -0
  21. data/app/views/decidim/verifications/id_documents/authorizations/choose.html.erb +21 -0
  22. data/app/views/decidim/verifications/id_documents/authorizations/edit.html.erb +14 -23
  23. data/app/views/decidim/verifications/id_documents/authorizations/new.html.erb +6 -13
  24. data/app/views/decidim/verifications/sms/authorizations/edit.html.erb +27 -0
  25. data/app/views/decidim/verifications/sms/authorizations/new.html.erb +27 -0
  26. data/config/locales/ca.yml +51 -1
  27. data/config/locales/de.yml +50 -0
  28. data/config/locales/en.yml +51 -1
  29. data/config/locales/es-PY.yml +50 -0
  30. data/config/locales/es.yml +51 -1
  31. data/config/locales/eu.yml +50 -0
  32. data/config/locales/fi-pl.yml +51 -1
  33. data/config/locales/fi.yml +51 -1
  34. data/config/locales/fr.yml +50 -0
  35. data/config/locales/gl.yml +50 -0
  36. data/config/locales/hu.yml +50 -0
  37. data/config/locales/id-ID.yml +51 -1
  38. data/config/locales/it.yml +50 -0
  39. data/config/locales/nl.yml +50 -0
  40. data/config/locales/pl.yml +50 -0
  41. data/config/locales/pt-BR.yml +50 -0
  42. data/config/locales/pt.yml +50 -0
  43. data/config/locales/sv.yml +50 -0
  44. data/config/locales/tr-TR.yml +51 -1
  45. data/lib/decidim/verifications.rb +1 -0
  46. data/lib/decidim/verifications/id_documents/admin_engine.rb +3 -0
  47. data/lib/decidim/verifications/id_documents/engine.rb +6 -2
  48. data/lib/decidim/verifications/sms.rb +4 -0
  49. data/lib/decidim/verifications/sms/engine.rb +29 -0
  50. data/lib/decidim/verifications/sms/example_gateway.rb +21 -0
  51. data/lib/decidim/verifications/version.rb +1 -1
  52. metadata +27 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35989fb875c3a9a35ef5b25cb46952b655cb2f506ec1cf6ad32560e7aba51523
4
- data.tar.gz: 0d797f5a1c10a56816f206b42d737effd16919372f4a9addcd09026c0e79bdeb
3
+ metadata.gz: 3f72535ac2342a5548bc109d27133bdbbc04ea5d31bf75e6bea9388129cfd962
4
+ data.tar.gz: 65a300dbe94c86dc4a185946617608e78cf912879df40aca37b72e4eb08504a8
5
5
  SHA512:
6
- metadata.gz: 97d9d80cf83c94b581158614ca5490f8aced492cb054bebad163eda1e6c2f67486a4c3f55330ab9b69eca2ebdb21b20e9304ae6fff0e7c10b8578b2f1c3d5724
7
- data.tar.gz: 35cf389ed2c0376d767d52c5587575806e17e465c88ee8af9f62691e27c5633e9c8ae135874ac2981667315721b37177d5f176681c1827c71d2bac9a34453fb0
6
+ metadata.gz: d8aea64e88a8f1ec983ee81e4ccdaab8c6788077ef171aac9ba432710eddbbf2d595e9a8200c0b5cff2735fc1b3659d4d4384c77d8c73cb6a369c33f4d0be550
7
+ data.tar.gz: 27e690f78d70610141648ec4acc0551401aa904476caeb842de371a57586cdd812ea2c5ab3dc23c27328a6f220deb5a4210b4b515305ce860c890304cfd57af0
data/README.md CHANGED
@@ -76,9 +76,9 @@ Decidim implements two type of authorization methods:
76
76
  ```ruby
77
77
  # config/initializers/decidim.rb
78
78
 
79
- Decidim::Verifications.register_workflow(:sms_verification) do |workflow|
80
- workflow.engine = Decidim::Verifications::SmsVerification::Engine
81
- workflow.admin_engine = Decidim::Verifications::SmsVerification::AdminEngine
79
+ Decidim::Verifications.register_workflow(:my_verification) do |workflow|
80
+ workflow.engine = Decidim::Verifications::MyVerification::Engine
81
+ workflow.admin_engine = Decidim::Verifications::MyVerification::AdminEngine
82
82
  end
83
83
  ```
84
84
 
@@ -97,6 +97,24 @@ Decidim implements two type of authorization methods:
97
97
  * `edit_authorization_path`: This is the entry point to resume an existing
98
98
  authorization process.
99
99
 
100
+ ### SMS verification
101
+
102
+ Decidim comes with a verification workflow designed to verify users by sending
103
+ an SMS to their mobile phone.
104
+
105
+ Much like a Census verification you just need to implement a class that sends an
106
+ SMS code using your preferred provider.
107
+
108
+ In order to setup Decidim with SMS verification you need to:
109
+
110
+ 1. Create a class that accepts two parameters when initializing it (mobile phone and code) and a method named `deliver_code` that will send an SMS and return a truthy or falsey value if the delivery was OK or not.
111
+ 1. Set the `sms_gateway_service` configuration variable to the name of the class that you just created (use a String, not the actual class) at `config/initializers/decidim.rb`.
112
+
113
+ Keep in mind that Decidim won't store a free text version of the mobile phone, only a hashed
114
+ version so we can avoid duplicates and guarantee the users' privacy.
115
+
116
+ You can find an example [here][example SMS gateway].
117
+
100
118
  ## Authorization options
101
119
 
102
120
  Sometimes you want to scope authorizations only to users that meet certain
@@ -163,10 +181,10 @@ its workflow manifest:
163
181
  ```ruby
164
182
  # config/initializers/decidim.rb
165
183
 
166
- Decidim::Verifications.register_workflow(:sms_verification) do |workflow|
167
- workflow.engine = Decidim::Verifications::SmsVerification::Engine
168
- workflow.admin_engine = Decidim::Verifications::SmsVerification::AdminEngine
169
- workflow.action_authorizer = "Decidim::Verifications::SmsVerification::ActionAuthorizer"
184
+ Decidim::Verifications.register_workflow(:my_verification) do |workflow|
185
+ workflow.engine = Decidim::Verifications::MyVerification::Engine
186
+ workflow.admin_engine = Decidim::Verifications::MyVerification::AdminEngine
187
+ workflow.action_authorizer = "Decidim::Verifications::MyVerification::ActionAuthorizer"
170
188
  end
171
189
  ```
172
190
 
@@ -174,6 +192,17 @@ Check the [example authorization handler](https://github.com/decidim/decidim/blo
174
192
  and the [DefaultActionAuthorizer class](https://github.com/decidim/decidim/blob/master/decidim-verifications/lib/decidim/verifications/default_action_authorizer.rb)
175
193
  for additional technical details.
176
194
 
195
+ ## How Handlers work
196
+
197
+ For a workflow to be visible in the user's profile, the organization must have
198
+ it in it's `available_authorizations` and the given handler must exist.
199
+ The name of the handler must match the authorization name plus the "Hander"
200
+ suffix. It also has to be in the `Decidim::Verifications` namespace.
201
+
202
+ The handler is both the Form object that the user must fill in order to be
203
+ verified, but also the validator of the filled information in order to grant the
204
+ authorization.
205
+
177
206
  ## Installation
178
207
 
179
208
  Add this line to your application's Gemfile:
@@ -197,6 +226,7 @@ See [Decidim](https://github.com/decidim/decidim).
197
226
  See [Decidim](https://github.com/decidim/decidim).
198
227
 
199
228
  [authorization handler base class]: https://github.com/decidim/decidim/blob/master/decidim-core/app/services/decidim/authorization_handler.rb
229
+ [example SMS gateway]: https://github.com/decidim/decidim/blob/master/decidim-verifications/lib/decidim/verifications/sms/example_gateway.rb
200
230
 
201
231
  [Decidim Barcelona]: https://github.com/AjuntamentdeBarcelona/decidim-barcelona/blob/master/app/services/census_authorization_handler.rb
202
232
  [Decidim Terrassa]: https://github.com/AjuntamentDeTerrassa/decidim-terrassa/blob/master/app/services/census_authorization_handler.rb
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ module IdDocuments
6
+ module Admin
7
+ # A command to confirm a previous partial offline authorization.
8
+ class ConfirmUserOfflineAuthorization < Rectify::Command
9
+ # Public: Initializes the command.
10
+ #
11
+ # form - A form object with the verification data to confirm it.
12
+ def initialize(form)
13
+ @form = form
14
+ end
15
+
16
+ # Executes the command. Broadcasts these events:
17
+ #
18
+ # - :ok when everything is valid.
19
+ # - :invalid if the handler wasn't valid and we couldn't proceed.
20
+ #
21
+ # Returns nothing.
22
+ def call
23
+ return broadcast(:invalid) unless form.valid?
24
+ return broadcast(:invalid) unless authorization
25
+
26
+ if confirmation_successful?
27
+ grant_authorization
28
+ broadcast(:ok)
29
+ else
30
+ broadcast(:invalid)
31
+ end
32
+ end
33
+
34
+ protected
35
+
36
+ def confirmation_successful?
37
+ form.verification_metadata.all? do |key, value|
38
+ authorization.verification_metadata[key] == value
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :form
45
+
46
+ def grant_authorization
47
+ Decidim.traceability.perform_action!(
48
+ :grant_id_documents_offline_verification,
49
+ authorization_user,
50
+ form.current_user
51
+ ) do
52
+ authorization.grant!
53
+ end
54
+ end
55
+
56
+ def authorization
57
+ @authorization ||= Authorizations
58
+ .new(organization: form.current_organization, name: "id_documents", granted: false)
59
+ .query
60
+ .where("verification_metadata->'rejected' IS NULL")
61
+ .where("verification_metadata->>'verification_type' = 'offline'")
62
+ .find_by(user: authorization_user)
63
+ end
64
+
65
+ def authorization_user
66
+ @authorization_user ||= Decidim::User
67
+ .where(organization: form.current_organization)
68
+ .find_by(email: form.email)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ module IdDocuments
6
+ module Admin
7
+ class UpdateConfig < Rectify::Command
8
+ def initialize(form)
9
+ @form = form
10
+ end
11
+
12
+ def call
13
+ return broadcast(:invalid) if form.invalid?
14
+
15
+ update_config
16
+
17
+ broadcast(:ok)
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :form
23
+
24
+ def update_config
25
+ Decidim.traceability.perform_action!(
26
+ :update_id_documents_config,
27
+ form.current_organization,
28
+ form.current_user
29
+ ) do
30
+ form.current_organization.id_documents_methods = form.selected_methods
31
+ form.current_organization.id_documents_explanation_text = form.offline_explanation
32
+ form.current_organization.save!
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ module IdDocuments
6
+ module Admin
7
+ #
8
+ # Handles the configuration for the ID documents verification
9
+ #
10
+ class ConfigController < Decidim::Admin::ApplicationController
11
+ layout "decidim/admin/users"
12
+
13
+ def edit
14
+ enforce_permission_to :update, :organization, organization: current_organization
15
+
16
+ @form = form(ConfigForm).from_model(current_organization)
17
+ end
18
+
19
+ def update
20
+ enforce_permission_to :update, :organization, organization: current_organization
21
+
22
+ @form = form(ConfigForm).from_params(params)
23
+
24
+ UpdateConfig.call(@form) do
25
+ on(:ok) do
26
+ flash[:notice] = t("config.update.success", scope: "decidim.verifications.id_documents.admin")
27
+ redirect_to pending_authorizations_path
28
+ end
29
+
30
+ on(:invalid) do
31
+ flash.now[:alert] = t("config.update.error", scope: "decidim.verifications.id_documents.admin")
32
+ render action: :edit
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ module IdDocuments
6
+ module Admin
7
+ #
8
+ # Handles confirmations for offline verification by identity document.
9
+ #
10
+ class OfflineConfirmationsController < Decidim::Admin::ApplicationController
11
+ layout "decidim/admin/users"
12
+
13
+ def new
14
+ enforce_permission_to :update, :authorization
15
+
16
+ @form = form(OfflineConfirmationForm).instance
17
+ end
18
+
19
+ def create
20
+ enforce_permission_to :update, :authorization
21
+
22
+ @form = form(OfflineConfirmationForm).from_params(params)
23
+
24
+ ConfirmUserOfflineAuthorization.call(@form) do
25
+ on(:ok) do
26
+ flash[:notice] = t("offline_confirmations.create.success", scope: "decidim.verifications.id_documents.admin")
27
+ redirect_to pending_authorizations_path
28
+ end
29
+
30
+ on(:invalid) do
31
+ flash.now[:alert] = t("offline_confirmations.create.error", scope: "decidim.verifications.id_documents.admin")
32
+ render action: :new
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -7,19 +7,30 @@ module Decidim
7
7
  class PendingAuthorizationsController < Decidim::Admin::ApplicationController
8
8
  layout "decidim/admin/users"
9
9
 
10
+ helper_method :has_offline_method?
11
+
10
12
  def index
11
13
  enforce_permission_to :index, :authorization
12
14
 
13
- @pending_authorizations = pending_authorizations
15
+ @pending_online_authorizations = pending_online_authorizations
14
16
  end
15
17
 
16
18
  private
17
19
 
18
- def pending_authorizations
20
+ def pending_online_authorizations
19
21
  Authorizations
20
22
  .new(organization: current_organization, name: "id_documents", granted: false)
21
23
  .query
22
24
  .where("verification_metadata->'rejected' IS NULL")
25
+ .where("verification_metadata->>'verification_type' = 'online'")
26
+ end
27
+
28
+ def has_offline_method?
29
+ available_methods.include?("offline")
30
+ end
31
+
32
+ def available_methods
33
+ @available_methods ||= current_organization.id_documents_methods
23
34
  end
24
35
  end
25
36
  end
@@ -7,14 +7,20 @@ module Decidim
7
7
  # Handles verification by identity document upload
8
8
  #
9
9
  class AuthorizationsController < ApplicationController
10
- helper_method :authorization
10
+ helper_method :authorization, :verification_type, :using_offline?, :using_online?, :available_methods
11
11
 
12
12
  before_action :load_authorization
13
13
 
14
+ def choose
15
+ return redirect_to action: :new, using: verification_type if available_methods.count == 1
16
+ render :choose
17
+ end
18
+
14
19
  def new
20
+ raise ActionController::RoutingError, "Method not available" unless available_methods.include?(verification_type)
15
21
  enforce_permission_to :create, :authorization, authorization: @authorization
16
22
 
17
- @form = UploadForm.new
23
+ @form = UploadForm.from_params(id_document_upload: { verification_type: verification_type })
18
24
  end
19
25
 
20
26
  def create
@@ -47,6 +53,7 @@ module Decidim
47
53
  @form = UploadForm.from_params(
48
54
  params.merge(
49
55
  user: current_user,
56
+ verification_type: verification_type,
50
57
  verification_attachment: params[:id_document_upload][:verification_attachment] || @authorization.verification_attachment
51
58
  )
52
59
  )
@@ -78,6 +85,27 @@ module Decidim
78
85
  name: "id_documents"
79
86
  )
80
87
  end
88
+
89
+ def verification_type
90
+ params[:using] || authorization_verification_type || available_methods.first
91
+ end
92
+
93
+ def authorization_verification_type
94
+ return unless @authorization
95
+ @authorization.verification_metadata["verification_type"]
96
+ end
97
+
98
+ def using_online?
99
+ verification_type == "online"
100
+ end
101
+
102
+ def using_offline?
103
+ verification_type == "offline"
104
+ end
105
+
106
+ def available_methods
107
+ @available_methods ||= current_organization.id_documents_methods
108
+ end
81
109
  end
82
110
  end
83
111
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ module Sms
6
+ class AuthorizationsController < ApplicationController
7
+ helper_method :authorization
8
+
9
+ before_action :load_authorization
10
+
11
+ def new
12
+ enforce_permission_to :create, :authorization, authorization: @authorization
13
+
14
+ @form = MobilePhoneForm.new
15
+ end
16
+
17
+ def create
18
+ enforce_permission_to :create, :authorization, authorization: @authorization
19
+
20
+ @form = MobilePhoneForm.from_params(params.merge(user: current_user))
21
+
22
+ PerformAuthorizationStep.call(@authorization, @form) do
23
+ on(:ok) do
24
+ flash[:notice] = t("authorizations.create.success", scope: "decidim.verifications.sms")
25
+ authorization_method = Decidim::Verifications::Adapter.from_element(authorization.name)
26
+ redirect_to authorization_method.resume_authorization_path
27
+ end
28
+ on(:invalid) do
29
+ flash.now[:alert] = t("authorizations.create.error", scope: "decidim.verifications.sms")
30
+ render :new
31
+ end
32
+ end
33
+ end
34
+
35
+ def edit
36
+ enforce_permission_to :update, :authorization, authorization: @authorization
37
+
38
+ @form = ConfirmationForm.from_params(params)
39
+ end
40
+
41
+ def update
42
+ enforce_permission_to :update, :authorization, authorization: @authorization
43
+
44
+ @form = ConfirmationForm.from_params(params)
45
+
46
+ ConfirmUserAuthorization.call(@authorization, @form) do
47
+ on(:ok) do
48
+ flash[:notice] = t("authorizations.update.success", scope: "decidim.verifications.sms")
49
+ redirect_to decidim_verifications.authorizations_path
50
+ end
51
+
52
+ on(:invalid) do
53
+ flash.now[:alert] = t("authorizations.update.error", scope: "decidim.verifications.sms")
54
+ render :edit
55
+ end
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ # rubocop:disable Naming/MemoizedInstanceVariableName
62
+ def authorization
63
+ @authorization_presenter ||= AuthorizationPresenter.new(@authorization)
64
+ end
65
+ # rubocop:enable Naming/MemoizedInstanceVariableName
66
+
67
+ def load_authorization
68
+ @authorization = Decidim::Authorization.find_or_initialize_by(
69
+ user: current_user,
70
+ name: "sms"
71
+ )
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end