linkedin-client 0.0.8

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.
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ # Ignore the _creds.rb spec file
2
+ spec/_creds.rb
3
+
4
+ # Ignore tempfiles
5
+ *.sw[op]
6
+ .DS_Store
7
+
8
+ # RVM
9
+ .rvmrc
10
+
11
+ # Gems
12
+ *.gem
13
+
14
+ # IDEs
15
+ .idea
16
+ .project
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --backtrace
3
+ --require rspec/instafail
4
+ --format RSpec::Instafail
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ - jruby-19mode
6
+ script: rspec
7
+ notifications:
8
+ email:
9
+ - mike.lewis@airbnb.com
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ #gem 'saddle', :path => '../saddle'
4
+ gem 'saddle', '~> 0.0.38'
5
+ gem 'simple_oauth', '~> 0.2.0'
6
+
7
+ group :test do
8
+ gem 'rspec', '~> 2.13.0'
9
+ gem 'rspec-instafail', '~> 0.2'
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,45 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activesupport (4.0.0)
5
+ i18n (~> 0.6, >= 0.6.4)
6
+ minitest (~> 4.2)
7
+ multi_json (~> 1.3)
8
+ thread_safe (~> 0.1)
9
+ tzinfo (~> 0.3.37)
10
+ atomic (1.1.10)
11
+ diff-lcs (1.2.4)
12
+ faraday (0.8.8)
13
+ multipart-post (~> 1.2.0)
14
+ faraday_middleware (0.9.0)
15
+ faraday (>= 0.7.4, < 0.9)
16
+ i18n (0.6.4)
17
+ minitest (4.7.5)
18
+ multi_json (1.7.7)
19
+ multipart-post (1.2.0)
20
+ rspec (2.13.0)
21
+ rspec-core (~> 2.13.0)
22
+ rspec-expectations (~> 2.13.0)
23
+ rspec-mocks (~> 2.13.0)
24
+ rspec-core (2.13.1)
25
+ rspec-expectations (2.13.0)
26
+ diff-lcs (>= 1.1.3, < 2.0)
27
+ rspec-instafail (0.2.4)
28
+ rspec-mocks (2.13.1)
29
+ saddle (0.0.38)
30
+ activesupport (>= 3.0)
31
+ faraday (~> 0.8.7)
32
+ faraday_middleware (~> 0.9.0)
33
+ simple_oauth (0.2.0)
34
+ thread_safe (0.1.2)
35
+ atomic
36
+ tzinfo (0.3.37)
37
+
38
+ PLATFORMS
39
+ ruby
40
+
41
+ DEPENDENCIES
42
+ rspec (~> 2.13.0)
43
+ rspec-instafail (~> 0.2)
44
+ saddle (~> 0.0.38)
45
+ simple_oauth (~> 0.2.0)
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2013, Mike Lewis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Ruby Linkedin OAuth 1+2 client
2
+
3
+
4
+ ## Usage
5
+
6
+ ### For OAuth 1.0
7
+
8
+ client = Linkedin::Client.create({
9
+ :oauth1 => {
10
+ :consumer_key => YOUR_CONSUMER_KEY,
11
+ :consumer_secret => YOUR_CONSUMER_SECRET,
12
+ :token => YOUR_OAUTH1_ACCESS_TOKEN,
13
+ :token_secret => YOUR_OAUTH1_ACCESS_TOKEN_SECRET
14
+ }
15
+ })
16
+ user = client.people.me
17
+
18
+
19
+ ### For OAuth 2.0
20
+
21
+ client = Linkedin::Client.create(
22
+ :oauth2_access_token => YOUR_USER_ACCESS_TOKEN
23
+ )
24
+ user = client.people.me
25
+
26
+
27
+ ## License
28
+ (c) Airbnb 2013
29
+ linkedin-client is released under the [MIT License](http://www.opensource.org/licenses/MIT).
@@ -0,0 +1,58 @@
1
+ require 'saddle'
2
+ require 'saddle/middleware/authentication/oauth1'
3
+ require 'saddle/middleware/authentication/oauth2'
4
+
5
+ require 'linkedin-client/exceptions'
6
+ require 'linkedin-client/middleware/declare_format'
7
+ require 'linkedin-client/middleware/exception_raiser'
8
+ require 'linkedin-client/version'
9
+
10
+
11
+
12
+ module Linkedin
13
+
14
+ class Client < Saddle::Client
15
+
16
+ def self.host
17
+ 'api.linkedin.com'
18
+ end
19
+
20
+ def self.path_prefix
21
+ 'v1'
22
+ end
23
+
24
+ def self.use_ssl
25
+ true
26
+ end
27
+
28
+ def self.num_retries
29
+ 1
30
+ end
31
+
32
+ def self.timeout
33
+ 5 # seconds
34
+ end
35
+
36
+
37
+ add_middleware({
38
+ :klass => Middleware::ExceptionRaiser,
39
+ })
40
+
41
+ add_middleware({
42
+ :klass => Middleware::DeclareFormat,
43
+ :args => [:json],
44
+ })
45
+
46
+
47
+ add_middleware({
48
+ :klass => Saddle::Middleware::Authentication::OAuth1,
49
+ })
50
+
51
+ add_middleware({
52
+ :klass => Saddle::Middleware::Authentication::OAuth2,
53
+ :args => ['oauth2_access_token'],
54
+ })
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,50 @@
1
+ require 'saddle/endpoint'
2
+
3
+
4
+
5
+ module Linkedin
6
+ module Endpoints
7
+
8
+ class People < Saddle::TraversalEndpoint
9
+
10
+ # If selectors is an Array, it can be used to request specific fields
11
+ def me(opts = {})
12
+ get(
13
+ url_with_selectors('~', opts[:selectors]),
14
+ {},
15
+ opts
16
+ )
17
+ end
18
+
19
+ def by_id(_id, opts = {})
20
+ get(
21
+ url_with_selectors("id=#{_id.to_s}", opts[:selectors]),
22
+ {},
23
+ opts
24
+ )
25
+ end
26
+
27
+ def by_url(_url, opts = {})
28
+ escaped_url = CGI::escape(_url.to_s)
29
+ get(
30
+ url_with_selectors("url=#{escaped_url}", opts[:selectors]),
31
+ {},
32
+ opts
33
+ )
34
+ end
35
+
36
+
37
+
38
+ private
39
+
40
+ def url_with_selectors(url, selectors)
41
+ if selectors.is_a?(Array)
42
+ url += ":(#{selectors.join(',')})"
43
+ end
44
+ url
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,37 @@
1
+
2
+ ##
3
+ # Exceptions for using the Linkedin client
4
+ # It is recommended that you handle these.
5
+ ##
6
+
7
+ module Linkedin
8
+
9
+ class GeneralException < StandardError; end
10
+
11
+ class TimeoutError < GeneralException; end
12
+
13
+ # Some problems might take care of themselves if you try again later. Others won't.
14
+ class TemporaryError < GeneralException; end # fire warnings on these
15
+ class PermanentError < GeneralException; end # fire errors on these
16
+
17
+
18
+ ## http://developer.linkedin.com/documents/handling-errors-invalid-tokens
19
+
20
+ # 400
21
+ class BadRequest < PermanentError; end
22
+
23
+ # 401
24
+ class BadToken < PermanentError; end
25
+ class ExpiredToken < BadToken; end
26
+ class InvalidToken < BadToken; end
27
+
28
+ # 403
29
+ class ThrottleLimit < TemporaryError; end
30
+
31
+ # 404
32
+ class PageNotFound < PermanentError; end
33
+
34
+ # 500
35
+ class ServiceError < TemporaryError; end
36
+
37
+ end
@@ -0,0 +1,25 @@
1
+ require 'faraday'
2
+
3
+
4
+
5
+ module Linkedin
6
+ module Middleware
7
+
8
+ ## Declare the data format you would like to use. Defaults to JSON.
9
+ #
10
+ class DeclareFormat < Faraday::Middleware
11
+
12
+ def initialize(app, format=:json)
13
+ super(app)
14
+ @format = format
15
+ end
16
+
17
+ def call(env)
18
+ env[:request_headers]['x-li-format'] = 'json'
19
+ @app.call(env)
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,51 @@
1
+ require 'faraday'
2
+
3
+ require 'linkedin-client/exceptions'
4
+
5
+
6
+
7
+ module Linkedin
8
+ module Middleware
9
+
10
+ ## Raise beautiful exceptions
11
+ #
12
+ class ExceptionRaiser < Faraday::Middleware
13
+
14
+ ## For handling errors, the message that gets returned is of the following format:
15
+ # {:status => env[:status], :headers => env[:response_headers], :body => env[:body]}
16
+
17
+ def call(env)
18
+ begin
19
+ @app.call(env)
20
+ rescue Faraday::Error::ClientError => e
21
+ exception =
22
+ case e.response[:status]
23
+ when 400
24
+ Linkedin::BadRequest
25
+ when 401
26
+ if e.response[:body] == 'This token has expired. Renew it'
27
+ Linkedin::ExpiredToken
28
+ elsif e.response[:body].start_with?('Throttle limit for calls to this resource')
29
+ Linkedin::InvalidToken
30
+ else
31
+ Linkedin::BadToken
32
+ end
33
+ when 403
34
+ Linkedin::ThrottleLimit
35
+ when 404
36
+ Linkedin::PageNotFound
37
+ when 500
38
+ Linkedin::ServiceError
39
+ else
40
+ Linkedin::GeneralException
41
+ end
42
+ raise exception, e.response
43
+ rescue Saddle::TimeoutError => e
44
+ raise Linkedin::TimeoutError, e.response
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,3 @@
1
+ module Linkedin
2
+ VERSION = '0.0.8'
3
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/linkedin-client/version', __FILE__)
3
+
4
+ lib = File.expand_path('../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'linkedin-client'
9
+ s.version = ::Linkedin::VERSION
10
+ s.authors = ['Mike Lewis']
11
+ s.email = ['mike.lewis@airbnb.com']
12
+ s.description = %q{Linkedin OAuth1+2 client}
13
+ s.summary = %q{
14
+ This is a Linkedin OAuth1+2 client implemented on Saddle
15
+ }
16
+ s.homepage = 'https://github.com/airbnb/linkedin-client'
17
+ s.license = 'MIT'
18
+
19
+ s.require_path = 'lib'
20
+ s.files = `git ls-files`.split($\)
21
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
22
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
23
+
24
+ s.add_dependency 'saddle', '~> 0.0.38'
25
+ s.add_dependency 'simple_oauth', '~> 0.2.0'
26
+ end
@@ -0,0 +1,10 @@
1
+ TEST_API_KEY = 'XXX_YOUR_API_KEY_XXX'
2
+ TEST_SECRET_KEY = 'XXX_YOUR_SECRET_KEY_XXX'
3
+
4
+ TEST_OAUTH1_ACCESS_TOKEN = 'XXX_YOUR_OAUTH1_ACCESS_TOKEN_HERE_XXX'
5
+ TEST_OAUTH1_ACCESS_TOKEN_SECRET = 'XXX_YOUR_OAUTH1_ACCESS_TOKEN_SECRET_HERE_XXX'
6
+
7
+ TEST_OAUTH2_ACCESS_TOKEN = 'XXX_YOUR_OAUTH2_ACCESS_TOKEN_HERE_XXX'
8
+
9
+ TEST_USER_ID = 'xxxabcxxx'
10
+ TEST_USER_URL = 'http://www.linkedin.com/in/your_name_here'
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ ###
5
+ # NOTE: This spec will actually hit Linkedin's servers
6
+ ###
7
+
8
+ describe 'Linkedin::Endpoints::People' do
9
+ context "Test integration of /people endpoints" do
10
+
11
+ # Skip if the creds aren't setup
12
+ if defined?(TEST_OAUTH2_ACCESS_TOKEN)
13
+
14
+ before :each do
15
+ @client = Linkedin::Client.create({
16
+ :oauth1 => {
17
+ :consumer_key => TEST_CONSUMER_KEY,
18
+ :consumer_secret => TEST_CONSUMER_SECRET,
19
+ :token => TEST_OAUTH1_ACCESS_TOKEN,
20
+ :token_secret => TEST_OAUTH1_ACCESS_TOKEN_SECRET
21
+ }
22
+ })
23
+ end
24
+
25
+ it 'should get self profile' do
26
+ @client.people.me.should be_a(Hash)
27
+ end
28
+
29
+ it 'should get self profile with selectors' do
30
+ @client.people.me({:selectors => ['id']}).should be_a(Hash)
31
+ end
32
+
33
+ it 'should get another profile by id' do
34
+ @client.people.by_id(TEST_USER_ID).should be_a(Hash)
35
+ end
36
+
37
+ it 'should get another profile by url' do
38
+ @client.people.by_url(TEST_USER_URL).should be_a(Hash)
39
+ end
40
+
41
+ else
42
+ puts "You should put valid creds in _creds.rb"
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ ###
5
+ # NOTE: This spec will actually hit Linkedin's servers
6
+ ###
7
+
8
+ describe 'Linkedin::Endpoints::People' do
9
+ context "Test integration of /people endpoints" do
10
+
11
+ # Skip if the creds aren't setup
12
+ if defined?(TEST_OAUTH2_ACCESS_TOKEN)
13
+
14
+ before :each do
15
+ @client = Linkedin::Client.create(:oauth2_access_token => TEST_OAUTH2_ACCESS_TOKEN)
16
+ end
17
+
18
+ it 'should get self profile' do
19
+ @client.people.me.should be_a(Hash)
20
+ end
21
+
22
+ it 'should get self profile with selectors' do
23
+ @client.people.me({:selectors => ['id']}).should be_a(Hash)
24
+ end
25
+
26
+ it 'should get another profile by id' do
27
+ @client.people.by_id(TEST_USER_ID).should be_a(Hash)
28
+ end
29
+
30
+ it 'should get another profile by url' do
31
+ @client.people.by_url(TEST_USER_URL).should be_a(Hash)
32
+ end
33
+
34
+ else
35
+ puts "You should put valid creds in _creds.rb"
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe Linkedin::Middleware::ExceptionRaiser do
5
+
6
+ context "Test raising various exceptions using stubs" do
7
+
8
+ before :each do
9
+ @stubs = Faraday::Adapter::Test::Stubs.new
10
+ @client = Linkedin::Client.create(:stubs => @stubs)
11
+ end
12
+
13
+
14
+ it 'should detect a bad request' do
15
+ @stubs.get('/v1') { [ 400, {}, '' ] }
16
+ expect { @client.requester.get('') }.to raise_error(Linkedin::BadRequest)
17
+ end
18
+
19
+ it 'should detect an expired token' do
20
+ @stubs.get('/v1') { [ 401, {}, 'This token has expired. Renew it' ] }
21
+ expect { @client.requester.get('') }.to raise_error(Linkedin::ExpiredToken)
22
+ end
23
+
24
+ it 'should detect an expired token' do
25
+ @stubs.get('/v1') { [ 401, {}, 'Throttle limit for calls to this resource, x, is reached.' ] }
26
+ expect { @client.requester.get('') }.to raise_error(Linkedin::InvalidToken)
27
+ end
28
+
29
+ it 'should detect a throttle limit' do
30
+ @stubs.get('/v1') { [ 403, {}, '' ] }
31
+ expect { @client.requester.get('') }.to raise_error(Linkedin::ThrottleLimit)
32
+ end
33
+
34
+ it 'should detect a 404' do
35
+ @stubs.get('/v1') { [ 404, {}, '' ] }
36
+ expect { @client.requester.get('') }.to raise_error(Linkedin::PageNotFound)
37
+ end
38
+
39
+ it 'should detect a server error' do
40
+ @stubs.get('/v1') { [ 500, {}, '' ] }
41
+ expect { @client.requester.get('') }.to raise_error(Linkedin::ServiceError)
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,15 @@
1
+ require 'linkedin-client'
2
+
3
+
4
+ # Load credentials from ENV if possible, or load from _creds.rb
5
+ if ENV['TEST_USER_TOKEN'] && ENV['TEST_USER_ID'] && ENV['TEST_USER_URL']
6
+ TEST_USER_TOKEN = ENV['TEST_USER_TOKEN']
7
+ TEST_USER_ID = ENV['TEST_USER_ID']
8
+ TEST_USER_URL = ENV['TEST_USER_URL']
9
+ else
10
+ begin
11
+ require '_creds'
12
+ rescue LoadError
13
+ puts "Using _creds.stub.rb, create a _creds.rb with actual credentials for a live test."
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: linkedin-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.8
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mike Lewis
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: saddle
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.0.38
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.0.38
30
+ - !ruby/object:Gem::Dependency
31
+ name: simple_oauth
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.2.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.2.0
46
+ description: Linkedin OAuth1+2 client
47
+ email:
48
+ - mike.lewis@airbnb.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
54
+ - .rspec
55
+ - .travis.yml
56
+ - Gemfile
57
+ - Gemfile.lock
58
+ - LICENSE
59
+ - README.md
60
+ - lib/linkedin-client.rb
61
+ - lib/linkedin-client/endpoints/people.rb
62
+ - lib/linkedin-client/exceptions.rb
63
+ - lib/linkedin-client/middleware/declare_format.rb
64
+ - lib/linkedin-client/middleware/exception_raiser.rb
65
+ - lib/linkedin-client/version.rb
66
+ - linkedin-client.gemspec
67
+ - spec/_creds.stub.rb
68
+ - spec/integration/oauth1_people_spec.rb
69
+ - spec/integration/oauth2_people_spec.rb
70
+ - spec/middleware/exception_raiser_spec.rb
71
+ - spec/spec_helper.rb
72
+ homepage: https://github.com/airbnb/linkedin-client
73
+ licenses:
74
+ - MIT
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 1.8.25
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: This is a Linkedin OAuth1+2 client implemented on Saddle
97
+ test_files:
98
+ - spec/_creds.stub.rb
99
+ - spec/integration/oauth1_people_spec.rb
100
+ - spec/integration/oauth2_people_spec.rb
101
+ - spec/middleware/exception_raiser_spec.rb
102
+ - spec/spec_helper.rb