decidim-file_authorization_handler 0.27.1.5

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 (40) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +661 -0
  3. data/README.md +137 -0
  4. data/Rakefile +3 -0
  5. data/app/controllers/decidim/file_authorization_handler/admin/censuses_controller.rb +34 -0
  6. data/app/jobs/decidim/file_authorization_handler/application_job.rb +8 -0
  7. data/app/jobs/decidim/file_authorization_handler/remove_duplicates_job.rb +30 -0
  8. data/app/models/decidim/file_authorization_handler/application_record.rb +9 -0
  9. data/app/models/decidim/file_authorization_handler/census_datum.rb +70 -0
  10. data/app/models/decidim/file_authorization_handler/csv_data.rb +40 -0
  11. data/app/models/decidim/file_authorization_handler/status.rb +27 -0
  12. data/app/permissions/decidim/file_authorization_handler/admin/permissions.rb +27 -0
  13. data/app/services/file_authorization_handler.rb +59 -0
  14. data/app/views/decidim/file_authorization_handler/admin/censuses/show.html.erb +39 -0
  15. data/app/views/layouts/file_authorization_handler/application.html.erb +14 -0
  16. data/config/locales/ca.yml +50 -0
  17. data/config/locales/en.yml +50 -0
  18. data/config/locales/es.yml +50 -0
  19. data/db/migrate/20171110120821_create_decidim_file_authorization_handler_census_datum.rb +15 -0
  20. data/db/migrate/20221207143742_add_extras_to_census_datum.rb +7 -0
  21. data/lib/decidim/file_authorization_handler/admin.rb +10 -0
  22. data/lib/decidim/file_authorization_handler/admin_engine.rb +23 -0
  23. data/lib/decidim/file_authorization_handler/engine.rb +22 -0
  24. data/lib/decidim/file_authorization_handler/version.rb +12 -0
  25. data/lib/decidim/file_authorization_handler.rb +11 -0
  26. data/spec/controllers/decidim/file_authorization_handler/admin/censuses_controller_spec.rb +57 -0
  27. data/spec/factories/census_datum.rb +14 -0
  28. data/spec/factories/factories.rb +3 -0
  29. data/spec/fixtures/files/data-with_extras.csv +5 -0
  30. data/spec/fixtures/files/data1.csv +4 -0
  31. data/spec/fixtures/files/with-errors.csv +7 -0
  32. data/spec/helpers/decidim/file_authorization_handler/encoding_helper.rb +11 -0
  33. data/spec/jobs/decidim/file_authorization_handler/remove_duplicates_job_spec.rb +20 -0
  34. data/spec/models/decidim/file_authorization_handler/census_datum_spec.rb +75 -0
  35. data/spec/models/decidim/file_authorization_handler/csv_data_spec.rb +41 -0
  36. data/spec/models/decidim/file_authorization_handler/status_spec.rb +21 -0
  37. data/spec/permissions/decidim/file_authorization_handler/admin/permissions_spec.rb +58 -0
  38. data/spec/services/decidim/file_authorization_handler/file_authorization_handler_spec.rb +77 -0
  39. data/spec/spec_helper.rb +23 -0
  40. metadata +196 -0
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddExtrasToCensusDatum < ActiveRecord::Migration[6.0]
4
+ def change
5
+ add_column :decidim_file_authorization_handler_census_data, :extras, :jsonb
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module FileAuthorizationHandler
5
+ # This module contains all the domain logic associated to Decidim's Census
6
+ # component admin panel.
7
+ module Admin
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module FileAuthorizationHandler
5
+ class AdminEngine < ::Rails::Engine
6
+ isolate_namespace Decidim::FileAuthorizationHandler::Admin
7
+
8
+ routes do
9
+ resource :censuses, only: [:show, :create, :destroy]
10
+ end
11
+
12
+ initializer "decidim_file_authorization.add_admin_menu" do
13
+ Decidim.menu :admin_menu do |menu|
14
+ menu.item I18n.t("decidim.file_authorization_handler.admin.menu.census"),
15
+ decidim_file_authorization_handler_admin.censuses_path,
16
+ icon_name: "spreadsheet",
17
+ position: 7,
18
+ active: :inclusive
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module FileAuthorizationHandler
5
+ # Census have no public app (see AdminEngine)
6
+ class Engine < ::Rails::Engine
7
+ isolate_namespace Decidim::FileAuthorizationHandler
8
+
9
+ initializer "decidim_census.add_irregular_inflection" do |_app|
10
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
11
+ inflect.irregular "census", "census"
12
+ end
13
+ end
14
+
15
+ initializer "decidim_census.add_authorization_handlers" do |_app|
16
+ Decidim::Verifications.register_workflow(:file_authorization_handler) do |workflow|
17
+ workflow.form = "FileAuthorizationHandler"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module FileAuthorizationHandler
5
+ DECIDIM_VERSION = "0.27.1"
6
+
7
+ # Uses the latest matching Decidim version for
8
+ # - major, minor and patch
9
+ # - the optional extra number is related to this module's patches
10
+ VERSION = "#{DECIDIM_VERSION}.5".freeze
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/file_authorization_handler/admin"
4
+ require "decidim/file_authorization_handler/engine"
5
+ require "decidim/file_authorization_handler/admin_engine"
6
+
7
+ module Decidim
8
+ # Base module for this engine.
9
+ module FileAuthorizationHandler
10
+ end
11
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ RSpec.describe Decidim::FileAuthorizationHandler::Admin::CensusesController, type: :controller do
5
+ include Warden::Test::Helpers
6
+
7
+ routes { Decidim::FileAuthorizationHandler::AdminEngine.routes }
8
+
9
+ let(:organization) do
10
+ create :organization,
11
+ available_authorizations: ["file_authorization_handler"]
12
+ end
13
+
14
+ let(:user) do
15
+ create :user, :admin, :confirmed, organization:, admin: true
16
+ end
17
+
18
+ before do
19
+ controller.request.env["decidim.current_organization"] = organization
20
+ end
21
+
22
+ describe "GET #show" do
23
+ it "returns http success" do
24
+ sign_in user, scope: :user
25
+ get :show
26
+
27
+ expect(response).to have_http_status(:success)
28
+ end
29
+ end
30
+
31
+ describe "POST #create" do
32
+ it "imports the csv data" do
33
+ sign_in user
34
+
35
+ # Don't know why don't prepend with `spec/fixtures` automatically
36
+ file = fixture_file_upload("spec/fixtures/files/data1.csv")
37
+ post :create, params: { file: }
38
+ expect(response).to have_http_status(:redirect)
39
+
40
+ expect(Decidim::FileAuthorizationHandler::CensusDatum.count).to be 3
41
+ expect(Decidim::FileAuthorizationHandler::CensusDatum.first.id_document).to eq encode_id_document("1111A")
42
+ expect(Decidim::FileAuthorizationHandler::CensusDatum.last.id_document).to eq encode_id_document("3333C")
43
+ end
44
+ end
45
+
46
+ describe "POST #delete_all" do
47
+ it "clear all census data" do
48
+ sign_in user
49
+
50
+ create_list :census_datum, 5, organization: organization
51
+ delete :destroy
52
+ expect(response).to have_http_status(:redirect)
53
+
54
+ expect(Decidim::FileAuthorizationHandler::CensusDatum.count).to be 0
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ factory :census_datum, class: "Decidim::FileAuthorizationHandler::CensusDatum" do
5
+ id_document { "123456789A" }
6
+ birthdate { 20.years.ago }
7
+ organization
8
+ extras { nil }
9
+
10
+ trait :with_extras do
11
+ extras { { district: "123456789", postal_code: "ABCDEFGHIJK", segment_1: Random.hex } }
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/core/test/factories"
@@ -0,0 +1,5 @@
1
+ DNI,Data de naixement,district
2
+ 1111A,1/1/1981,17600
3
+ 2222B,2/2/1982,17481
4
+ 3333C,1/1/2000,17820
5
+ 4444D,1/1/2017,17003
@@ -0,0 +1,4 @@
1
+ DNI,Data de naixement
2
+ 1111A,1/1/1981
3
+ 2222-b , 2/2/1982
4
+ 33 33 C,1/1/2017
@@ -0,0 +1,7 @@
1
+ DNI,Data de naixement
2
+ 1111A,1/1/1981
3
+ 2222B , 2/2/1982
4
+ ,1/6/1989
5
+ 12323B,fecha-no-valida
6
+ sasd
7
+ 3333A,3/3/1983
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module FileAuthorizationHandler
5
+ module EncodingHelper
6
+ def encode_id_document(id_document)
7
+ Digest::SHA256.hexdigest("#{id_document}-#{Rails.application.secrets.secret_key_base}")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Decidim::FileAuthorizationHandler::RemoveDuplicatesJob do
6
+ let(:org_1) { create :organization }
7
+ let(:org_2) { create :organization }
8
+
9
+ it "remove duplicates in the database" do
10
+ %w(AAA BBB AAA AAA).each do |doc|
11
+ create(:census_datum, id_document: doc, organization: org_1)
12
+ create(:census_datum, id_document: doc, organization: org_2)
13
+ end
14
+ expect(Decidim::FileAuthorizationHandler::CensusDatum.count).to be 8
15
+ described_class.new.perform org_1
16
+ expect(Decidim::FileAuthorizationHandler::CensusDatum.count).to be 6
17
+ described_class.new.perform org_2
18
+ expect(Decidim::FileAuthorizationHandler::CensusDatum.count).to be 4
19
+ end
20
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ RSpec.describe Decidim::FileAuthorizationHandler::CensusDatum, type: :model do
5
+ let(:organization) { create :organization }
6
+
7
+ # rubocop: disable Lint/ConstantDefinitionInBlock
8
+ CensusDatum = Decidim::FileAuthorizationHandler::CensusDatum
9
+ # rubocop: enable Lint/ConstantDefinitionInBlock
10
+
11
+ describe "get census for a given identity document" do
12
+ it "returns the last inserted when duplicates" do
13
+ create(:census_datum, id_document: encode_id_document("AAA"))
14
+ last = create(:census_datum, id_document: encode_id_document("AAA"), organization:)
15
+ expect(CensusDatum.search_id_document(organization, "AAA")).to eq(last)
16
+ end
17
+
18
+ it "normalizes the document" do
19
+ census = create(:census_datum, id_document: encode_id_document("AAA"), organization:)
20
+ expect(CensusDatum.search_id_document(organization, "a-a-a")).to eq(census)
21
+ end
22
+ end
23
+
24
+ context "with #insert_all" do
25
+ it "inserts a collection of values" do
26
+ # rubocop: disable Rails/SkipsModelValidations
27
+ CensusDatum.insert_all(organization, [["1111A", "1990/12/1"], ["2222B", "1990/12/2"]])
28
+ expect(CensusDatum.count).to be 2
29
+ CensusDatum.insert_all(organization, [["1111A", "2001/12/1"], ["3333C", "1990/12/3"]])
30
+ # rubocop: enable Rails/SkipsModelValidations
31
+ expect(CensusDatum.count).to be 4
32
+ end
33
+
34
+ context "when values is empty" do
35
+ it "returns without crashing" do
36
+ # rubocop: disable Rails/SkipsModelValidations
37
+ CensusDatum.insert_all(organization, [])
38
+ # rubocop: enable Rails/SkipsModelValidations
39
+ end
40
+ end
41
+
42
+ context "when extra columns exist" do
43
+ it "inserts extra columns in the #extras column" do
44
+ # rubocop: disable Rails/SkipsModelValidations
45
+ CensusDatum.insert_all(organization, [
46
+ ["1111A", "2001/12/1", "001", "1234"],
47
+ ["3333C", "1990/12/3", "ABCD", "01-12/33"],
48
+ ], %w(POSTAL_CODE DISTRICT))
49
+ # rubocop: enable Rails/SkipsModelValidations
50
+
51
+ inserts = CensusDatum.all
52
+ expect(inserts.size).to be 2
53
+ expect(inserts.first.extras).to eq({ "postal_code" => "001", "district" => "1234" })
54
+ expect(inserts.last.extras).to eq({ "postal_code" => "ABCD", "district" => "01-12/33" })
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "normalization methods" do
60
+ it "normalizes and encodes the id document" do
61
+ expect(CensusDatum.normalize_and_encode_id_document("1234a"))
62
+ .to eq encode_id_document("1234A")
63
+ expect(CensusDatum.normalize_and_encode_id_document(" 1234a "))
64
+ .to eq encode_id_document("1234A")
65
+ expect(CensusDatum.normalize_and_encode_id_document(")($·$")).to eq ""
66
+ expect(CensusDatum.normalize_and_encode_id_document(nil)).to eq ""
67
+ end
68
+
69
+ it "normalizes dates" do
70
+ expect(CensusDatum.parse_date("20/3/1992")).to eq Date.strptime("1992/03/20", "%Y/%m/%d")
71
+ expect(CensusDatum.parse_date("1/20/1992")).to be_nil
72
+ expect(CensusDatum.parse_date("n/3/1992")).to be_nil
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Decidim::FileAuthorizationHandler::CsvData do
6
+ let(:file) { file_fixture("data1.csv") }
7
+ let(:data) { described_class.new(file) }
8
+
9
+ it "loads from files" do
10
+ expect(data.values.length).to be 3
11
+ expect(data.values[0]).to eq [encode_id_document("1111A"), Date.strptime("1981/01/01", "%Y/%m/%d")]
12
+ expect(data.values[1]).to eq [encode_id_document("2222B"), Date.strptime("1982/02/02", "%Y/%m/%d")]
13
+ expect(data.values[2]).to eq [encode_id_document("3333C"), Date.strptime("2017/01/01", "%Y/%m/%d")]
14
+ end
15
+
16
+ it "returns the zero errored rows when all are good" do
17
+ expect(data.errors.count).to be 0
18
+ end
19
+
20
+ context "when file has errors" do
21
+ let(:file) { file_fixture("with-errors.csv") }
22
+
23
+ it "returns the number of errored rows" do
24
+ expect(data.errors.count).to be 3
25
+ end
26
+ end
27
+
28
+ context "with extra columns" do
29
+ let(:file) { file_fixture("data-with_extras.csv") }
30
+
31
+ it "parses all columns from file" do
32
+ expect(data.values.length).to be 4
33
+ expect(data.headers).to eq ["DNI", "Data de naixement", "district"]
34
+ expect(data.errors.count).to be 0
35
+ expect(data.values[0]).to eq [encode_id_document("1111A"), Date.strptime("1981/01/01", "%Y/%m/%d"), "17600"]
36
+ expect(data.values[1]).to eq [encode_id_document("2222B"), Date.strptime("1982/02/02", "%Y/%m/%d"), "17481"]
37
+ expect(data.values[2]).to eq [encode_id_document("3333C"), Date.strptime("2000/01/01", "%Y/%m/%d"), "17820"]
38
+ expect(data.values[3]).to eq [encode_id_document("4444D"), Date.strptime("2017/01/01", "%Y/%m/%d"), "17003"]
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Decidim::FileAuthorizationHandler::Status, type: :model do
6
+ let(:organization) { create :organization }
7
+
8
+ it "returns last import date" do
9
+ last = create :census_datum, organization: organization
10
+ status = Decidim::FileAuthorizationHandler::Status.new(organization)
11
+ expect(last.created_at.to_i).to eq status.last_import_at.to_i
12
+ end
13
+
14
+ it "retrieve the number of unique documents" do
15
+ %w(AAA BBB AAA AAA).each do |doc|
16
+ create(:census_datum, id_document: doc, organization:)
17
+ end
18
+ status = Decidim::FileAuthorizationHandler::Status.new(organization)
19
+ expect(status.count).to be 2
20
+ end
21
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Decidim::FileAuthorizationHandler::Admin::Permissions do
6
+ subject { described_class.new(user, permission_action, context).permissions.allowed? }
7
+
8
+ let(:dummy_component) { create :dummy_component }
9
+ let(:organization) { dummy_component.organization }
10
+ let(:user) { create :user, organization: }
11
+ let(:context) do
12
+ {
13
+ current_component: dummy_component,
14
+ }
15
+ end
16
+ let(:scope) { :admin }
17
+ let(:auth_subject) { Decidim::FileAuthorizationHandler::CensusDatum }
18
+ let(:action) do
19
+ { scope:, action: action_name, subject: auth_subject }
20
+ end
21
+ let(:permission_action) { Decidim::PermissionAction.new(**action) }
22
+
23
+ before do
24
+ organization.update!(available_authorizations: ["file_authorization_handler"])
25
+ end
26
+
27
+ context "when action is allowed" do
28
+ [:show, :create, :destroy].each do |action_name|
29
+ let(:action_name) { action_name }
30
+
31
+ context "##{action_name}" do
32
+ it { is_expected.to be true }
33
+ end
34
+ end
35
+ end
36
+
37
+ context "when action is NOT allowed" do
38
+ [:manage, :list, :update].each do |action_name|
39
+ let(:action_name) { action_name }
40
+
41
+ it_behaves_like "permission is not set"
42
+ end
43
+ end
44
+
45
+ context "when scope is not admin" do
46
+ let(:scope) { :public }
47
+ let(:action_name) { :show }
48
+
49
+ it_behaves_like "permission is not set"
50
+ end
51
+
52
+ context "when subject is not :authorize" do
53
+ let(:action_name) { :admin }
54
+ let(:auth_subject) { :foo }
55
+
56
+ it_behaves_like "permission is not set"
57
+ end
58
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ RSpec.describe FileAuthorizationHandler do
5
+ let(:organization) { create(:organization) }
6
+ let(:user) { create(:user, organization:) }
7
+ let(:dni) { "1234A" }
8
+ let(:encoded_dni) { encode_id_document(dni) }
9
+ let(:date) { Date.strptime("1990/11/21", "%Y/%m/%d") }
10
+ let(:handler) do
11
+ described_class.new(user:, id_document: dni, birthdate: date)
12
+ .with_context(current_organization: organization)
13
+ end
14
+ let!(:unique_id) do
15
+ Digest::SHA256.hexdigest("#{handler.census_for_user&.id_document}-#{organization.id}-#{Rails.application.secrets.secret_key_base}")
16
+ end
17
+
18
+ context "without extras in CensusDatum" do
19
+ let(:census_datum) do
20
+ create(:census_datum, id_document: encoded_dni,
21
+ birthdate: date,
22
+ organization:)
23
+ end
24
+
25
+ it "validates against database" do
26
+ expect(handler.valid?).to be false
27
+ census_datum
28
+ expect(handler.valid?).to be true
29
+ end
30
+
31
+ it "normalizes the id document" do
32
+ census_datum
33
+ normalizer =
34
+ described_class.new(user:, id_document: "12-34-a", birthdate: date)
35
+ .with_context(current_organization: organization)
36
+ expect(normalizer.valid?).to be true
37
+ end
38
+
39
+ it "generates birthdate metadata" do
40
+ census_datum
41
+ expect(handler.valid?).to be true
42
+ expect(handler.metadata).to eq(birthdate: "1990/11/21")
43
+ end
44
+
45
+ it "generates unique_id correctly" do
46
+ expect(unique_id).to eq(handler.unique_id)
47
+ end
48
+
49
+ it "works when no current_organization context is provided (but the user is)" do
50
+ census_datum
51
+ contextless_handler = described_class.new(user:,
52
+ id_document: dni,
53
+ birthdate: date)
54
+ expect(contextless_handler.valid?).to be true
55
+ end
56
+ end
57
+
58
+ context "with extras in CensusDatum" do
59
+ let(:date) { Date.strptime("2000/01/01", "%Y/%m/%d") }
60
+ let(:census_datum) do
61
+ create(:census_datum, :with_extras, id_document: encoded_dni,
62
+ birthdate: date,
63
+ organization:)
64
+ end
65
+
66
+ it "adds extras as metadata" do
67
+ census_datum
68
+ expect(handler.valid?).to be true
69
+ expect(handler.metadata).to eq({
70
+ birthdate: "2000/01/01",
71
+ district: census_datum.extras["district"],
72
+ postal_code: census_datum.extras["postal_code"],
73
+ segment_1: census_datum.extras["segment_1"],
74
+ })
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ ENV["RAILS_ENV"] ||= "test"
4
+
5
+ require "decidim/dev"
6
+ require "decidim/admin"
7
+ require "decidim/core"
8
+ require "decidim/verifications"
9
+ require "decidim/core/test"
10
+ require "social-share-button"
11
+ require "letter_opener_web"
12
+
13
+ require "helpers/decidim/file_authorization_handler/encoding_helper"
14
+
15
+ ENV["ENGINE_NAME"] = File.dirname(__dir__).split("/").last
16
+
17
+ Decidim::Dev.dummy_app_path = File.expand_path(File.join(".", "spec", "decidim_dummy_app"))
18
+
19
+ require "decidim/dev/test/base_spec_helper"
20
+
21
+ RSpec.configure do |config|
22
+ config.include Decidim::FileAuthorizationHandler::EncodingHelper
23
+ end