decidim-direct_verifications 0.17.8 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
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: