checkr-canada 0.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.
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Checkr
4
+ module Canada
5
+ module Entities
6
+ class CriminalRecordForm < Evil::Struct
7
+ attribute :offence, Types::Strict::String
8
+ attribute :location, Types::Strict::String
9
+ attribute :sentence_date, Types::Date
10
+ end
11
+
12
+ class CriminalRecord < CriminalRecordForm
13
+ attribute :id, Types::Strict::String
14
+ attribute :object, Types::String, optional: true
15
+ attribute :uri, Types::Strict::String
16
+ attribute :created_at, Types::Json::DateTime
17
+ attribute :updated_at, Types::Json::DateTime, optional: true
18
+ end
19
+ end
20
+
21
+ class Client
22
+ operation :create_criminal_record do |_settings|
23
+ http_method :post
24
+
25
+ path do |candidate_id:, **|
26
+ "candidates/#{candidate_id}/criminal_records"
27
+ end
28
+
29
+ body format: "json", model: Entities::CriminalRecordForm
30
+
31
+ response :success, 201, format: :json, model: Entities::CriminalRecord
32
+
33
+ response :not_authorized, 401, format: :json, raise: true do
34
+ attribute :error
35
+ end
36
+
37
+ response :invalid, 400, format: :json, raise: true do
38
+ attribute :error
39
+ end
40
+ end
41
+
42
+ scope :criminal_records do
43
+ def create(data)
44
+ operations[:create_criminal_record].call(data)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Checkr
4
+ module Canada
5
+ module Entities
6
+ class Document < Evil::Struct
7
+ attribute :id, Types::Strict::String
8
+ attribute :object, Types::String, optional: true
9
+ attribute :filename, Types::String, optional: true
10
+ attribute :uri, Types::Strict::String
11
+ attribute :download_uri, Types::Strict::String
12
+ attribute :created_at, Types::Json::DateTime
13
+ attribute :content_type, Types::String, optional: true
14
+ attribute :filesize, Types::Int, optional: true
15
+ end
16
+ end
17
+
18
+ class Client
19
+ operation :upload_document do |_settings|
20
+ http_method :post
21
+
22
+ path { |candidate_id:, **| "candidates/#{candidate_id}/documents" }
23
+
24
+ body format: "json" do
25
+ attribute :type, Types::DocumentType
26
+ attribute :url, Types::Strict::String
27
+ attribute :filename, Types::Strict::String, optional: true
28
+ end
29
+
30
+ response :success, 201, format: :json, model: Entities::Document
31
+
32
+ response :not_authorized, 401, format: :json, raise: true do
33
+ attribute :error
34
+ end
35
+
36
+ response :invalid, 400, format: :json, raise: true do
37
+ attribute :error
38
+ end
39
+ end
40
+
41
+ scope :documents do
42
+ def upload(data)
43
+ operations[:upload_document].call(data)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Checkr
4
+ module Canada
5
+ module Entities
6
+ class Report < Evil::Struct
7
+ attribute :id, Types::Strict::String
8
+ attribute :object, Types::Strict::String
9
+ attribute :uri, Types::Strict::String
10
+ attribute :package, Types::Package
11
+ attribute :status, Types::Status
12
+ attribute :adjudication, Types::String, optional: true
13
+ attribute :created_at, Types::Json::DateTime
14
+ attribute :completed_at, Types::Json::DateTime
15
+ attribute :turnaround_time, Types::Int, optional: true
16
+ attribute :account_id, Types::Strict::String, optional: true
17
+ attribute :candidate_id, Types::Strict::String, optional: true
18
+ attribute :motor_vehicle_report_id, Types::String, optional: true
19
+ attribute :national_criminal_search_id, Types::String, optional: true
20
+ attribute :criminal_record_ids, Types::Array.member(Types::Strict::String), optional: true
21
+ attribute :document_ids, Types::Array.member(Types::Strict::String), optional: true
22
+ end
23
+ end
24
+
25
+ class Client
26
+ operation :list_reports do |_settings|
27
+ http_method :get
28
+ path { "reports" }
29
+
30
+ query do
31
+ attributes optional: true do
32
+ attribute :page
33
+ attribute :per_page
34
+ end
35
+ end
36
+
37
+ response :success, 200, format: :json do
38
+ attribute :object, Types::Strict::String
39
+ attribute :next_href, Types::String, optional: true
40
+ attribute :previous_href, Types::String, optional: true
41
+ attribute :count, Types::Strict::Int
42
+ attribute :data, Types::Coercible::Array.member(Entities::Report)
43
+ end
44
+
45
+ response :not_authorized, 401, format: :json, raise: true do
46
+ attribute :error
47
+ end
48
+
49
+ response :not_found, 404, format: :json, raise: true do
50
+ attribute :error
51
+ end
52
+ end
53
+
54
+ operation :get_report do |_settings|
55
+ http_method :get
56
+ path { |id:, **| "reports/#{id}" }
57
+
58
+ response :success, 200, format: :json, model: Entities::Report
59
+
60
+ response :not_authorized, 401, format: :json, raise: true do
61
+ attribute :error
62
+ end
63
+
64
+ response :not_found, 404, format: :json, raise: true do
65
+ attribute :message, as: :error
66
+ end
67
+ end
68
+
69
+ operation :create_report do |_settings|
70
+ http_method :post
71
+
72
+ path { |candidate_id:, **| "candidates/#{candidate_id}/reports" }
73
+
74
+ body format: "json" do
75
+ attribute :package, Types::Package
76
+ end
77
+
78
+ response :success, 201, format: :json, model: Entities::Report
79
+
80
+ response :not_authorized, 401, format: :json, raise: true do
81
+ attribute :error
82
+ end
83
+
84
+ response :invalid, 400, format: :json, raise: true do
85
+ attribute :error
86
+ end
87
+ end
88
+
89
+ scope :reports do
90
+ def all(**data)
91
+ operations[:list_reports].call(**data)
92
+ end
93
+
94
+ def get(id, data = {})
95
+ operations[:get_report].call(data.merge(id: id))
96
+ end
97
+
98
+ def create(data)
99
+ operations[:create_report].call(data)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Fix setting body to '{}' when it is blank
4
+ module StringifyJsonPatch
5
+ def build(env)
6
+ return env unless env[:format] == "json"
7
+ new_env = super
8
+ new_env.delete(:body_string) if env[:body].nil? || env[:body].empty?
9
+ new_env
10
+ end
11
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry-types"
4
+
5
+ module Checkr
6
+ module Canada
7
+ PROVINCE_CODES = %w[
8
+ AB
9
+ BC
10
+ MB
11
+ NB
12
+ NL
13
+ NT
14
+ NS
15
+ NU
16
+ ON
17
+ PE
18
+ QC
19
+ SK
20
+ YT
21
+ ].freeze
22
+
23
+ # Dry types + custom types
24
+ module Types
25
+ include Dry::Types.module
26
+
27
+ Status = Strict::String.enum(
28
+ 'pending', 'clear', 'consider', 'suspended'
29
+ )
30
+
31
+ Package = Strict::String.enum(
32
+ 'mvr', 'criminal', 'criminal_mvr'
33
+ )
34
+
35
+ DocumentType = Strict::String.enum(
36
+ 'identification', 'consent'
37
+ )
38
+
39
+ Province = Strict::String.enum(*PROVINCE_CODES)
40
+
41
+ Gender = Strict::String.enum('M', 'F')
42
+ Email = Strict::String
43
+
44
+ Date = Strict::String
45
+ .constrained(format: /\A\d{4}-\d{2}-\d{2}\z/)
46
+ .constructor do |value|
47
+ begin
48
+ date = value.to_date if value.respond_to? :to_date
49
+ date ||= ::Date.parse(value.to_s)
50
+ date.strftime "%Y-%m-%d"
51
+ rescue
52
+ raise Dry::Types::ConstraintError.new(
53
+ "#{value.inspect} cannot be coerced to date",
54
+ value
55
+ )
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Checkr
4
+ module Canada
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe "Addresses" do
6
+ let(:client) { Checkr::Canada::Client.new("test_api_key") }
7
+
8
+ describe "#create" do
9
+ let(:answer) do
10
+ File.read("./spec/fixtures/address.json")
11
+ end
12
+
13
+ let(:params) do
14
+ {
15
+ candidate_id: 'abc123xyz',
16
+ street1: "Mission st",
17
+ street2: "4-2",
18
+ region: "BC",
19
+ city: "San Francisco",
20
+ postal_code: "BC341",
21
+ start_date: "2017-01-02"
22
+ }
23
+ end
24
+
25
+ subject(:doc) { client.addresses.create(**params) }
26
+
27
+ before do
28
+ stub_request(:post, /candidates\/abc123xyz\/addresses/)
29
+ .to_return(
30
+ body: answer,
31
+ status: 201
32
+ )
33
+ end
34
+
35
+ it "makes request" do
36
+ subject
37
+
38
+ expect(
39
+ a_request(:post, "https://api.checkr.com/ca/v1/candidates/abc123xyz/addresses")
40
+ ).to have_been_made
41
+ end
42
+
43
+ it "returns an address", :aggregate_failures do
44
+ expect(doc.country).to eq "CA"
45
+ expect(doc.created_at).to be_a(DateTime)
46
+ end
47
+
48
+ it "raises when missing params" do
49
+ params.delete(:region)
50
+
51
+ expect { subject }.to raise_error(ArgumentError)
52
+ end
53
+
54
+ it "raises when unknown region" do
55
+ params[:region] = "Arizona"
56
+
57
+ expect { subject }.to raise_error(TypeError)
58
+ end
59
+
60
+ it "raises when missing candidate_id" do
61
+ params.delete(:candidate_id)
62
+
63
+ expect { subject }.to raise_error(ArgumentError)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe "Authentication" do
6
+ let(:client) { Checkr::Canada::Client.new("test_api_key") }
7
+ subject { client.reports.all }
8
+
9
+ context "successful" do
10
+ before do
11
+ stub_request(:get, "https://api.checkr.com/ca/v1/reports").to_return(
12
+ body: { data: [], object: "list", count: 0 }.to_json
13
+ )
14
+ end
15
+
16
+ it "build basic auth from api_key" do
17
+ subject
18
+
19
+ expect(
20
+ a_request(:get, "https://api.checkr.com/ca/v1/reports")
21
+ .with(basic_auth: ["test_api_key", ""])
22
+ ).to have_been_made
23
+ end
24
+ end
25
+
26
+ context "failed" do
27
+ before do
28
+ stub_request(:get, "https://api.checkr.com/ca/v1/reports").to_return(
29
+ body: { error: 'Not authorized' }.to_json, status: 401
30
+ )
31
+ end
32
+
33
+ it "raises error" do
34
+ expect { subject }.to raise_error(Evil::Client::Operation::ResponseError)
35
+
36
+ expect(
37
+ a_request(:get, "https://api.checkr.com/ca/v1/reports")
38
+ .with(basic_auth: ["test_api_key", ""])
39
+ ).to have_been_made
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe "Candidates" do
6
+ let(:client) { Checkr::Canada::Client.new("test_api_key") }
7
+
8
+ describe "#all" do
9
+ let(:answer) { { data: [], object: "list", count: 0 }.to_json }
10
+ let(:options) { {} }
11
+
12
+ subject { client.candidates.all(**options) }
13
+
14
+ before do
15
+ stub_request(:get, /candidates/)
16
+ .to_return(
17
+ body: answer
18
+ )
19
+ end
20
+
21
+ it "builds response", :aggregate_failures do
22
+ expect(subject.count).to eq 0
23
+ expect(subject.object).to eq 'list'
24
+ expect(subject.next_href).to be_nil
25
+ expect(subject.previous_href).to be_nil
26
+ expect(subject.data.size).to eq 0
27
+ end
28
+
29
+ context "with params" do
30
+ let(:options) { { per_page: 1, page: 2, foo: "bar" } }
31
+
32
+ it "recognizes only valid params" do
33
+ subject
34
+
35
+ expect(
36
+ a_request(:get, "https://api.checkr.com/ca/v1/candidates")
37
+ .with(query: { per_page: 1, page: 2 })
38
+ ).to have_been_made
39
+ end
40
+ end
41
+
42
+ context "with data" do
43
+ let(:answer) do
44
+ File.read("./spec/fixtures/candidates.json")
45
+ end
46
+
47
+ it "builds candidate", :aggregate_failures do
48
+ expect(subject.data.size).to eq 1
49
+
50
+ candidate = subject.data.first
51
+
52
+ expect(candidate.dob).to eq "1975-03-19"
53
+ expect(candidate.created_at).to be_a(DateTime)
54
+ expect(candidate.created_at.to_date).to eq Date.new(2017, 3, 23)
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#get" do
60
+ let(:answer) do
61
+ File.read("./spec/fixtures/candidate.json")
62
+ end
63
+
64
+ subject(:candidate) { client.candidates.get('123abc') }
65
+
66
+ before do
67
+ stub_request(:get, /candidates\/123/)
68
+ .to_return(
69
+ body: answer
70
+ )
71
+ end
72
+
73
+ it "makes request" do
74
+ subject
75
+
76
+ expect(
77
+ a_request(:get, "https://api.checkr.com/ca/v1/candidates/123abc")
78
+ ).to have_been_made
79
+ end
80
+
81
+ it "builds candidate", :aggregate_failures do
82
+ expect(candidate.dob).to eq "1975-03-19"
83
+ expect(candidate.created_at).to be_a(DateTime)
84
+ expect(candidate.created_at.to_date).to eq Date.new(2017, 3, 23)
85
+ end
86
+
87
+ context "not found" do
88
+ before do
89
+ stub_request(:get, /candidates\/123/)
90
+ .to_return(
91
+ body: { message: 'Not found' }.to_json,
92
+ status: 404
93
+ )
94
+ end
95
+
96
+ it "raises error" do
97
+ expect { subject }.to raise_error(Evil::Client::Operation::ResponseError)
98
+ end
99
+ end
100
+ end
101
+
102
+ describe "#create" do
103
+ let(:answer) do
104
+ File.read("./spec/fixtures/candidate.json")
105
+ end
106
+
107
+ let(:params) do
108
+ {
109
+ first_name: "Test",
110
+ last_name: "Candidate",
111
+ email: "testonboard@test.com",
112
+ phone: "000-000-0002",
113
+ birth_place: "Toronto",
114
+ dob: Date.new(2017, 3, 23),
115
+ gender: "F"
116
+ }
117
+ end
118
+
119
+ subject(:candidate) { client.candidates.create(params) }
120
+
121
+ before do
122
+ stub_request(:post, /candidates/)
123
+ .to_return(
124
+ body: answer,
125
+ status: 201
126
+ )
127
+ end
128
+
129
+ it "makes request" do
130
+ subject
131
+
132
+ expect(
133
+ a_request(:post, "https://api.checkr.com/ca/v1/candidates")
134
+ ).to have_been_made
135
+ end
136
+
137
+ it "returns a candidate", :aggregate_failures do
138
+ expect(candidate.first_name).to eq "Test"
139
+ expect(candidate.last_name).to eq "Candidate"
140
+ end
141
+
142
+ it "raises when missing params" do
143
+ params.delete(:first_name)
144
+
145
+ expect { subject }.to raise_error(ArgumentError)
146
+ end
147
+ end
148
+ end