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
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ module IdDocuments
6
+ # A form object to be used as the base for identity document verification
7
+ module Admin
8
+ class ConfigForm < Decidim::Form
9
+ include TranslatableAttributes
10
+ mimic :config
11
+
12
+ attribute :offline, Boolean
13
+ attribute :online, Boolean
14
+ translatable_attribute :offline_explanation, String
15
+
16
+ validates :offline_explanation, translatable_presence: true, if: :offline
17
+ validate :has_some_method_selected?
18
+
19
+ def map_model(model)
20
+ self.online = model.id_documents_methods.include?("online")
21
+ self.offline = model.id_documents_methods.include?("offline")
22
+ self.offline_explanation = model.id_documents_explanation_text
23
+ end
24
+
25
+ def has_some_method_selected?
26
+ return if online || offline
27
+
28
+ errors.add(:online, :invalid)
29
+ errors.add(:offline, :invalid)
30
+ end
31
+
32
+ def selected_methods
33
+ methods = []
34
+ methods << "offline" if offline
35
+ methods << "online" if online
36
+ methods
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ module IdDocuments
6
+ # A form object to be used as the base for identity document verification
7
+ module Admin
8
+ class OfflineConfirmationForm < InformationForm
9
+ attribute :email, String
10
+
11
+ validates :email, presence: true
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -11,6 +11,7 @@ module Decidim
11
11
 
12
12
  attribute :document_number, String
13
13
  attribute :document_type, String
14
+ attribute :verification_type, String
14
15
 
15
16
  validates :document_type,
16
17
  inclusion: { in: DOCUMENT_TYPES },
@@ -20,6 +21,10 @@ module Decidim
20
21
  format: { with: /\A[A-Z0-9]*\z/, message: I18n.t("errors.messages.uppercase_only_letters_numbers") },
21
22
  presence: true
22
23
 
24
+ validates :verification_type,
25
+ presence: true,
26
+ inclusion: { in: %w(offline online) }
27
+
23
28
  def handler_name
24
29
  "id_documents"
25
30
  end
@@ -27,12 +32,14 @@ module Decidim
27
32
  def map_model(model)
28
33
  self.document_type = model.verification_metadata["document_type"]
29
34
  self.document_number = model.verification_metadata["document_number"]
35
+ self.verification_type = model.verification_metadata["verification_type"].presence || "online"
30
36
  end
31
37
 
32
38
  def verification_metadata
33
39
  {
34
40
  "document_type" => document_type,
35
- "document_number" => document_number
41
+ "document_number" => document_number,
42
+ "verification_type" => verification_type
36
43
  }
37
44
  end
38
45
 
@@ -44,6 +51,10 @@ module Decidim
44
51
  ]
45
52
  end
46
53
  end
54
+
55
+ def uses_online_method?
56
+ verification_type == "online"
57
+ end
47
58
  end
48
59
  end
49
60
  end
@@ -13,7 +13,8 @@ module Decidim
13
13
  validates :verification_attachment,
14
14
  file_size: { less_than_or_equal_to: ->(_record) { Decidim.maximum_attachment_size } },
15
15
  file_content_type: { allow: ["image/jpeg", "image/png"] },
16
- presence: true
16
+ presence: true,
17
+ if: :uses_online_method?
17
18
  end
18
19
  end
19
20
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ module Sms
6
+ # A form object that just holds a verification code that the user will
7
+ # have received by SMS.
8
+ class ConfirmationForm < AuthorizationHandler
9
+ attribute :verification_code, String
10
+
11
+ validates :verification_code, presence: true
12
+
13
+ def verification_metadata
14
+ { "verification_code" => verification_code }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
5
+ module Decidim
6
+ module Verifications
7
+ module Sms
8
+ # A form object to be used when public users want to get verified using their phone.
9
+ class MobilePhoneForm < AuthorizationHandler
10
+ attribute :mobile_phone_number, String
11
+
12
+ validates :mobile_phone_number, :verification_code, :sms_gateway, presence: true
13
+
14
+ def handler_name
15
+ "sms"
16
+ end
17
+
18
+ # A mobile phone can only be verified once but it should be private.
19
+ def unique_id
20
+ Digest::MD5.hexdigest(
21
+ "#{mobile_phone_number}-#{Rails.application.secrets.secret_key_base}"
22
+ )
23
+ end
24
+
25
+ # When there's a phone number, sanitize it allowing only numbers and +.
26
+ def mobile_phone_number
27
+ return unless super
28
+ super.gsub(/[^\+0-9]/, "")
29
+ end
30
+
31
+ # The verification metadata to validate in the next step.
32
+ def verification_metadata
33
+ {
34
+ verification_code: verification_code,
35
+ code_sent_at: Time.current
36
+ }
37
+ end
38
+
39
+ private
40
+
41
+ def verification_code
42
+ return unless sms_gateway
43
+ return @verification_code if defined?(@verification_code)
44
+
45
+ return unless sms_gateway.new(mobile_phone_number, generated_code).deliver_code
46
+ @verification_code = generated_code
47
+ end
48
+
49
+ def sms_gateway
50
+ Decidim.sms_gateway_service.to_s.safe_constantize
51
+ end
52
+
53
+ def generated_code
54
+ @generated_code ||= SecureRandom.random_number(1_000_000).to_s
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,26 @@
1
+ <%= decidim_form_for(@form, url: { action: :update },
2
+ html: { class: "form" }) do |form| %>
3
+ <div class="card">
4
+ <div class="card-divider">
5
+ <h2 class="card-title">
6
+ <%= t(".title") %>
7
+ </h2>
8
+ </div>
9
+
10
+ <div class="card-section">
11
+ <div class="row column">
12
+ <%= label_tag(:available_methods, t("activemodel.attributes.config.available_methods")) %>
13
+ <%= form.check_box :online %>
14
+ <%= form.check_box :offline %>
15
+ </div>
16
+
17
+ <div class="row column">
18
+ <%= form.translated :editor, :offline_explanation, lines: 10 %>
19
+ </div>
20
+ </div>
21
+ </div>
22
+
23
+ <div class="button--double form-general-submit">
24
+ <%= form.submit t(".update") %>
25
+ </div>
26
+ <% end %>
@@ -16,6 +16,7 @@
16
16
  <div class="row column">
