decidim-direct_verifications 0.17.8 → 1.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +43 -2
  3. data/app/assets/config/direct_verifications_admin_manifest.css +3 -0
  4. data/app/assets/stylesheets/decidim/direct_verifications/authorizations.scss +17 -0
  5. data/app/commands/decidim/direct_verifications/verification/create_import.rb +50 -0
  6. data/app/controllers/decidim/direct_verifications/verification/admin/authorizations_controller.rb +40 -0
  7. data/app/controllers/decidim/direct_verifications/verification/admin/direct_verifications_controller.rb +71 -46
  8. data/app/controllers/decidim/direct_verifications/verification/admin/imports_controller.rb +55 -0
  9. data/app/forms/decidim/direct_verifications/registration_form.rb +8 -0
  10. data/app/forms/decidim/direct_verifications/verification/create_import_form.rb +43 -0
  11. data/app/jobs/decidim/direct_verifications/authorize_users_job.rb +34 -0
  12. data/app/jobs/decidim/direct_verifications/base_import_job.rb +38 -0
  13. data/app/jobs/decidim/direct_verifications/register_users_job.rb +19 -0
  14. data/app/jobs/decidim/direct_verifications/revoke_users_job.rb +17 -0
  15. data/app/mailers/decidim/direct_verifications/import_mailer.rb +27 -0
  16. data/app/mailers/decidim/direct_verifications/stats.rb +23 -0
  17. data/app/views/decidim/direct_verifications/import_mailer/finished_processing.html.erb +7 -0
  18. data/app/views/decidim/direct_verifications/import_mailer/finished_processing.text.erb +7 -0
  19. data/app/views/decidim/direct_verifications/verification/admin/authorizations/index.html.erb +42 -0
  20. data/app/views/decidim/direct_verifications/verification/admin/direct_verifications/index.html.erb +18 -17
  21. data/app/views/decidim/direct_verifications/verification/admin/imports/new.html.erb +50 -0
  22. data/app/views/decidim/direct_verifications/verification/admin/stats/index.html.erb +3 -3
  23. data/config/initializers/mail_previews.rb +5 -0
  24. data/config/locales/ca.yml +25 -20
  25. data/config/locales/cs.yml +69 -0
  26. data/config/locales/en.yml +34 -2
  27. data/config/locales/es.yml +25 -20
  28. data/config/locales/fr.yml +69 -0
  29. data/lib/decidim/direct_verifications.rb +24 -1
  30. data/lib/decidim/direct_verifications/authorize_user.rb +64 -0
  31. data/lib/decidim/direct_verifications/instrumenter.rb +58 -0
  32. data/lib/decidim/direct_verifications/parsers.rb +11 -0
  33. data/lib/decidim/direct_verifications/parsers/base_parser.rb +37 -0
  34. data/lib/decidim/direct_verifications/parsers/metadata_parser.rb +54 -0
  35. data/lib/decidim/direct_verifications/parsers/name_parser.rb +40 -0
  36. data/lib/decidim/direct_verifications/register_user.rb +54 -0
  37. data/lib/decidim/direct_verifications/revoke_user.rb +45 -0
  38. data/lib/decidim/direct_verifications/tests/factories.rb +11 -0
  39. data/lib/decidim/direct_verifications/tests/verification_controller_examples.rb +83 -0
  40. data/lib/decidim/direct_verifications/user_processor.rb +18 -98
  41. data/lib/decidim/direct_verifications/user_stats.rb +9 -6
  42. data/lib/decidim/direct_verifications/verification/admin_engine.rb +6 -1
  43. data/lib/decidim/direct_verifications/version.rb +3 -2
  44. metadata +38 -9
  45. data/lib/decidim/direct_verifications/config.rb +0 -23
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/direct_verifications/instrumenter"
4
+
5
+ module Decidim
6
+ module DirectVerifications
7
+ class AuthorizeUsersJob < BaseImportJob
8
+ class NullSession; end
9
+
10
+ def process_users
11
+ emails.each do |email, data|
12
+ AuthorizeUser.new(
13
+ email,
14
+ data,
15
+ session,
16
+ organization,
17
+ instrumenter,
18
+ authorization_handler
19
+ ).call
20
+ end
21
+ end
22
+
23
+ def type
24
+ :authorized
25
+ end
26
+
27
+ private
28
+
29
+ def session
30
+ NullSession.new
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/direct_verifications/instrumenter"
4
+
5
+ module Decidim
6
+ module DirectVerifications
7
+ # This class implements the logic to import the user entries and sending an email notification
8
+ # with the result. The specifics to process the entries are meant to be implemented by
9
+ # subclasses which must implement the `#process_users` and `#type` methods.
10
+ class BaseImportJob < ApplicationJob
11
+ queue_as :default
12
+
13
+ def perform(userslist, organization, current_user, authorization_handler)
14
+ @emails = Parsers::MetadataParser.new(userslist).to_h
15
+ @organization = organization
16
+ @current_user = current_user
17
+ @instrumenter = Instrumenter.new(current_user)
18
+ @authorization_handler = authorization_handler
19
+
20
+ process_users
21
+ send_email_notification
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :emails, :organization, :current_user, :instrumenter, :authorization_handler
27
+
28
+ def send_email_notification
29
+ ImportMailer.finished_processing(
30
+ current_user,
31
+ instrumenter,
32
+ type,
33
+ authorization_handler
34
+ ).deliver_now
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/direct_verifications/instrumenter"
4
+
5
+ module Decidim
6
+ module DirectVerifications
7
+ class RegisterUsersJob < BaseImportJob
8
+ def process_users
9
+ emails.each do |email, data|
10
+ RegisterUser.new(email, data, organization, current_user, instrumenter).call
11
+ end
12
+ end
13
+
14
+ def type
15
+ :registered
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DirectVerifications
5
+ class RevokeUsersJob < BaseImportJob
6
+ def process_users
7
+ emails.each do |email, _name|
8
+ RevokeUser.new(email, organization, instrumenter, authorization_handler).call
9
+ end
10
+ end
11
+
12
+ def type
13
+ :revoked
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DirectVerifications
5
+ class ImportMailer < Decidim::Admin::ApplicationMailer
6
+ include LocalisedMailer
7
+
8
+ layout "decidim/mailer"
9
+
10
+ I18N_SCOPE = "decidim.direct_verifications.verification.admin.imports.mailer"
11
+
12
+ def finished_processing(user, instrumenter, type, handler)
13
+ @stats = Stats.from(instrumenter, type)
14
+ @organization = user.organization
15
+ @i18n_key = "#{I18N_SCOPE}.#{type}"
16
+ @handler = handler
17
+
18
+ with_user(user) do
19
+ mail(
20
+ to: user.email,
21
+ subject: I18n.t("#{I18N_SCOPE}.subject")
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DirectVerifications
5
+ class Stats
6
+ attr_reader :count, :successful, :errors
7
+
8
+ def self.from(instrumenter, type)
9
+ new(
10
+ count: instrumenter.emails_count(type),
11
+ successful: instrumenter.processed_count(type),
12
+ errors: instrumenter.errors_count(type)
13
+ )
14
+ end
15
+
16
+ def initialize(count:, successful:, errors:)
17
+ @count = count
18
+ @successful = successful
19
+ @errors = errors
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ <p><%= t(
2
+ @i18n_key,
3
+ count: @stats.count,
4
+ successful: @stats.successful,
5
+ errors: @stats.errors,
6
+ handler: @handler
7
+ ) %></p>
@@ -0,0 +1,7 @@
1
+ <%= t(
2
+ @i18n_key,
3
+ count: @stats.count,
4
+ successful: @stats.successful,
5
+ errors: @stats.errors,
6
+ handler: @handler
7
+ ) %>
@@ -0,0 +1,42 @@
1
+ <%= stylesheet_link_tag "decidim/direct_verifications/authorizations" %>
2
+
3
+ <div class="card">
4
+ <div class="card-divider">
5
+ <h2 class="card-title">
6
+ <%= t(".title") %>
7
+ <%= link_to t("admin.index.stats", scope: "decidim.direct_verifications.verification"), stats_path, class: "button tiny button--title" %>
8
+ <%= link_to t(".new_import"), direct_verifications_path, class: "button tiny button--title" %>
9
+ </h2>
10
+ </div>
11
+ <div class="card-section">
12
+ <div class="table-scroll">
13
+ <table class="table-list">
14
+ <thead>
15
+ <tr>
16
+ <th><%= t(".name") %></th>
17
+ <th><%= t(".metadata") %></th>
18
+ <th><%= t(".user_name") %></th>
19
+ <th><%= t(".created_at") %></th>
20
+ <th>&nbsp;</th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ <% @authorizations.each do |authorization| %>
25
+ <tr data-authorization-id="<%= authorization.id %>">
26
+ <td><%= authorization.name %></td>
27
+ <td class="metadata">
28
+ <span class="code"><%= authorization.metadata %></span>
29
+ </td>
30
+ <td><%= authorization.user.name %></td>
31
+ <td><%= authorization.created_at %></td>
32
+
33
+ <td class="table-list__actions">
34
+ <%= icon_link_to "circle-x", authorization_path(authorization), t("actions.destroy", scope: "decidim.admin"), class: "action-icon--remove", method: :delete, data: { confirm: t("actions.confirm_destroy", scope: "decidim.admin") } %>
35
+ </td>
36
+ </tr>
37
+ <% end %>
38
+ </tbody>
39
+ </table>
40
+ </div>
41
+ </div>
42
+ </div>
@@ -1,40 +1,41 @@
1
1
  <div class="card">
2
2
  <div class="card-divider">
3
3
  <h2 class="card-title">
4
- <%= t('admin.index.title', scope: 'decidim.direct_verifications.verification') %>
5
- <%= link_to t("admin.index.stats", scope: 'decidim.direct_verifications.verification'), stats_path, class: "button tiny button--title" %>
4
+ <%= t("admin.index.title", scope: "decidim.direct_verifications.verification") %>
5
+ <%= link_to t("admin.index.stats", scope: "decidim.direct_verifications.verification"), stats_path, class: "button tiny button--title" %>
6
+ <%= link_to t("admin.index.authorizations", scope: "decidim.direct_verifications.verification"), authorizations_path, class: "button tiny button--title" %>
6
7
  </h2>
7
8
  </div>
8
9
  <div class="card-section">
9
- <p><%= t('decidim.direct_verifications.verification.admin.new.info') %></p>
10
- <%= form_tag direct_verifications_path, multipart: true, class: 'form' do %>
11
- <%= label_tag :userlist, t('admin.new.textarea', scope: 'decidim.direct_verifications.verification') %>
12
- <%= text_area_tag :userlist, @userlist, rows: 10 %>
10
+ <p><%= t("decidim.direct_verifications.verification.admin.new.info_html", link: new_import_path) %></p>
11
+ <%= form_tag direct_verifications_path, multipart: true, class: "form" do %>
12
+ <%= label_tag :userslist, t("admin.new.textarea", scope: "decidim.direct_verifications.verification") %>
13
+ <%= text_area_tag :userslist, @userslist, rows: 10 %>
13
14
  <label>
14
15
  <%= check_box_tag :register %>
15
- <%= t('admin.new.register', scope: 'decidim.direct_verifications.verification') %>
16
+ <%= t("admin.new.register", scope: "decidim.direct_verifications.verification") %>
16
17
  <div data-alert class="callout alert hide">
17
- <%= t('admin.direct_verifications.gdpr_disclaimer', scope: 'decidim.direct_verifications.verification') %>
18
+ <%= t("admin.direct_verifications.gdpr_disclaimer", scope: "decidim.direct_verifications.verification") %>
18
19
  </div>
19
20
  </label>
20
21
  <label>
21
- <%= radio_button_tag :authorize, 'in' %>
22
- <%= t('admin.new.authorize', scope: 'decidim.direct_verifications.verification') %>
22
+ <%= radio_button_tag :authorize, "in" %>
23
+ <%= t("admin.new.authorize", scope: "decidim.direct_verifications.verification") %>
23
24
  </label>
24
25
  <label>
25
- <%= radio_button_tag :authorize, 'out' %>
26
- <%= t('admin.new.revoke', scope: 'decidim.direct_verifications.verification') %>
26
+ <%= radio_button_tag :authorize, "out" %>
27
+ <%= t("admin.new.revoke", scope: "decidim.direct_verifications.verification") %>
27
28
  </label>
28
29
  <label>
29
- <%= radio_button_tag :authorize, 'check', true %>
30
- <%= t('admin.new.check', scope: 'decidim.direct_verifications.verification') %>
30
+ <%= radio_button_tag :authorize, "check", true %>
31
+ <%= t("admin.new.check", scope: "decidim.direct_verifications.verification") %>
31
32
  </label>
32
33
 
33
- <%= label_tag :authorization_handler, t('admin.new.authorization_handler', scope: 'decidim.direct_verifications.verification') %>
34
+ <%= label_tag :authorization_handler, t("admin.new.authorization_handler", scope: "decidim.direct_verifications.verification") %>
34
35
 
35
- <%= select_tag :authorization_handler, options_for_select(@workflows, @authorization_handler) %>
36
+ <%= select_tag :authorization_handler, options_for_select(workflows, current_authorization_handler) %>
36
37
 
37
- <%= submit_tag t('admin.new.submit', scope: 'decidim.direct_verifications.verification'), class: 'button' %>
38
+ <%= submit_tag t("admin.new.submit", scope: "decidim.direct_verifications.verification"), class: "button" %>
38
39
 
39
40
  <% end %>
40
41
 
@@ -0,0 +1,50 @@
1
+ <div class="card">
2
+ <div class="card-divider">
3
+ <h2 class="card-title">
4
+ <%= t("admin.index.title", scope: "decidim.direct_verifications.verification") %>
5
+ <%= link_to t("admin.index.stats", scope: "decidim.direct_verifications.verification"), stats_path, class: "button tiny button--title" %>
6
+ <%= link_to t("admin.index.authorizations", scope: "decidim.direct_verifications.verification"), authorizations_path, class: "button tiny button--title" %>
7
+ </h2>
8
+ </div>
9
+ <div class="card-section">
10
+ <p><%= t("decidim.direct_verifications.verification.admin.imports.new.info") %></p>
11
+ <pre class="code-block">
12
+ <strong>email, name, membership_phone, membership_type, membership_weight</strong>
13
+ ava@example.com, Ava Hawkins, +3476318371, consumer, 1
14
+ ewan@example.com, Ewan Cooper, +34653565765, worker, 1
15
+ tilly@example.com, Tilly Jones, +34653565761, collaborator, 0.67
16
+ ...
17
+ </pre>
18
+
19
+ <%= decidim_form_for(@form, url: imports_path, html: { class: "form" }) do |form| %>
20
+ <label>
21
+ <%= check_box_tag :register %>
22
+ <%= t("admin.new.register", scope: "decidim.direct_verifications.verification") %>
23
+ <div data-alert class="callout alert hide">
24
+ <%= t("admin.direct_verifications.gdpr_disclaimer", scope: "decidim.direct_verifications.verification") %>
25
+ </div>
26
+ </label>
27
+ <label>
28
+ <%= radio_button_tag :authorize, "in" %>
29
+ <%= t("admin.new.authorize", scope: "decidim.direct_verifications.verification") %>
30
+ </label>
31
+ <label>
32
+ <%= radio_button_tag :authorize, "out" %>
33
+ <%= t("admin.new.revoke", scope: "decidim.direct_verifications.verification") %>
34
+ </label>
35
+ <label>
36
+ <%= radio_button_tag :authorize, "check", true %>
37
+ <%= t("admin.new.check", scope: "decidim.direct_verifications.verification") %>
38
+ </label>
39
+
40
+ <%= label_tag :authorization_handler, t("admin.new.authorization_handler", scope: "decidim.direct_verifications.verification") %>
41
+ <%= select_tag :authorization_handler, options_for_select(workflows, current_authorization_handler) %>
42
+
43
+ <%= form.file_field :file, label: t(".file") %>
44
+ <%= form.submit t(".submit"), class: "button" %>
45
+ <% end %>
46
+
47
+ </div>
48
+ </div>
49
+
50
+ <%= javascript_include_tag "decidim/direct_verifications/verification/admin/direct_verifications_admin" %>
@@ -1,15 +1,15 @@
1
1
  <div class="card">
2
2
  <div class="card-divider">
3
3
  <h2 class="card-title">
4
- <%= t('admin.index.stats', scope: 'decidim.direct_verifications.verification') %>
5
- <%= link_to t("admin.index.title", scope: 'decidim.direct_verifications.verification'), direct_verifications_path, class: "button tiny button--title" %>
4
+ <%= t("admin.index.stats", scope: "decidim.direct_verifications.verification") %>
5
+ <%= link_to t("admin.index.title", scope: "decidim.direct_verifications.verification"), direct_verifications_path, class: "button tiny button--title" %>
6
6
  </h2>
7
7
  </div>
8
8
  <div class="card-section">
9
9
  <table class="table-list">
10
10
  <thead>
11
11
  <tr>
12
- <th><%= t("admin.new.authorization_handler", scope: 'decidim.direct_verifications.verification') %></th>
12
+ <th><%= t("admin.new.authorization_handler", scope: "decidim.direct_verifications.verification") %></th>
13
13
  <th><%= t(".registered") %></th>
14
14
  <th><%= t(".authorized") %></th>
15
15
  <th><%= t(".unconfirmed") %></th>
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.configure do
4
+ config.action_mailer.preview_path = Decidim::DirectVerifications::Verification::Engine.root.join("spec/mailers")
5
+ end
@@ -1,4 +1,3 @@
1
- ---
2
1
  ca:
3
2
  decidim:
4
3
  admin:
@@ -11,40 +10,41 @@ ca:
11
10
  admin:
12
11
  direct_verifications:
13
12
  help:
14
- - 'Permet la introducció massiva d''usuaris per tal de:'
15
- - Registrar-los directament a la organització amb l'enviament d'invitacions
16
- - Verificar-los en qualsevol mètode de verificació actiu
17
- - Revocar la verificació en qualsevol mètode de verificació actiu
13
+ - 'Permet la introducció massiva d''usuaris per tal de:'
14
+ - Registrar-los directament a la organització amb l'enviament d'invitacions
15
+ - Verificar-los en qualsevol mètode de verificació actiu
16
+ - Revocar la verificació en qualsevol mètode de verificació actiu
18
17
  direct_verifications:
19
18
  explanation: Verificació manual per par dels administradors de l'organització
20
19
  name: Verificació directa
21
20
  direct_verifications:
22
21
  verification:
23
22
  admin:
23
+ authorizations:
24
+ index:
25
+ created_at: Data de creació
26
+ metadata: Metadades
27
+ name: Nom
28
+ title: Autoritzacions
29
+ user_name: Nom d'usuari
30
+ new_import: Nova importació
24
31
  direct_verifications:
25
32
  create:
26
- authorized: S'han verificat correctament %{authorized} usuaris utilitzant
27
- [%{handler}] (%{count} detectats, %{errors} errors)
28
- info: S'han detectat %{count} usuaris, dels quals %{registered} estan
29
- registrats, %{authorized} autoritzats utilitzant [%{handler}] (%{unconfirmed}
30
- sense confirmar)
31
- registered: S'han registrat correctament %{registered} usuaris (%{count}
32
- detectats, %{errors} errors)
33
- revoked: S'ha revocat correctament la verificació de %{revoked} usuaris
34
- utilitzant [%{handler}] (%{count} detectats, %{errors} errors)
35
- gdpr_disclaimer: Feu-ho sota la vostra responsabilitat. Recordeu que heu
36
- de tenir el consentiment explícit dels vostres usuaris per registrar-los.
37
- En cas contrari, estareu infringint la regulació GDPR als països de
38
- la UE.
33
+ authorized: "S'han verificat correctament %{authorized} usuaris utilitzant [%{handler}] (%{count} detectats, %{errors} errors)"
34
+ info: "S'han detectat %{count} usuaris, dels quals %{registered} estan registrats, %{authorized} autoritzats utilitzant [%{handler}] (%{unconfirmed} sense confirmar)"
35
+ missing_header: Si us plau, proporcioneu una fila d'encapçalament
36
+ registered: "S'han registrat correctament %{registered} usuaris (%{count} detectats, %{errors} errors)"
37
+ revoked: S'ha revocat correctament la verificació de %{revoked} usuaris utilitzant [%{handler}] (%{count} detectats, %{errors} errors)
38
+ gdpr_disclaimer: Feu-ho sota la vostra responsabilitat. Recordeu que heu de tenir el consentiment explícit dels vostres usuaris per registrar-los. En cas contrari, estareu infringint la regulació GDPR als països de la UE.
39
39
  index:
40
+ authorizations: Usuaris autoritzats
40
41
  stats: Estadístiques d'usuaris
41
42
  title: Inscriu i autoritza usuaris
42
43
  new:
43
44
  authorization_handler: Mètode de verificació
44
45
  authorize: Autoritza els usuaris
45
46
  check: Comprova l'estat dels usuaris
46
- info: Introdueix aquí els emails, un per línia. Si els emails estan precedits
47
- per un text, s'interpretarà com el nom de l'usuari
47
+ info: Introdueix aquí els emails, un per línia. Si els emails estan precedits per un text, s'interpretarà com el nom de l'usuari
48
48
  register: Registra els usuaris a la plataforma (si existeixen s'ignoraran)
49
49
  revoke: Revoca l'autorització dels usuaris
50
50
  submit: Envia i processa el llistat
@@ -59,6 +59,11 @@ ca:
59
59
  authorizations:
60
60
  new:
61
61
  no_action: Aquest mètode requereix que un administrador us verifiqui
62
+ verifications:
63
+ authorizations:
64
+ first_login:
65
+ actions:
66
+ direct_verifications: Verificació directa
62
67
  devise:
63
68
  mailer:
64
69
  direct_invite: