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
@@ -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>