17
17
  <%= form.select :document_type, @form.document_types_for_select, prompt: true, selected: nil %>
18
18
  <%= form.text_field :document_number, value: nil %>
19
+ <%= form.hidden_field :verification_type, value: :online %>
19
20
  </div>
20
21
  </div>
21
22
  </div>
@@ -0,0 +1,24 @@
1
+ <%= decidim_form_for(@form, url: offline_confirmation_path,
2
+ html: { class: "form" }) do |form| %>
3
+ <div class="card">
4
+ <div class="card-divider">
5
+ <h2 class="card-title">
6
+ <%= t(".introduce_user_data") %>
7
+ </h2>
8
+ </div>
9
+
10
+ <div class="card-section">
11
+ <div class="row column">
12
+ <%= form.text_field :email %>
13
+ <%= form.select :document_type, @form.document_types_for_select, prompt: true %>
14
+ <%= form.text_field :document_number %>
15
+ <%= form.hidden_field :verification_type, value: :offline %>
16
+ </div>
17
+ </div>
18
+ </div>
19
+
20
+ <div class="button--double form-general-submit">
21
+ <%= form.submit t(".verify") %>
22
+ <%= link_to t(".cancel"), root_path, class: "button hollow" %>
23
+ </div>
24
+ <% end %>
@@ -2,6 +2,8 @@
2
2
  <div class="card-divider">
3
3
  <h2 class="card-title">
4
4
  <%= t(".title") %>
5
+ <%= link_to t(".config"), edit_config_path, class: "button tiny button--title" %>
6
+ <%= link_to t(".offline_verification"), new_offline_confirmation_path, class: "button tiny button--title" if has_offline_method? %>
5
7
  </h2>
6
8
  </div>
7
9
  <div class="card-section">
@@ -14,7 +16,7 @@
14
16
  </thead>
15
17
  <tbody>
16
18
  <tr>
17
- <% @pending_authorizations.each do |authorization| %>
19
+ <% @pending_online_authorizations.each do |authorization| %>
18
20
  <td>
19
21
  <%= link_to t(".verification_number", n: authorization.id),
20
22
  new_pending_authorization_confirmation_path(authorization.id) %>
@@ -0,0 +1,17 @@
1
+ <div class="card-section">
2
+ <div class="field">
3
+ <%= form.select :document_type, @form.document_types_for_select, prompt: true %>
4
+ </div>
5
+
6
+ <div class="field">
7
+ <%= form.text_field :document_number %>
8
+ </div>
9
+
10
+ <% if using_online? %>
11
+ <div class="field">
12
+ <%= form.upload :verification_attachment %>
13
+ </div>
14
+ <% end %>
15
+
16
+ <%= form.hidden_field :verification_type, value: verification_type %>
17
+ </div>
@@ -0,0 +1,21 @@
1
+ <div class="wrapper">
2
+ <div class="row collapse">
3
+ <div class="row collapse">
4
+ <div class="columns large-8 large-centered text-center page-title">
5
+ <h1><%= t(".title") %></h1>
6
+ </div>
7
+ </div>
8
+
9
+ <div class="row">
10
+ <div class="columns large-6 medium-centered">
11
+ <div class="card">
12
+ <div class="card__content">
13
+ <p><%= t(".choose_a_type") %></p>
14
+ <%= link_to t(".offline"), { action: :new, using: :offline }, class: "button button--sc expanded hollow" %>
15
+ <%= link_to t(".online"), { action: :new, using: :online }, class: "button button--sc expanded" %>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </div>
@@ -17,37 +17,28 @@
17
17
  </div>
