checkr-canada 0.1.0

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