fullcontacter 0.3.2

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 (74) hide show
  1. data/.document +5 -0
  2. data/.gitignore +53 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE.md +20 -0
  6. data/README.md +36 -0
  7. data/Rakefile +25 -0
  8. data/VERSION +1 -0
  9. data/bugs.txt +2 -0
  10. data/fullcontact.gemspec +34 -0
  11. data/lib/faraday/request/gateway.rb +18 -0
  12. data/lib/faraday/response/fullcontact_errors.rb +33 -0
  13. data/lib/faraday/response/raise_http_4xx.rb +45 -0
  14. data/lib/faraday/response/raise_http_5xx.rb +24 -0
  15. data/lib/fullcontact.rb +27 -0
  16. data/lib/fullcontact/api.rb +21 -0
  17. data/lib/fullcontact/client.rb +32 -0
  18. data/lib/fullcontact/client/batch_process.rb +35 -0
  19. data/lib/fullcontact/client/contact.rb +119 -0
  20. data/lib/fullcontact/client/contact_list.rb +84 -0
  21. data/lib/fullcontact/client/icon.rb +35 -0
  22. data/lib/fullcontact/client/name.rb +167 -0
  23. data/lib/fullcontact/client/person.rb +94 -0
  24. data/lib/fullcontact/client/provisioning.rb +28 -0
  25. data/lib/fullcontact/client/snapshot.rb +31 -0
  26. data/lib/fullcontact/client/subscription.rb +45 -0
  27. data/lib/fullcontact/client/user.rb +28 -0
  28. data/lib/fullcontact/configuration.rb +95 -0
  29. data/lib/fullcontact/connection.rb +36 -0
  30. data/lib/fullcontact/error.rb +35 -0
  31. data/lib/fullcontact/request.rb +43 -0
  32. data/lib/fullcontact/version.rb +3 -0
  33. data/spec/faraday/response_spec.rb +56 -0
  34. data/spec/fixtures/clear_contact_list.json +3 -0
  35. data/spec/fixtures/contact_history.json +16 -0
  36. data/spec/fixtures/create_contact_list.json +4 -0
  37. data/spec/fixtures/create_snapshot.json +7 -0
  38. data/spec/fixtures/create_subscription.json +4 -0
  39. data/spec/fixtures/deduce_by_email.json +13 -0
  40. data/spec/fixtures/deduce_by_username.json +13 -0
  41. data/spec/fixtures/delete_contact.json +4 -0
  42. data/spec/fixtures/delete_contact_list.json +3 -0
  43. data/spec/fixtures/delete_subscription.json +3 -0
  44. data/spec/fixtures/get_contact.json +20 -0
  45. data/spec/fixtures/get_contact_lists.json +11 -0
  46. data/spec/fixtures/get_contacts_in_a_list.json +41 -0
  47. data/spec/fixtures/get_enriched_contact.json +261 -0
  48. data/spec/fixtures/get_updates.json +252 -0
  49. data/spec/fixtures/has_enriched_updates.json +4 -0
  50. data/spec/fixtures/list_snapshots.json +7 -0
  51. data/spec/fixtures/list_subscriptions.json +10 -0
  52. data/spec/fixtures/normalize.json +27 -0
  53. data/spec/fixtures/parse.json +10 -0
  54. data/spec/fixtures/person.json +47 -0
  55. data/spec/fixtures/queue_contact_list_for_enrichment.json +3 -0
  56. data/spec/fixtures/save_enriched_contact.json +261 -0
  57. data/spec/fixtures/similarity.json +45 -0
  58. data/spec/fixtures/stats_by_family_name.json +12 -0
  59. data/spec/fixtures/stats_by_given_and_family_name.json +62 -0
  60. data/spec/fixtures/stats_by_given_name.json +57 -0
  61. data/spec/fixtures/stats_by_name.json +64 -0
  62. data/spec/fixtures/update_contact.json +9 -0
  63. data/spec/fullcontact/api_spec.rb +68 -0
  64. data/spec/fullcontact/client/contact_list_spec.rb +89 -0
  65. data/spec/fullcontact/client/contact_spec.rb +108 -0
  66. data/spec/fullcontact/client/icon_spec.rb +24 -0
  67. data/spec/fullcontact/client/name_spec.rb +121 -0
  68. data/spec/fullcontact/client/person_spec.rb +77 -0
  69. data/spec/fullcontact/client/snapshot_spec.rb +35 -0
  70. data/spec/fullcontact/client/subscription_spec.rb +47 -0
  71. data/spec/fullcontact/client_spec.rb +10 -0
  72. data/spec/fullcontact_spec.rb +114 -0
  73. data/spec/helper.rb +39 -0
  74. metadata +384 -0
