decidim-verifications 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +101 -0
  3. data/Rakefile +3 -0
  4. data/app/commands/decidim/verifications/authorize_user.rb +61 -0
  5. data/app/commands/decidim/verifications/confirm_user_authorization.rb +49 -0
  6. data/app/commands/decidim/verifications/perform_authorization_step.rb +48 -0
  7. data/app/controllers/decidim/verifications/authorizations_controller.rb +91 -0
  8. data/app/controllers/decidim/verifications/id_documents/admin/confirmations_controller.rb +48 -0
  9. data/app/controllers/decidim/verifications/id_documents/admin/pending_authorizations_controller.rb +28 -0
  10. data/app/controllers/decidim/verifications/id_documents/admin/rejections_controller.rb +37 -0
  11. data/app/controllers/decidim/verifications/id_documents/authorizations_controller.rb +82 -0
  12. data/app/controllers/decidim/verifications/postal_letter/admin/pending_authorizations_controller.rb +27 -0
  13. data/app/controllers/decidim/verifications/postal_letter/admin/postages_controller.rb +41 -0
  14. data/app/controllers/decidim/verifications/postal_letter/authorizations_controller.rb +74 -0
  15. data/app/forms/decidim/verifications/id_documents/information_form.rb +50 -0
  16. data/app/forms/decidim/verifications/id_documents/information_rejection_form.rb +15 -0
  17. data/app/forms/decidim/verifications/id_documents/upload_form.rb +20 -0
  18. data/app/forms/decidim/verifications/postal_letter/address_form.rb +28 -0
  19. data/app/forms/decidim/verifications/postal_letter/confirmation_form.rb +19 -0
  20. data/app/forms/decidim/verifications/postal_letter/postage_form.rb +34 -0
  21. data/app/presenters/decidim/verifications/id_documents/authorization_presenter.rb +20 -0
  22. data/app/presenters/decidim/verifications/postal_letter/authorization_presenter.rb +59 -0
  23. data/app/queries/decidim/verifications/authorizations.rb +41 -0
  24. data/app/services/decidim/authorization_handler.rb +112 -0
  25. data/app/services/decidim/dummy_authorization_handler.rb +27 -0
  26. data/app/uploaders/decidim/verifications/attachment_uploader.rb +16 -0
  27. data/app/views/decidim/verifications/authorizations/first_login.html.erb +22 -0
  28. data/app/views/decidim/verifications/authorizations/index.html.erb +78 -0
  29. data/app/views/decidim/verifications/authorizations/new.html.erb +33 -0
  30. data/app/views/decidim/verifications/id_documents/admin/confirmations/new.html.erb +26 -0
  31. data/app/views/decidim/verifications/id_documents/admin/pending_authorizations/index.html.erb +32 -0
  32. data/app/views/decidim/verifications/id_documents/authorizations/edit.html.erb +53 -0
  33. data/app/views/decidim/verifications/id_documents/authorizations/new.html.erb +35 -0
  34. data/app/views/decidim/verifications/postal_letter/admin/pending_authorizations/index.html.erb +50 -0
  35. data/app/views/decidim/verifications/postal_letter/authorizations/edit.html.erb +37 -0
  36. data/app/views/decidim/verifications/postal_letter/authorizations/new.html.erb +27 -0
  37. data/config/locales/ca.yml +126 -0
  38. data/config/locales/en.yml +126 -0
  39. data/config/locales/es.yml +126 -0
  40. data/config/locales/eu.yml +125 -0
  41. data/config/locales/fi.yml +125 -0
  42. data/config/locales/fr.yml +125 -0
  43. data/config/locales/it.yml +125 -0
  44. data/config/locales/nl.yml +125 -0
  45. data/config/locales/pl.yml +125 -0
  46. data/config/locales/pt.yml +125 -0
  47. data/config/locales/ru.yml +5 -0
  48. data/config/locales/uk.yml +41 -0
  49. data/db/migrate/20171030133426_move_authorizations_to_new_api.rb +66 -0
  50. data/lib/decidim/verifications.rb +26 -0
  51. data/lib/decidim/verifications/adapter.rb +88 -0
  52. data/lib/decidim/verifications/dummy.rb +5 -0
  53. data/lib/decidim/verifications/engine.rb +24 -0
  54. data/lib/decidim/verifications/id_documents.rb +6 -0
  55. data/lib/decidim/verifications/id_documents/admin.rb +12 -0
  56. data/lib/decidim/verifications/id_documents/admin_engine.rb +21 -0
  57. data/lib/decidim/verifications/id_documents/engine.rb +18 -0
  58. data/lib/decidim/verifications/id_documents/workflow.rb +6 -0
  59. data/lib/decidim/verifications/postal_letter.rb +6 -0
  60. data/lib/decidim/verifications/postal_letter/admin.rb +12 -0
  61. data/lib/decidim/verifications/postal_letter/admin_engine.rb +21 -0
  62. data/lib/decidim/verifications/postal_letter/engine.rb +18 -0
  63. data/lib/decidim/verifications/postal_letter/workflow.rb +6 -0
  64. data/lib/decidim/verifications/registry.rb +39 -0
  65. data/lib/decidim/verifications/version.rb +10 -0
  66. data/lib/decidim/verifications/workflow_manifest.rb +56 -0
  67. data/lib/decidim/verifications/workflows.rb +58 -0
  68. metadata +152 -0
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ module PostalLetter
6
+ #
7
+ # Decorator for postal letter authorizations.
8
+ #
9
+ class AuthorizationPresenter < SimpleDelegator
10
+ def self.for_collection(authorizations)
11
+ authorizations.map { |authorization| new(authorization) }
12
+ end
13
+
14
+ #
15
+ # The address where the verification code will be sent
16
+ #
17
+ def verification_address
18
+ verification_metadata["address"]
19
+ end
20
+
21
+ #
22
+ # The verification code to be sent. It's kept in a different metadata
23
+ # key according to whether it has already been sent or not
24
+ #
25
+ def verification_code
26
+ if letter_sent?
27
+ verification_metadata["verification_code"]
28
+ else
29
+ verification_metadata["pending_verification_code"]
30
+ end
31
+ end
32
+
33
+ #
34
+ # Whether the letter with the verification code has already been sent or
35
+ # not
36
+ #
37
+ def letter_sent?
38
+ verification_metadata["verification_code"].present?
39
+ end
40
+
41
+ #
42
+ # Formatted time when the postal letter was sent. Or an informational
43
+ # string if not yet sent
44
+ #
45
+ def letter_sent_at
46
+ unless letter_sent?
47
+ return I18n.t("pending_authorizations.index.not_yet_sent",
48
+ scope: "decidim.verifications.postal_letter.admin")
49
+ end
50
+
51
+ I18n.l(
52
+ Time.zone.parse(verification_metadata["letter_sent_at"]),
53
+ format: :short
54
+ )
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ # Finds authorizations by different criteria
6
+ class Authorizations < Rectify::Query
7
+ # Initializes the class.
8
+ #
9
+ # @param name [String] The name of an authorization method
10
+ # @param user [User] A user to find authorizations for
11
+ # @param granted [Boolean] Whether the authorization is granted or not
12
+ def initialize(user: nil, name: nil, granted: nil)
13
+ @user = user
14
+ @name = name
15
+ @granted = granted
16
+ end
17
+
18
+ # Finds the Authorizations for the given method
19
+ #
20
+ # Returns an ActiveRecord::Relation.
21
+ def query
22
+ scope = Decidim::Authorization.where(nil)
23
+
24
+ scope = scope.where(name: name) unless name.nil?
25
+ scope = scope.where(user: user) unless user.nil?
26
+
27
+ if granted == true
28
+ scope = scope.where.not(granted_at: nil)
29
+ elsif granted == false
30
+ scope = scope.where(granted_at: nil)
31
+ end
32
+
33
+ scope
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :user, :name, :granted
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # This is the base class for authorization handlers, all implementations
5
+ # should inherit from it.
6
+ # Each AuthorizationHandler is a form that will be used to check if the
7
+ # authorization is valid or not. When it is valid a new authorization will
8
+ # be created for the user.
9
+ #
10
+ # Feel free to use validations to assert fields against a remote API,
11
+ # local database, or whatever.
12
+ #
13
+ # It also sets two default attributes, `user` and `handler_name`.
14
+ class AuthorizationHandler < Form
15
+ # The user that is trying to authorize, it's initialized with the
16
+ # `current_user` from the controller.
17
+ attribute :user, Decidim::User
18
+
19
+ # The String name of the handler, should not be modified since it's used to
20
+ # infer the class name of the authorization handler.
21
+ attribute :handler_name, String
22
+
23
+ # A unique ID to be implemented by the authorization handler that ensures
24
+ # no duplicates are created. This uniqueness check will be skipped if
25
+ # unique_id returns nil.
26
+ def unique_id
27
+ nil
28
+ end
29
+
30
+ # THe attributes of the handler that should be exposed as form input when
31
+ # rendering the handler in a form.
32
+ #
33
+ # Returns an Array of Strings.
34
+ def form_attributes
35
+ attributes.except(:id, :user).keys
36
+ end
37
+
38
+ # The String partial path so Rails can render the handler as a form. This
39
+ # is useful if you want to have a custom view to render the form instead of
40
+ # the default view.
41
+ #
42
+ # Example:
43
+ #
44
+ # A handler named Decidim::CensusHandler would look for its partial in:
45
+ # decidim/census/form
46
+ #
47
+ # Returns a String.
48
+ def to_partial_path
49
+ handler_name.sub!(/_handler$/, "") + "/form"
50
+ end
51
+
52
+ # Any data that the developer would like to inject to the `metadata` field
53
+ # of an authorization when it's created. Can be useful if some of the
54
+ # params the user sent with the authorization form want to be persisted for
55
+ # future use.
56
+ #
57
+ # Returns a Hash.
58
+ def metadata
59
+ {}
60
+ end
61
+
62
+ #
63
+ # Any data to be injected in the `verification_metadata` field of an
64
+ # authorization when it's created. This data will be used for multi-step
65
+ # verificaton workflows in order to confirm the authorization.
66
+ #
67
+ # Returns a Hash.
68
+ def verification_metadata
69
+ {}
70
+ end
71
+
72
+ #
73
+ # An optional attachment to help out with verification.
74
+ #
75
+ def verification_attachment
76
+ nil
77
+ end
78
+
79
+ # A serialized version of the handler's name.
80
+ #
81
+ # Returns a String.
82
+ def self.handler_name
83
+ name.demodulize.underscore
84
+ end
85
+
86
+ # Same as the class method but accessible from the instance.
87
+ #
88
+ # Returns a String.
89
+ def handler_name
90
+ self.class.handler_name
91
+ end
92
+
93
+ # Finds a handler class from a String. This is necessary when processing
94
+ # the form data. It will only look for valid handlers that have also been
95
+ # configured in `Decidim.authorization_handlers`.
96
+ #
97
+ # name - The String name of the class to find, usually in the same shape as
98
+ # the one returned by `handler_name`.
99
+ # params - An optional Hash with params to initialize the handler.
100
+ #
101
+ # Returns an AuthorizationHandler descendant.
102
+ # Returns nil when no handlers could be found.
103
+ def self.handler_for(name, params = {})
104
+ return unless name
105
+
106
+ manifest = Decidim.authorization_handlers.find { |m| m.name == name }
107
+ return unless manifest
108
+
109
+ manifest.form.constantize.from_params(params || {})
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # An example implementation of an AuthorizationHandler to be used in tests.
5
+ class DummyAuthorizationHandler < AuthorizationHandler
6
+ attribute :document_number, String
7
+ attribute :postal_code, String
8
+ attribute :birthday, Date
9
+
10
+ validates :document_number, presence: true
11
+ validate :valid_document_number
12
+
13
+ def metadata
14
+ super.merge(document_number: document_number)
15
+ end
16
+
17
+ def unique_id
18
+ document_number
19
+ end
20
+
21
+ private
22
+
23
+ def valid_document_number
24
+ errors.add(:document_number, :invalid) unless document_number.to_s.end_with?("X")
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Verifications
5
+ # This class deals with uploading identity documents.
6
+ class AttachmentUploader < ImageUploader
7
+ version :thumbnail do
8
+ process resize_to_limit: [90, nil]
9
+ end
10
+
11
+ version :big do
12
+ process resize_to_limit: [600, nil]
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ <main class="wrapper">
2
+ <div class="row collapse">
3
+ <div class="row collapse">
4
+ <div class="columns large-8 large-centered text-center">
5
+ <h1 class="heading1 page-title"><%= t(".title") %></h1>
6
+ <p class="heading5"><%= t(".verify_with_these_options") %></p>
7
+ </div>
8
+ </div>
9
+ <div class="row">
10
+ <div class="columns medium-7 large-5 medium-centered">
11
+ <div class="card">
12
+ <div class="card__content">
13
+ <% unauthorized_methods.each do |unauthorized_method| %>
14
+ <%= link_to t(".actions.#{unauthorized_method.key}"), unauthorized_method.root_path, class: "button expanded" %>
15
+ <% end %>
16
+ <p class="text-center skip"><%= t("decidim.verifications.authorizations.skip_verification", link: link_to(t("decidim.verifications.authorizations.start_exploring"), cta_button_path).html_safe).html_safe %>.</p>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ </main>
@@ -0,0 +1,78 @@
1
+ <div class="row column authorizations-list">
2
+ <section class="section">
3
+ <% if @granted_authorizations.any? %>
4
+ <div class="card card--list">
5
+ <% @granted_authorizations.each do |authorization| %>
6
+ <div class="card--list__item">
7
+ <div class="card--list__text">
8
+ <%= icon "lock-unlocked", class: "card--list__icon" %>
9
+ <div>
10
+ <h5 class="card--list__heading">
11
+ <%= t("#{authorization.name}.name", scope: "decidim.authorization_handlers") %>
12
+ </h5>
13
+ <span class="text-small">
14
+ <%= t("granted_at", scope: "decidim.authorization_handlers", timestamp: l(authorization.granted_at, format: :long)) %>
15
+ </span>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ <% end %>
20
+ </div>
21
+ <% end %>
22
+
23
+ <% if @pending_authorizations.any? %>
24
+ <div class="card card--list">
25
+ <% @pending_authorizations.each do |authorization| %>
26
+ <% authorization_method = Decidim::Verifications::Adapter.from_element(authorization.name) %>
27
+ <%= link_to authorization_method.resume_authorization_path do %>
28
+ <div class="card--list__item">
29
+ <div class="card--list__text">
30
+ <%= icon "reload", class: "card--list__icon" %>
31
+ <div>
32
+ <h5 class="card--list__heading">
33
+ <%= t("#{authorization.name}.name", scope: "decidim.authorization_handlers") %>
34
+ </h5>
35
+ <span class="text-small">
36
+ <%= t("started_at", scope: "decidim.authorization_handlers", timestamp: l(authorization.updated_at, format: :long)) %>
37
+ </span>
38
+ </div>
39
+ </div>
40
+ <div class="card--list__data">
41
+ <span class="card--list__data__icon">
42
+ <%= icon "chevron-right" %>
43
+ </span>
44
+ </div>
45
+ </div>
46
+ <% end %>
47
+ <% end %>
48
+ </div>
49
+ <% end %>
50
+
51
+ <% if unauthorized_methods.any? %>
52
+ <div class="card card--list">
53
+ <% unauthorized_methods.each do |unauthorized_method| %>
54
+ <%= link_to unauthorized_method.root_path do %>
55
+ <div class="card--list__item">
56
+ <div class="card--list__text">
57
+ <%= icon "lock-locked", class: "card--list__icon" %>
58
+ <div>
59
+ <h5 class="card--list__heading">
60
+ <%= t("#{unauthorized_method.key}.name", scope: "decidim.authorization_handlers") %>
61
+ </h5>
62
+ <span class="text-small">
63
+ <%= t("#{unauthorized_method.key}.explanation", scope: "decidim.authorization_handlers") %>
64
+ </span>
65
+ </div>
66
+ </div>
67
+ <div class="card--list__data">
68
+ <span class="card--list__data__icon">
69
+ <%= icon "chevron-right" %>
70
+ </span>
71
+ </div>
72
+ </div>
73
+ <% end %>
74
+ <% end %>
75
+ </div>
76
+ <% end %>
77
+ </section>
78
+ </div>
@@ -0,0 +1,33 @@
1
+ <main 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(".authorize_with", authorizer: t("#{params[:handler]}.name", scope: "decidim.authorization_handlers")) %></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
+ <%= authorization_form_for(handler, url: authorizations_path(redirect_url: params[:redirect_url])) do |form| %>
14
+ <%= form.error_for(:base) %>
15
+
16
+ <% if lookup_context.exists?(handler.to_partial_path, [], true) %>
17
+ <%= render partial: handler.to_partial_path, locals: { handler: handler, form: form } %>
18
+ <% else %>
19
+ <%= form.all_fields %>
20
+ <div class="actions">
21
+ <%= form.submit t(".authorize"), class: "button expanded" %>
22
+ </div>
23
+ <% end %>
24
+ <% end %>
25
+ <p class="text-center skip">
26
+ <%= t("decidim.verifications.authorizations.skip_verification", link: link_to(t("decidim.verifications.authorizations.start_exploring"), cta_button_path).html_safe).html_safe %>.
27
+ </p>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </div>
33
+ </main>
@@ -0,0 +1,26 @@
1
+ <%= decidim_form_for(@form, url: pending_authorization_confirmation_path(@pending_authorization),
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
+ <%= link_to t(".reject"), pending_authorization_rejection_path(@pending_authorization), method: :post, class: "button alert tiny button--title destroy" %>
8
+ </h2>
9
+ </div>
10
+
11
+ <div class="card-section">
12
+ <div class="row column">
13
+ <%= image_tag @pending_authorization.verification_attachment.url(:big), class: "thumbnail" %>
14
+ </div>
15
+
16
+ <div class="row column">
17
+ <%= form.select :document_type, @form.document_types_for_select, prompt: true, selected: nil %>
18
+ <%= form.text_field :document_number, value: nil %>
19
+ </div>
20
+ </div>
21
+ </div>
22
+
23
+ <div class="button--double form-general-submit">
24
+ <%= form.submit t(".verify") %>
25
+ </div>
26
+ <% end %>
@@ -0,0 +1,32 @@
1
+ <div class="card">
2
+ <div class="card-divider">
3
+ <h2 class="card-title">
4
+ <%= t(".title") %>
5
+ </h2>
6
+ </div>
7
+ <div class="card-section">
8
+ <table class="table-list">
9
+ <thead>
10
+ <tr>
11
+ <th><%= t("activemodel.attributes.id") %></th>
12
+ <th><%= t("activemodel.attributes.id_document_upload.verification_attachment") %></th>
13
+ </tr>
14
+ </thead>
15
+ <tbody>
16
+ <tr>
17
+ <% @pending_authorizations.each do |authorization| %>
18
+ <td>
19
+ <%= link_to t(".verification_number", n: authorization.id),
20
+ new_pending_authorization_confirmation_path(authorization.id) %>
21
+ </td>
22
+ <td>
23
+ <%= link_to new_pending_authorization_confirmation_path(authorization.id) do %>
24
+ <%= image_tag authorization.verification_attachment.url(:thumbnail), class: "thumbnail-list" %>
25
+ <% end %>
26
+ </td>
27
+ <% end %>
28
+ </tr>
29
+ </tbody>
30
+ </table>
31
+ </div>
32
+ </div>