onfido 0.0.1

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 (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +161 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +14 -0
  6. data/LICENSE +22 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +154 -0
  9. data/Rakefile +2 -0
  10. data/lib/onfido.rb +23 -0
  11. data/lib/onfido/address.rb +10 -0
  12. data/lib/onfido/api.rb +18 -0
  13. data/lib/onfido/applicant.rb +18 -0
  14. data/lib/onfido/check.rb +21 -0
  15. data/lib/onfido/configuration.rb +35 -0
  16. data/lib/onfido/document.rb +13 -0
  17. data/lib/onfido/null_logger.rb +6 -0
  18. data/lib/onfido/report.rb +11 -0
  19. data/lib/onfido/request_error.rb +23 -0
  20. data/lib/onfido/requestable.rb +12 -0
  21. data/lib/onfido/resource.rb +48 -0
  22. data/lib/onfido/response_handler.rb +38 -0
  23. data/lib/onfido/version.rb +3 -0
  24. data/onfido.gemspec +25 -0
  25. data/spec/integrations/4xx_response_spec.rb +35 -0
  26. data/spec/integrations/address_spec.rb +10 -0
  27. data/spec/integrations/applicant_spec.rb +73 -0
  28. data/spec/integrations/check_spec.rb +36 -0
  29. data/spec/integrations/document_spec.rb +27 -0
  30. data/spec/integrations/report_spec.rb +20 -0
  31. data/spec/onfido/request_error_spec.rb +39 -0
  32. data/spec/onfido/resource_spec.rb +63 -0
  33. data/spec/onfido/response_handler_spec.rb +79 -0
  34. data/spec/onfido_spec.rb +55 -0
  35. data/spec/spec_helper.rb +45 -0
  36. data/spec/support/fake_onfido_api.rb +55 -0
  37. data/spec/support/fixtures/4xx_response.json +14 -0
  38. data/spec/support/fixtures/addresses.json +24 -0
  39. data/spec/support/fixtures/applicant.json +44 -0
  40. data/spec/support/fixtures/applicants.json +12 -0
  41. data/spec/support/fixtures/check.json +30 -0
  42. data/spec/support/fixtures/checks.json +34 -0
  43. data/spec/support/fixtures/document.json +10 -0
  44. data/spec/support/fixtures/report.json +10 -0
  45. data/spec/support/fixtures/reports.json +24 -0
  46. metadata +151 -0
@@ -0,0 +1,18 @@
1
+ module Onfido
2
+ class Applicant < Resource
3
+ def create(payload)
4
+ post(
5
+ url: url_for('applicants'),
6
+ payload: payload
7
+ )
8
+ end
9
+
10
+ def find(applicant_id)
11
+ get(url: url_for("applicants/#{applicant_id}"), payload: {})
12
+ end
13
+
14
+ def all
15
+ get(url: url_for("applicants"), payload: {})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ module Onfido
2
+ class Check < Resource
3
+ def create(applicant_id, payload)
4
+ post(
5
+ url: url_for("applicants/#{applicant_id}/checks"),
6
+ payload: payload
7
+ )
8
+ end
9
+
10
+ def find(applicant_id, check_id)
11
+ get(
12
+ url: url_for("applicants/#{applicant_id}/checks/#{check_id}"),
13
+ payload: {}
14
+ )
15
+ end
16
+
17
+ def all(applicant_id)
18
+ get(url: url_for("applicants/#{applicant_id}/checks"), payload: {})
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ module Onfido
2
+ module Configuration
3
+ attr_accessor :api_key, :throws_exceptions
4
+
5
+ def self.extended(base)
6
+ base.reset
7
+ end
8
+
9
+ def configure
10
+ yield self
11
+ end
12
+
13
+ def reset
14
+ self.api_key = nil
15
+ self.throws_exceptions = true
16
+ RestClient.log = nil
17
+ end
18
+
19
+ def logger=(log)
20
+ if log.respond_to?(:<<)
21
+ RestClient.log = log
22
+ else
23
+ raise "#{log.class} doesn't seem to behave like a logger!"
24
+ end
25
+ end
26
+
27
+ def logger
28
+ RestClient.log ||= NullLogger.new
29
+ end
30
+
31
+ def endpoint
32
+ 'https://api.onfido.com/v1/'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,13 @@
1
+ module Onfido
2
+ class Document < Resource
3
+ # with open-uri the file can be a link or an actual file
4
+
5
+ def create(applicant_id, payload)
6
+ payload[:file] = open(payload.fetch(:file), 'r')
7
+ post(
8
+ url: url_for("applicants/#{applicant_id}/documents"),
9
+ payload: payload
10
+ )
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module Onfido
2
+ class NullLogger
3
+ def <<
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ module Onfido
2
+ class Report < Resource
3
+ def find(check_id, report_id)
4
+ get(url: url_for("checks/#{check_id}/reports/#{report_id}"), payload: {})
5
+ end
6
+
7
+ def all(check_id)
8
+ get(url: url_for("checks/#{check_id}/reports"), payload: {})
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ =begin
2
+ The class will handle response failures coming from Onfido
3
+ It's main purpose is to produce meaningful error messages to the user e.g.
4
+
5
+ RequestError: Authorization error: please re-check your credentials
6
+
7
+ Users can also rescue the error and insect its type and affected fields as
8
+ specified in the Onfido documentation e.g.
9
+
10
+ begin
11
+ # error being raised
12
+ rescue Onfido::RequestError => e
13
+ e.type
14
+ e.fields
15
+ end
16
+
17
+ =end
18
+
19
+ module Onfido
20
+ class RequestError < StandardError
21
+ attr_accessor :type, :fields, :response_code
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ module Onfido
2
+ module Requestable
3
+ def make_request(options)
4
+ url = options.fetch(:url)
5
+ payload = options.fetch(:payload)
6
+ method = options.fetch(:method)
7
+ RestClient::Request.execute(url: url, payload: payload, method: method, headers: headers) do |response, *|
8
+ ResponseHandler.new(response).parse!
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,48 @@
1
+ module Onfido
2
+ class Resource
3
+ VALID_HTTP_METHODS = %i(get post)
4
+
5
+ include Requestable
6
+
7
+ def url_for(path)
8
+ Onfido.endpoint + path
9
+ end
10
+
11
+ def method_missing(method, *args)
12
+ if VALID_HTTP_METHODS.include?(method.to_sym)
13
+ make_request(
14
+ url: args.first.fetch(:url),
15
+ payload: build_query(args.first.fetch(:payload)),
16
+ method: method.to_sym
17
+ )
18
+ else
19
+ super
20
+ end
21
+ end
22
+
23
+ def respond_to_missing?(method, include_private = false)
24
+ VALID_HTTP_METHODS.include?(method.to_sym) || super
25
+ end
26
+
27
+ def headers
28
+ {
29
+ 'Authorization' => "Token token=#{Onfido.api_key}",
30
+ 'Accept' => "application/json"
31
+ }
32
+ end
33
+
34
+ private
35
+
36
+ # There seems to be a serialization issue with the HTTP client
37
+ # which does not serialize the payload properly.
38
+ # Have a look here https://gist.github.com/PericlesTheo/cb35139c57107ab3c84a
39
+
40
+ def build_query(payload)
41
+ if payload[:file]
42
+ payload
43
+ else
44
+ Rack::Utils.build_nested_query(payload)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,38 @@
1
+ module Onfido
2
+ class ResponseHandler
3
+ attr_reader :response
4
+
5
+ def initialize(response)
6
+ @response = response
7
+ end
8
+
9
+ def parse!
10
+ if Onfido.throws_exceptions && parsed_response["error"]
11
+ raise request_error
12
+ else
13
+ parsed_response
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def parsed_response
20
+ @parsed_response ||=
21
+ begin
22
+ JSON.parse(response)
23
+ rescue JSON::ParserError
24
+ {
25
+ 'error' => {"message" => "Unparseable response: #{response}"}
26
+ }
27
+ end
28
+ end
29
+
30
+ def request_error
31
+ RequestError.new(parsed_response['error']['message']).tap do |error|
32
+ error.type = parsed_response['error']["type"]
33
+ error.fields = parsed_response['error']["fields"]
34
+ error.response_code = response.code if response.respond_to?(:code)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ module Onfido
2
+ VERSION = '0.0.1'
3
+ end
data/onfido.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'onfido/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'onfido'
8
+ spec.version = Onfido::VERSION
9
+ spec.authors = ['Pericles Theodorou']
10
+ spec.email = ['periclestheo@gmail.com']
11
+ spec.summary = %q{A wrapper for Onfido API 1.0}
12
+ spec.description = %q{A wrapper for Onfido API 1.0}
13
+ spec.homepage = 'http://github.com/hvssle/onfido'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.7'
22
+ spec.add_development_dependency 'rake', '~> 10.0'
23
+
24
+ spec.add_dependency 'rest-client', '~> 1.8.0'
25
+ end
@@ -0,0 +1,35 @@
1
+ describe Onfido::Resource do
2
+ let(:resource) { described_class.new }
3
+ let(:url) { Onfido.endpoint + path }
4
+ let(:api_key) { 'some_key' }
5
+ let(:payload) { {postcode: 'SE1 4NG'} }
6
+
7
+
8
+ before do
9
+ allow(Onfido).to receive(:api_key).and_return(api_key)
10
+ end
11
+
12
+ context 'when a response is a 4xx' do
13
+ let(:path) { '4xx_response' }
14
+
15
+ context "when 'throws_exceptions' is true" do
16
+ it 'raises a custom error' do
17
+ expect {
18
+ resource.get({url: url, payload: payload})
19
+ }.to raise_error(
20
+ Onfido::RequestError, 'Something went wrong')
21
+ end
22
+ end
23
+
24
+ context "when 'throws_exceptions' is false" do
25
+ before do
26
+ allow(Onfido).to receive(:throws_exceptions).and_return(false)
27
+ end
28
+
29
+ it 'returns the body as a hash' do
30
+ response = resource.get({url: url, payload: payload})
31
+ expect(response['error']).not_to be_nil
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,10 @@
1
+ describe Onfido::Address do
2
+ subject(:api) { Onfido::API.new }
3
+
4
+ describe '#all' do
5
+ it 'returns the addresses matching the postcode' do
6
+ response = api.address.all('SW1 4NG')
7
+ expect(response['addresses'].count).to eq(2)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,73 @@
1
+ describe Onfido::Applicant do
2
+ subject(:applicant) { described_class.new }
3
+ let(:params) do
4
+ {
5
+ 'title' => 'Mr',
6
+ 'first_name' => 'Chandler',
7
+ 'last_name' => 'Bing',
8
+ 'gender' => 'male',
9
+ 'middle_name' => 'Muriel',
10
+ 'dob' => '1968-04-08',
11
+ 'telephone' => '555555555',
12
+ 'mobile' => '77777777',
13
+ 'email' => 'chandler_bing_6@friends.com',
14
+ 'addresses' => [
15
+ {
16
+ 'flat_number' => '4',
17
+ 'building_number' => '100',
18
+ 'building_name' => 'Awesome Building',
19
+ 'street' => 'Main Street',
20
+ 'sub_street' => 'A sub street',
21
+ 'town' => 'London',
22
+ 'postcode' => 'SW4 6EH',
23
+ 'country' => 'GBR'
24
+ },
25
+ {
26
+ 'flat_number' => '1',
27
+ 'building_number' => '10',
28
+ 'building_name' => 'Great Building',
29
+ 'street' => 'Old Street',
30
+ 'sub_street' => 'Sub Street',
31
+ 'town' => 'London',
32
+ 'postcode' => 'SW1 4NG',
33
+ 'country' => 'GBR'
34
+ }
35
+ ]
36
+ }
37
+ end
38
+
39
+ describe '#create' do
40
+ # Need to find a better way of testing that the request is not malformed.
41
+ # Currently this runs for every feature spec. The fact that it's under here
42
+ # is only for semantic reasons
43
+
44
+ it 'serializes the payload correctly' do
45
+ WebMock.after_request do |request_signature, response|
46
+ if request_signature.uri.path == 'v1/applicants'
47
+ expect(Rack::Utils.parse_nested_query(request_signature.body)).to eq(params)
48
+ end
49
+ end
50
+ end
51
+
52
+ it 'creates an applicant' do
53
+ response = applicant.create(params)
54
+ expect(response['id']).not_to be_nil
55
+ end
56
+ end
57
+
58
+ describe '#find' do
59
+ let(:applicant_id) { '61f659cb-c90b-4067-808a-6136b5c01351' }
60
+
61
+ it 'returns the applicant' do
62
+ response = applicant.find(applicant_id)
63
+ expect(response['id']).to eq(applicant_id)
64
+ end
65
+ end
66
+
67
+ describe '#all' do
68
+ it 'returns all the applicants' do
69
+ response = applicant.all
70
+ expect(response['applicants'].size).to eq(2)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,36 @@
1
+ describe Onfido::Check do
2
+ subject(:check) { described_class.new }
3
+ let(:applicant_id) { '61f659cb-c90b-4067-808a-6136b5c01351' }
4
+
5
+ describe '#create' do
6
+ let(:params) do
7
+ {
8
+ type: 'express',
9
+ reports: [{name: 'identity'}]
10
+ }
11
+ end
12
+
13
+ it 'creates a new check for an applicant' do
14
+ response = check.create(applicant_id, params)
15
+ expect(response['id']).not_to be_nil
16
+ end
17
+ end
18
+
19
+ describe '#find' do
20
+ let(:check_id) { '8546921-123123-123123' }
21
+
22
+ it 'returns an existing check for the applicant' do
23
+ response = check.find(applicant_id, check_id)
24
+ expect(response['id']).to eq(check_id)
25
+ end
26
+ end
27
+
28
+ describe '#all' do
29
+ let(:check_id) { '8546921-123123-123123' }
30
+
31
+ it 'returns all existing checks for the applicant' do
32
+ response = check.all(applicant_id)
33
+ expect(response['checks'].size).to eq(1)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,27 @@
1
+ require 'tempfile'
2
+
3
+ describe Onfido::Document do
4
+ subject(:document) { described_class.new }
5
+
6
+ describe '#create' do
7
+ after do
8
+ file.close
9
+ file.unlink
10
+ end
11
+
12
+ let(:file) { Tempfile.new(['passport', '.jpg']) }
13
+ let(:params) do
14
+ {
15
+ type: 'passport',
16
+ side: 'back',
17
+ file: file
18
+ }
19
+ let(:applicant_id) { '1030303-123123-123123' }
20
+
21
+ it 'creates a new document' do
22
+ response = document.create('foobar', params)
23
+ expect(response['id']).not_to be_nil
24
+ end
25
+ end
26
+ end
27
+ end