decidim-direct_verifications 0.22.1 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +32 -3
  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 +20 -18
  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 +2 -1
  21. data/app/views/decidim/direct_verifications/verification/admin/imports/new.html.erb +50 -0
  22. data/config/initializers/mail_previews.rb +5 -0
  23. data/config/locales/ca.yml +20 -20
  24. data/config/locales/cs.yml +69 -0
  25. data/config/locales/en.yml +29 -2
  26. data/config/locales/es.yml +20 -20
  27. data/config/locales/fr.yml +69 -0
  28. data/lib/decidim/direct_verifications.rb +24 -1
  29. data/lib/decidim/direct_verifications/authorize_user.rb +64 -0
  30. data/lib/decidim/direct_verifications/instrumenter.rb +58 -0
  31. data/lib/decidim/direct_verifications/parsers.rb +11 -0
  32. data/lib/decidim/direct_verifications/parsers/base_parser.rb +37 -0
  33. data/lib/decidim/direct_verifications/parsers/metadata_parser.rb +54 -0
  34. data/lib/decidim/direct_verifications/parsers/name_parser.rb +40 -0
  35. data/lib/decidim/direct_verifications/register_user.rb +54 -0
  36. data/lib/decidim/direct_verifications/revoke_user.rb +45 -0
  37. data/lib/decidim/direct_verifications/tests/factories.rb +11 -0
  38. data/lib/decidim/direct_verifications/tests/verification_controller_examples.rb +8 -3
  39. data/lib/decidim/direct_verifications/user_processor.rb +17 -101
  40. data/lib/decidim/direct_verifications/user_stats.rb +5 -5
  41. data/lib/decidim/direct_verifications/verification/admin_engine.rb +6 -1
  42. data/lib/decidim/direct_verifications/version.rb +3 -3
  43. metadata +37 -9
  44. data/lib/decidim/direct_verifications/config.rb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 860fec657e68dab8325cde196bbfaa66059ede6b76414bb250a549d5639ebe6e
4
- data.tar.gz: f40a1f9bb946c0254c518cba3dd05a1e1764bd23729270e80554076cd07ffc12
3
+ metadata.gz: 46d0f12ed4661879a4cdec82f1482875823fe9c5f4fba39c129e2a020d3c7f19
4
+ data.tar.gz: 5cf039fb0a1b3474082dbf7acc28013d8d0034c6d959c7c7ad589aca85c1fdf8
5
5
  SHA512:
6
- metadata.gz: 87f25e203fe473612d2b53ae4986a5452d2096f12543d00eba10c1a8ba7d04c09471cbc9a15eed4916281ea07186152c61d630d0e40320c27d63cde699b6b7a0
7
- data.tar.gz: b3c34eccfd75f9849c5866fc402969fc7c0e2c99313983bd302fe025254e299356790697ed34ab9f96ef8c4cace2c335dd3bb6f4dbb412f9073c4316c1554d10
6
+ metadata.gz: 4f960edacf1528f9801d6cfd82aa6898a5bffbf9233a2386a57cdb0c55c0a3d5ef45ddf501d1775db1ab325dbcd61925b012dcc3ab8bf83bedbd4630abbf3b03
7
+ data.tar.gz: 909e8c8be3368861bc6fe75c1290f820a4d697e20bf4ded85d9e91ec9a5b7a27d3aa65953d749460d3fe0efbfe132fd8aa586ac27e032782127463be98476a61
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # Decidim::DirectVerifications
2
2
 
