decidim-verifications 0.15.2 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
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