@@ -0,0 +1,28 @@
1
+ module FullContact
2
+ class Client
3
+ module Provisioning
4
+ # Public:The Provisioning method creates a new API key based on an
5
+ # Account Key. This method is useful when your application has many end
6
+ # users that you would like to track separately. An account key is
7
+ # required for accessing this api method. This account key can be
8
+ # initialized through the configure method. For getting an account key,
9
+ # send an email to support@fullcontact.com.
10
+ #
11
+ # Example
12
+ #
13
+ # api_key = FullContact.create_new_api_key
14
+ #
15
+ # Returns a hash which contains the generated api_key and monthly quota
16
+ def create_new_api_key
17
+ # return error if no provisioning key defined
18
+ return unless FullContact.options[:account_key]
19
+ self.endpoint = 'https://api.fullcontact.com/apiKey'
20
+ options = {:accountKey => FullContact.options[:account_key]}
21
+ get('new', options)
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,31 @@
1
+ module FullContact
2
+ class Client
3
+ module Snapshot
4
+ # Public: Creates a snapshot in order to store a point-in-time backup of a contactList
5
+ #
6
+ # list_id - id of the contact list to be backed-up
7
+ # options - hash containing additonal arguments
8
+ # :name - Name of the snapshot
9
+ #
10
+ # Example
11
+ #
12
+ # response = FullContact.create_snapshot(list_id, {:name => 'foo'})
13
+ # response.result now contains the snapshot name and timestamp
14
+ def create_snapshot(list_id, options)
15
+ post("contactList/#{list_id}/snapshot", options)
16
+ end
17
+
18
+ # Public: List all snapshots associated with a contact list
19
+ #
20
+ # list_id - id of the contact list for which snapshots need to be fetched
21
+ #
22
+ # Example
23
+ #
24
+ # response = FullContact.list_snapshots(list_id)
25
+ # response.snapshots gives a list of snapshot names
26
+ def list_snapshots(list_id)
27
+ get("contactList/#{list_id}/snapshot")
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,45 @@
1
+ module FullContact
2
+ class Client
3
+ module Subscription
4
+ # Public: Creates a subscription to a contactList in order to receive webhook notifications for certain events
5
+ #
6
+ # list_id - id of the contact list for which subscription is to be created
7
+ # options - hash containing additional arguments
8
+ # :event Type of event. Only 'enriched' is supported right now
9
+ # :callback Callback URL to post to when event occurs
10
+ #
11
+ # Example
12
+ #
13
+ # response = FullContact.create_subscription(list_id, {:event => 'enriched', :callback => callback_url })
14
+ # response.id contains the subscription id
15
+ def create_subscription(list_id, options)
16
+ post("contactList/#{list_id}/subscribe", options)
17
+ end
18
+
19
+ # Public: Lists all subscriptions associated with a contactList
20
+ #
21
+ # list_id - id of the contact list for which subscription is to be created
22
+ #
23
+ # Example
24
+ #
25
+ # response = FullContact.list_subscriptions(list_id)
26
+ # response.subscriptions contains list of all subscriptions for this contact list
27
+ def list_subscriptions(list_id)
28
+ get("contactList/#{list_id}/subscribe")
29
+ end
30
+
31
+ # Public: Delete a subscription associated with a contactList
32
+ #
33
+ # list_id - id of the contact list for which subscription is to be created
34
+ # options - hash containing additional arguments
35
+ # :subscription id of the subscription to delete
36
+ #
37
+ # Example
38
+ #
39
+ # response = FullContact.delete_subscriptions(list_id, {:subscription => subscription_id})
40
+ def delete_subscription(list_id, options)
41
+ delete("contactList/#{list_id}/subscribe", options)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ module FullContact
2
+ class Client
3
+ module User
4
+ # Public: Authenticate a user using the username and password. If
5
+ # authenticated, sets the returned access_token in a access_token config
6
+ # variable
7
+ #
8
+ # options - a hash containing the user's username and password
9
+ #
10
+ # Example
11
+ #
12
+ # FullContact.authenticate({ :username => 'prafullakiran@gmail.com',
13
+ # :password => 'grizzlybear' })
14
+ # # we're authenticated now
15
+ # contact_lists = FullContact.get_contact_lists
16
+ def authenticate(options = {})
17
+ self.endpoint = 'https://api.fullcontact.com/auth/'
18
+ self.format = ''
19
+ access_token = post('token', options)
20
+
21
+ FullContact.configure do |config|
22
+ config.access_token = access_token
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,95 @@
1
+ require 'faraday'
2
+
3
+ module FullContact
4
+ # Defines constants and methods related to configuration
5
+ module Configuration
6
+ # An array of valid keys in the options hash when configuring a {FullContact::API}
7
+ VALID_OPTIONS_KEYS = [
8
+ :adapter,
9
+ :api_key,
10
+ :account_key,
11
+ :get_request_url_only,
12
+ :endpoint,
13
+ :format,
14
+ :access_token,
15
+ :gateway,
16
+ :proxy,
17
+ :user_agent].freeze
18
+
19
+ # An array of valid request/response formats
20
+ #
21
+ # @note Not all methods support the XML format.
22
+ VALID_FORMATS = [
23
+ :json,
24
+ :xml].freeze
25
+
26
+ # The adapter that will be used to connect if none is set
27
+ #
28
+ # @note The default faraday adapter is Net::HTTP.
29
+ DEFAULT_ADAPTER = Faraday.default_adapter
30
+
31
+ # By default, don't set an api key
32
+ DEFAULT_API_KEY = nil
33
+
34
+ # By default, don't set an access key
35
+ DEFAULT_ACCESS_TOKEN = nil
36
+
37
+ # By default, don't set an account key
38
+ DEFAULT_ACCOUNT_KEY = nil
39
+
40
+ # By default, get full response
41
+ GET_REQUEST_URL_ONLY = false
42
+
43
+ # The endpoint that will be used to connect if none is set
44
+ #
45
+ DEFAULT_ENDPOINT = 'https://api.fullcontact.com/v2/'.freeze
46
+
47
+ # The response format appended to the path and sent in the 'Accept' header if none is set
48
+ #
49
+ # @note JSON is preferred over XML because it is more concise and faster to parse.
50
+ DEFAULT_FORMAT = :json
51
+
52
+ # By default, don't use a proxy server
53
+ DEFAULT_PROXY = nil
54
+
55
+ # The user agent that will be sent to the API endpoint if none is set
56
+ DEFAULT_USER_AGENT = "FullContact Ruby Gem".freeze
57
+
58
+ DEFAULT_GATEWAY = nil
59
+
60
+ # @private
61
+ attr_accessor *VALID_OPTIONS_KEYS
62
+
63
+ # When this module is extended, set all configuration options to their default values
64
+ def self.extended(base)
65
+ base.reset
66
+ end
67
+
68
+ # Convenience method to allow configuration options to be set in a block
69
+ def configure
70
+ yield self
71
+ end
72
+
73
+ # Create a hash of options and their values
74
+ def options
75
+ options = {}
76
+ VALID_OPTIONS_KEYS.each{|k| options[k] = send(k) }
77
+ options
78
+ end
79
+
80
+ # Reset all configuration options to defaults
81
+ def reset
82
+ self.adapter = DEFAULT_ADAPTER
83
+ self.api_key = DEFAULT_API_KEY
84
+ self.access_token = DEFAULT_ACCESS_TOKEN
85
+ self.account_key = DEFAULT_ACCOUNT_KEY
86
+ self.get_request_url_only = GET_REQUEST_URL_ONLY
87
+ self.endpoint = DEFAULT_ENDPOINT
88
+ self.format = DEFAULT_FORMAT
89
+ self.proxy = DEFAULT_PROXY
90
+ self.user_agent = DEFAULT_USER_AGENT
91
+ self.gateway = DEFAULT_GATEWAY
92
+ self
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,36 @@
1
+ require 'faraday_middleware'
2
+ require 'faraday/request/gateway'
3
+ require 'faraday/response/fullcontact_errors'
4
+
5
+
6
+ module FullContact
7
+ # @private
8
+ module Connection
9
+ private
10
+
11
+ def connection(raw=false)
12
+ options = {
13
+ :headers => {'Accept' => "application/#{format}", 'User-Agent' => user_agent},
14
+ :proxy => proxy,
15
+ :ssl => {:verify => false},
16
+ :url => api_endpoint,
17
+ }
18
+
19
+ Faraday.new(options) do |builder|
20
+ builder.use Faraday::Request::UrlEncoded
21
+ builder.use Faraday::Request::Gateway, gateway if gateway
22
+ builder.use Faraday::Response::Rashify unless raw
23
+ unless raw
24
+ case format.to_s.downcase
25
+ when 'json'
26
+ builder.use Faraday::Response::ParseJson
27
+ when 'xml'
28
+ builder.use Faraday::Response::ParseXml
29
+ end
30
+ end
31
+ builder.use Faraday::Response::FullContactErrors
32
+ builder.adapter Faraday.default_adapter
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,35 @@
1
+ module FullContact
2
+ # Custom error class for rescuing from all FullContact errors
3
+ class Error < StandardError
4
+ attr_reader :http_headers
5
+
6
+ def initialize(message, http_headers)
7
+ @http_headers = Hash[http_headers]
8
+ super message
9
+ end
10
+ end
11
+
12
+ # Raised when FullContact returns the HTTP status code 400
13
+ class BadRequest < Error; end
14
+
15
+ # Raised when FullContact returns the HTTP status code 401
16
+ class Unauthorized < Error; end
17
+
18
+ # Raised when FullContact returns the HTTP status code 403
19
+ class Forbidden < Error; end
20
+
21
+ # Raised when FullContact returns the HTTP status code 404
22
+ class NotFound < Error; end
23
+
24
+ # Raised when FullContact returns the HTTP status code 422
25
+ class Invalid < Error; end
26
+
27
+ # Raised when FullContact returns the HTTP status code 500
28
+ class InternalServerError < Error; end
29
+
30
+ # Raised when FullContact returns the HTTP status code 502
31
+ class BadGateway < Error; end
32
+
33
+ # Raised when FullContact returns the HTTP status code 503
34
+ class ServiceUnavailable < Error; end
35
+ end
@@ -0,0 +1,43 @@
1
+ module FullContact
2
+ # Defines HTTP request methods
3
+ module Request
4
+ # Perform an HTTP GET request
5
+ def get(path, options={}, raw=false)
6
+ request(:get, path, options, raw)
7
+ end
8
+
9
+ # Perform an HTTP POST request
10
+ def post(path, options={}, raw=false)
11
+ request(:post, path, options, raw)
12
+ end
13
+
14
+ # Perform an HTTP DELETE request
15
+ def delete(path, options={}, raw=false)
16
+ request(:delete, path, options, raw)
17
+ end
18
+
19
+ private
20
+
21
+ # Perform an HTTP request
22
+ def request(method, path, options, raw=false)
23
+ if FullContact.options[:get_request_url_only]
24
+ return connection(raw).build_url(formatted_path(path), options)
25
+ end
26
+ options[:apiKey] = FullContact.options[:api_key]
27
+ unless FullContact.options[:access_token].nil?
28
+ options[:accessToken] = FullContact.options[:access_token]
29
+ end
30
+ response = connection(raw).send(method) do |request|
31
+ request.url(formatted_path(path), options)
32
+ request.headers["Content-Type"] = options[:content_type] if options.include?(:content_type)
33
+ request.body = options[:request_body] if options.include?(:request_body)
34
+ end
35
+ raw ? response : response.body
36
+ end
37
+
38
+ def formatted_path(path)
39
+ return path if format.to_s.empty?
40
+ [path, format].compact.join('.')
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,3 @@
1
+ module FullContact
2
+ VERSION = "0.3.2"
3
+ end
@@ -0,0 +1,56 @@
1
+ require 'helper'
2
+ require 'faraday'
3
+ require 'fullcontact'
4
+
5
+ describe Faraday::Response do
6
+ before do
7
+ FullContact.configure do |config|
8
+ config.api_key = "api_key"
9
+ end
10
+ @client = FullContact::Client.new
11
+ end
12
+
13
+ {
14
+ 400 => FullContact::BadRequest,
15
+ 401 => FullContact::Unauthorized,
16
+ 403 => FullContact::Forbidden,
17
+ 404 => FullContact::NotFound,
18
+ 422 => FullContact::Invalid,
19
+ 500 => FullContact::InternalServerError,
20
+ 502 => FullContact::BadGateway,
21
+ 503 => FullContact::ServiceUnavailable,
22
+ }.each do |status, exception|
23
+ if (status >= 500)
24
+ context "when HTTP status is #{status}" do
25
+ before do
26
+ stub_get('person.json').
27
+ with(:query => {:apiKey => "api_key", :email => 'brawest@gmail.com'}).
28
+ to_return(:status => status)
29
+ end
30
+
31
+ it "should raise #{exception.name} error" do
32
+ lambda do
33
+ @client.lookup_by_email('brawest@gmail.com')
34
+ end.should raise_error(exception)
35
+ end
36
+ end
37
+ else
38
+ [nil, "error", "errors"].each do |body|
39
+ context "when HTTP status is #{status} and body is #{body||='nil'}" do
40
+ before do
41
+ body_message = '{"'+body+'":"test"}' unless body.nil?
42
+ stub_get('person.json').
43
+ with(:query => {:apiKey => "api_key", :email => 'brawest@gmail.com'}).
44
+ to_return(:status => status, :body => body_message)
45
+ end
46
+
47
+ it "should raise #{exception.name} error" do
48
+ lambda do
49
+ @client.lookup_by_email('brawest@gmail.com')
50
+ end.should raise_error(exception)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ {
2
+ "status": 200
3
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "history":
3
+ [
4
+ {
5
+ "eTag": "fffffec9b5094cf18aaef4da318436755124a12d2422eaf2c9c44b95",
6
+ "date": "2012-03-25T17:45:43.441Z",
7
+ "action": "Enriched"
8
+ },
9
+ {
10
+ "eTag": "fffffec9b536c589363364e51a5dc9800f54d11cdbf1a21fe94ef35b",
11
+ "date": "2012-03-25T16:56:03.448Z",
12
+ "action": "Added"
13
+ }
14
+ ],
15
+ "status": 200
16
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "listId": "fd4e7ca63f79ea5113b2a2ebcf0759c5ebecc250",
3
+ "status": 200
4
+ }