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.
- checksums.yaml +4 -4
- data/README.md +37 -7
- data/app/commands/decidim/verifications/id_documents/admin/confirm_user_offline_authorization.rb +74 -0
- data/app/commands/decidim/verifications/id_documents/admin/update_config.rb +39 -0
- data/app/controllers/decidim/verifications/id_documents/admin/config_controller.rb +40 -0
- data/app/controllers/decidim/verifications/id_documents/admin/offline_confirmations_controller.rb +40 -0
- data/app/controllers/decidim/verifications/id_documents/admin/pending_authorizations_controller.rb +13 -2
- data/app/controllers/decidim/verifications/id_documents/authorizations_controller.rb +30 -2
- data/app/controllers/decidim/verifications/sms/authorizations_controller.rb +76 -0
- data/app/forms/decidim/verifications/id_documents/admin/config_form.rb +42 -0
- data/app/forms/decidim/verifications/id_documents/admin/offline_confirmation_form.rb +16 -0
- data/app/forms/decidim/verifications/id_documents/information_form.rb +12 -1
- data/app/forms/decidim/verifications/id_documents/upload_form.rb +2 -1
- data/app/forms/decidim/verifications/sms/confirmation_form.rb +19 -0
- data/app/forms/decidim/verifications/sms/mobile_phone_form.rb +59 -0
- data/app/views/decidim/verifications/id_documents/admin/config/edit.html.erb +26 -0
- data/app/views/decidim/verifications/id_documents/admin/confirmations/new.html.erb +1 -0
- data/app/views/decidim/verifications/id_documents/admin/offline_confirmations/new.html.erb +24 -0
- data/app/views/decidim/verifications/id_documents/admin/pending_authorizations/index.html.erb +3 -1
- data/app/views/decidim/verifications/id_documents/authorizations/_form.html.erb +17 -0
- data/app/views/decidim/verifications/id_documents/authorizations/choose.html.erb +21 -0
- data/app/views/decidim/verifications/id_documents/authorizations/edit.html.erb +14 -23
- data/app/views/decidim/verifications/id_documents/authorizations/new.html.erb +6 -13
- data/app/views/decidim/verifications/sms/authorizations/edit.html.erb +27 -0
- data/app/views/decidim/verifications/sms/authorizations/new.html.erb +27 -0
- data/config/locales/ca.yml +51 -1
- data/config/locales/de.yml +50 -0
- data/config/locales/en.yml +51 -1
- data/config/locales/es-PY.yml +50 -0
- data/config/locales/es.yml +51 -1
- data/config/locales/eu.yml +50 -0
- data/config/locales/fi-pl.yml +51 -1
- data/config/locales/fi.yml +51 -1
- data/config/locales/fr.yml +50 -0
- data/config/locales/gl.yml +50 -0
- data/config/locales/hu.yml +50 -0
- data/config/locales/id-ID.yml +51 -1
- data/config/locales/it.yml +50 -0
- data/config/locales/nl.yml +50 -0
- data/config/locales/pl.yml +50 -0
- data/config/locales/pt-BR.yml +50 -0
- data/config/locales/pt.yml +50 -0
- data/config/locales/sv.yml +50 -0
- data/config/locales/tr-TR.yml +51 -1
- data/lib/decidim/verifications.rb +1 -0
- data/lib/decidim/verifications/id_documents/admin_engine.rb +3 -0
- data/lib/decidim/verifications/id_documents/engine.rb +6 -2
- data/lib/decidim/verifications/sms.rb +4 -0
- data/lib/decidim/verifications/sms/engine.rb +29 -0
- data/lib/decidim/verifications/sms/example_gateway.rb +21 -0
- data/lib/decidim/verifications/version.rb +1 -1
- 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 %>
|
data/app/views/decidim/verifications/id_documents/admin/pending_authorizations/index.html.erb
CHANGED
@@ -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
|
-
<% @
|
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
|
-
|
21
|
-
<div class="
|
22
|
-
<div class="
|
23
|
-
<div class="
|
24
|
-
<div class="
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
47
|
-
</div>
|
38
|
+
<% end %>
|
48
39
|
</div>
|
49
40
|
</div>
|
50
41
|
</div>
|
51
42
|
</div>
|
52
|
-
|
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
|
-
|
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="
|
27
|
-
|
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>
|