18
18
  </div>
19
19
 
20
- <% if authorization.rejected? %>
21
- <div class="row">
22
- <div class="columns large-6 medium-centered">
23
- <div class="row column">
24
- <div class="card">
25
- <div class="card__content">
26
- <%= decidim_form_for(@form, url: authorization_path, method: :put) do |form| %>
27
- <div class="card-section">
28
- <div class="field">
29
- <%= form.select :document_type, @form.document_types_for_select, prompt: true %>
30
- </div>
31
-
32
- <div class="field">
33
- <%= form.text_field :document_number %>
34
- </div>
35
-
36
- <div class="field">
37
- <%= form.upload :verification_attachment, optional: false %>
38
- </div>
39
- </div>
20
+ <div class="row">
21
+ <div class="columns large-6 medium-centered">
22
+ <div class="row column">
23
+ <div class="card">
24
+ <div class="card__content">
25
+ <%= translated_attribute(current_organization.id_documents_explanation_text).html_safe unless using_online? %>
26
+ <%= decidim_form_for(@form, url: authorization_path, method: :put) do |form| %>
27
+ <%= render partial: "form", locals: { form: form } %>
40
28
 
41
29
  <div class="card-section">
42
30
  <div class="actions">
43
31
  <%= form.submit t(".send"), class: "button expanded", "data-disable-with" => "#{t('.send')}..." %>
32
+ <% if available_methods.count > 1 %>
33
+ <%= link_to t(".offline"), { action: :edit, using: :offline }, class: "button expanded hollow" if using_online? %>
34
+ <%= link_to t(".online"), { action: :edit, using: :online }, class: "button expanded hollow" if using_offline? %>
35
+ <% end %>
44
36
  </div>
45
37
  </div>
46
- <% end %>
47
- </div>
38
+ <% end %>
48
39
  </div>
49
40
  </div>
50
41
  </div>
51
42
  </div>
52
- <% end %>
43
+ </div>
53
44
  </div>
@@ -10,21 +10,14 @@
10
10
  <div class="columns large-6 medium-centered">
11
11
  <div class="card">
12
12
  <div class="card__content">
13
+ <%= translated_attribute(current_organization.id_documents_explanation_text).html_safe unless using_online? %>
13
14
  <%= decidim_form_for(@form, url: authorization_path) do |form| %>
14
- <div class="field">
15
- <%= form.select :document_type, @form.document_types_for_select, prompt: true %>
16
- </div>
17
-
18
- <div class="field">
19
- <%= form.text_field :document_number %>
20
- </div>
21
-
22
- <div class="field">
23
- <%= form.upload :verification_attachment %>
24
- </div>
15
+ <%= render partial: "form", locals: { form: form } %>
25
16
 
26
- <div class="actions">
27
- <%= form.submit t(".send"), class: "button expanded", "data-disable-with" => "#{t('.send')}..." %>
17
+ <div class="card-section">
18
+ <div class="actions">
19
+ <%= form.submit t(".send"), class: "button expanded", "data-disable-with" => "#{t('.send')}..." %>
20
+ </div>
28
21
  </div>
29
22
  <% end %>
30
23
  </div>
@@ -0,0 +1,27 @@
1
+ <div class="wrapper">
2
+ <div class="row collapse">
3
+ <div class="row collapse">
4
+ <div class="columns large-8 large-centered text-center page-title">
5
+ <h1><%= t(".title") %></h1>
6
+ </div>
7
+ </div>
8
+
9
+ <div class="row">
10
+ <div class="columns large-6 medium-centered">
11
+ <div class="card">
12
+ <div class="card__content">
13
+ <%= decidim_form_for(@form, url: authorization_path, method: :put) do |form| %>
14
+ <div class="field">
15
+ <%= form.text_field :verification_code %>
16
+ </div>
17
+
18
+ <div class="actions">
19
+ <%= form.submit t(".send"), class: "button expanded", "data-disable-with" => "#{t('.send')}..." %>
20
+ </div>
21
+ <% end %>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </div>
@@ -0,0 +1,27 @@
1
+ <div class="wrapper">
2
+ <div class="row collapse">
3
+ <div class="row collapse">
4
+ <div class="columns large-8 large-centered text-center page-title">
5
+ <h1><%= t(".title") %></h1>
6
+ </div>
7
+ </div>
8
+
9
+ <div class="row">
10
+ <div class="columns large-6 medium-centered">
11
+ <div class="card">
12
+ <div class="card__content">
13
+ <%= decidim_form_for(@form, url: authorization_path) do |form| %>
14
+ <div class="field">
15
+ <%= form.text_field :mobile_phone_number %>
16
+ </div>
17
+
18
+ <div class="actions">
19
+ <%= form.submit t(".send"), class: "button expanded", "data-disable-with" => "#{t('.send')}..." %>
20
+ </div>
21
+ <% end %>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </div>