3
- ![Test](https://github.com/Platoniq/decidim-verifications-direct_verifications/workflows/Test/badge.svg)
3
+ [![Test](https://github.com/Platoniq/decidim-verifications-direct_verifications/actions/workflows/test.yml/badge.svg)](https://github.com/Platoniq/decidim-verifications-direct_verifications/actions/workflows/test.yml)
4
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/2195deb4de6c6354a6bc/maintainability)](https://codeclimate.com/github/Platoniq/decidim-verifications-direct_verifications/maintainability)
5
- [![codecov](https://codecov.io/gh/Platoniq/decidim-verifications-direct_verifications/branch/master/graph/badge.svg?token=FR1zkV71S2)](https://codecov.io/gh/Platoniq/decidim-verifications-direct_verifications)
5
+ [![codecov](https://codecov.io/gh/Platoniq/decidim-verifications-direct_verifications/branch/main/graph/badge.svg?token=FR1zkV71S2)](https://codecov.io/gh/Platoniq/decidim-verifications-direct_verifications)
6
+
7
+
6
8
 
7
9
  A [Decidim](https://github.com/decidim/decidim) that provides a verification method called `Direct verification`. Works only on the admin side, final users do not intervene in the verification process.
8
10
 
@@ -36,6 +38,23 @@ With the detected list of emails admin have different options available:
36
38
  3. Revoke the authorization for the list of users using any verification method available.
37
39
  4. Check the status of the users in order to know if they are verified or registered.
38
40
 
41
+ ### Metadata mode
42
+
43
+ This mode provides extra capabilities over the default processing:
44
+
45
+ * Reads CSV format with header (copy and paste it from your spreadsheet)
46
+ * Stores all columns except the email as authorization metadata
47
+
48
+ This enables querying the authorization metadata however fits you best.
49
+
50
+ To enable it create a new initializer, for instance `config/initializers/decidim_direct_verifications.rb` with the following contents
51
+
52
+ ```ruby
53
+ Decidim::DirectVerifications.configure do |config|
54
+ config.input_parser = :metadata_parser
55
+ end
56
+ ```
57
+
39
58
  ## Installation
40
59
 
41
60
  Add this line to your application's Gemfile:
@@ -50,6 +69,13 @@ And then execute:
50
69
  bundle
51
70
  ```
52
71
 
72
+ Depending on your Decidim version, you might want to specify the version to ensure compatibility:
73
+
74
+ | Direct Verifications version | Compatible Decidim versions |
75
+ |---|---|
76
+ | 1.0 | >= 0.23.x |
77
+ | 0.22.x | 0.22.x |
78
+
53
79
  ## Using additional verification methods
54
80
 
55
81
  You can manage other verification methods (or workflow) a part from `Direct verification`. You need to configure it in a new file in the `config/initializers` folder.
@@ -70,7 +96,10 @@ end
70
96
 
71
97
  # We need to tell the plugin to handle this method in addition to the default "Direct verification". Any registered workflow is valid.
72
98
  Decidim::DirectVerifications.configure do |config|
73
- config.manage_workflows = %w(direct_verifications_managers)
99
+ config.manage_workflows = %w(direct_verifications direct_verifications_managers)
100
+
101
+ # change the to the metadata_parser if you want it
102
+ # config.input_parser = :metadata_parser
74
103
  end
75
104
 
76
105
  ```
@@ -0,0 +1,3 @@
1
+ /*
2
+ *= link decidim/direct_verifications/authorizations.css
3
+ */
@@ -0,0 +1,17 @@
1
+ @import "decidim/admin/utils/settings";
2
+
3
+ $code-color: $black;
4
+ $code-font-family: $font-family-monospace;
5
+ $code-font-weight: $global-weight-normal;
6
+ $code-background: $light-gray;
7
+ $code-border: 1px solid $medium-gray;
8
+ $code-padding: rem-calc(2 5 1);
9
+
10
+ .code {
11
+ background: $code-background;
12
+ color: $code-color;
13
+ font-family: $code-font-family;
14
+ font-weight: $code-font-weight;
15
+ border: $code-border;
16
+ padding: $code-padding;
17
+ }
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DirectVerifications
5
+ module Verification
6
+ class CreateImport < Rectify::Command
7
+ def initialize(form)
8
+ @form = form
9
+ @file = form.file
10
+ @organization = form.organization
11
+ @user = form.user
12
+ @action = form.action
13
+ end
14
+
15
+ def call
16
+ return broadcast(:invalid) unless form.valid?
17
+
18
+ case action
19
+ when :register
20
+ register_users_async
21
+ when :register_and_authorize
22
+ register_users_async
23
+ file.rewind
24
+ authorize_users_async
25
+ when :revoke
26
+ revoke_users_async
27
+ end
28
+
29
+ broadcast(:ok)
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :form, :file, :organization, :user, :action
35
+
36
+ def register_users_async
37
+ RegisterUsersJob.perform_later(file.read, organization, user, form.authorization_handler)
38
+ end
39
+
40
+ def revoke_users_async
41
+ RevokeUsersJob.perform_later(file.read, organization, user, form.authorization_handler)
42
+ end
43
+
44
+ def authorize_users_async
45
+ AuthorizeUsersJob.perform_later(file.read, organization, user, form.authorization_handler)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DirectVerifications
5
+ module Verification
6
+ module Admin
7
+ class AuthorizationsController < Decidim::Admin::ApplicationController
8
+ layout "decidim/admin/users"
9
+
10
+ def index
11
+ enforce_permission_to :index, :authorization
12
+ @authorizations = collection.includes(:user)
13
+ end
14
+
15
+ def destroy
16
+ if authorization.destroy
17
+ flash[:notice] = "successfully"
18
+ redirect_to authorizations_path
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def collection
25
+ # Decidim::Verifications::Authorizations Query
26
+ Decidim::Verifications::Authorizations.new(
27
+ organization: current_organization,
28
+ name: "direct_verifications",
29
+ granted: true
30
+ ).query
31
+ end
32
+
33
+ def authorization
34
+ @authorization ||= collection.find_by(id: params[:id])
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -18,29 +18,39 @@ module Decidim
18
18
  enforce_permission_to :create, :authorization
19
19
 
20
20
  @userslist = params[:userslist]
21
- @processor = UserProcessor.new(current_organization, current_user, session)
22
- @processor.emails = extract_emails_to_hash @userslist
21
+
22
+ @processor = UserProcessor.new(current_organization, current_user, session, instrumenter)
23
+ @processor.emails = parser_class.new(@userslist).to_h
23
24
  @processor.authorization_handler = current_authorization_handler
25
+
24
26
  @stats = UserStats.new(current_organization)
25
27
  @stats.authorization_handler = @processor.authorization_handler
28
+
26
29
  register_users
27
30
  authorize_users
28
31
  revoke_users
29
32
 
30
33
  render(action: :index) && return if show_users_info
31
34
 
35
+ redirect_to direct_verifications_path
36
+ rescue InputParserError => e
37
+ flash[:error] = e.message
32
38
  redirect_to direct_verifications_path
33
39
  end
34
40
 
35
41
  private
36
42
 
43
+ def instrumenter
44
+ @instrumenter ||= Instrumenter.new(current_user)
45
+ end
46
+
37
47
  def register_users
38
48
  return unless params[:register]
39
49
 
40
50
  @processor.register_users
41
51
  flash[:warning] = t(".registered", count: @processor.emails.count,
42
- registered: @processor.processed[:registered].count,
43
- errors: @processor.errors[:registered].count)
52
+ registered: instrumenter.processed_count(:registered),
53
+ errors: instrumenter.errors_count(:registered))
44
54
  end
45
55
 
46
56
  def authorize_users
@@ -49,8 +59,8 @@ module Decidim
49
59
  @processor.authorize_users
50
60
  flash[:notice] = t(".authorized", handler: t("#{@processor.authorization_handler}.name", scope: "decidim.authorization_handlers"),
51
61
  count: @processor.emails.count,
52
- authorized: @processor.processed[:authorized].count,
53
- errors: @processor.errors[:authorized].count)
62
+ authorized: instrumenter.processed_count(:authorized),
63
+ errors: instrumenter.errors_count(:authorized))
54
64
  end
55
65
 
56
66
  def revoke_users
@@ -59,8 +69,8 @@ module Decidim
59
69
  @processor.revoke_users
60
70
  flash[:notice] = t(".revoked", handler: t("#{@processor.authorization_handler}.name", scope: "decidim.authorization_handlers"),
61
71
  count: @processor.emails.count,
62
- revoked: @processor.processed[:revoked].count,
63
- errors: @processor.errors[:revoked].count)
72
+ revoked: instrumenter.processed_count(:revoked),
73
+ errors: instrumenter.errors_count(:revoked))
64
74
  end
65
75
 
66
76
  def show_users_info
@@ -75,16 +85,8 @@ module Decidim
75
85
  true
76
86
  end
77
87
 
78
- def extract_emails_to_hash(txt)
79
- reg = /([A-Z0-9+._-]+@[A-Z0-9._-]+\.[A-Z0-9_-]+)\b/i
80
- emails = {}
81
- txt.split(/[\r\n;,]/).each do |line|
82
- reg.match line do |m|
83
- n = line.split(m[0]).first
84
- emails[m[0]] = (n.presence || "").gsub(/[^[:print:]]|[\"\$\<\>\|\\]/, "").strip
85
- end
86
- end
87
- emails
88
+ def parser_class
89
+ Decidim::DirectVerifications.find_parser_class(Decidim::DirectVerifications.input_parser)
88
90
  end
89
91
 
90
92
  def authorization_handler(authorization_handler)
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DirectVerifications
5
+ module Verification
6
+ module Admin
7
+ class ImportsController < Decidim::Admin::ApplicationController
8
+ layout "decidim/admin/users"
9
+ helper_method :workflows, :current_authorization_handler
10
+
11
+ def new
12
+ enforce_permission_to :create, :authorization
13
+ @form = form(CreateImportForm).instance
14
+ end
15
+
16
+ def create
17
+ enforce_permission_to :create, :authorization
18
+
19
+ defaults = { organization: current_organization, user: current_user }
20
+ form = form(CreateImportForm).from_params(params.merge(defaults))
21
+
22
+ CreateImport.call(form) do
23
+ on(:ok) do
24
+ flash[:notice] = t(".success")
25
+ end
26
+
27
+ on(:invalid) do
28
+ flash[:alert] = t(".error")
29
+ end
30
+ end
31
+
32
+ redirect_to new_import_path
33
+ end
34
+
35
+ def workflows
36
+ workflows = configured_workflows & current_organization.available_authorizations.map.to_a
37
+ workflows.map do |workflow|
38
+ [t("#{workflow}.name", scope: "decidim.authorization_handlers"), workflow]
39
+ end
40
+ end
41
+
42
+ def configured_workflows
43
+ return Decidim::DirectVerifications.config.manage_workflows if Decidim::DirectVerifications.config
44
+
45
+ ["direct_verifications"]
46
+ end
47
+
48
+ def current_authorization_handler
49
+ params[:authorization_handler]
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DirectVerifications
5
+ class RegistrationForm < OpenStruct
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module DirectVerifications
5
+ module Verification
6
+ class CreateImportForm < Form
7
+ ACTIONS = {
8
+ "in" => :authorize,
9
+ "out" => :revoke,
10
+ "check" => :check
11
+ }.freeze
12
+
13
+ attribute :file
14
+ attribute :organization, Decidim::Organization
15
+ attribute :user, Decidim::User
16
+ attribute :authorize, String
17
+ attribute :register, Boolean
18
+ attribute :authorization_handler, String
19
+
20
+ validates :file, :organization, :user, :authorize, :authorization_handler, presence: true
21
+ validates :authorize, inclusion: { in: ACTIONS.keys }
22
+
23
+ validate :available_authorization_handler
24
+
25
+ def available_authorization_handler
26
+ return if authorization_handler.in?(organization.available_authorizations)
27
+
28
+ errors.add(:authorization_handler, :inclusion)
29
+ end
30
+
31
+ def action
32
+ if register && authorize == "in"
33
+ :register_and_authorize
34
+ elsif register
35
+ :register
36
+ else
37
+ ACTIONS[authorize]
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -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