linkedin-build 1.1.14
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.
- checksums.yaml +7 -0
- data/.autotest +14 -0
- data/.gemtest +0 -0
- data/.gitignore +49 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +99 -0
- data/EXAMPLES.md +202 -0
- data/Gemfile +11 -0
- data/LICENSE +22 -0
- data/README.md +43 -0
- data/Rakefile +15 -0
- data/lib/linked_in/api.rb +38 -0
- data/lib/linked_in/api/communications.rb +44 -0
- data/lib/linked_in/api/companies.rb +129 -0
- data/lib/linked_in/api/groups.rb +115 -0
- data/lib/linked_in/api/jobs.rb +64 -0
- data/lib/linked_in/api/people.rb +73 -0
- data/lib/linked_in/api/query_helpers.rb +86 -0
- data/lib/linked_in/api/share_and_social_stream.rb +137 -0
- data/lib/linked_in/client.rb +51 -0
- data/lib/linked_in/errors.rb +29 -0
- data/lib/linked_in/helpers.rb +6 -0
- data/lib/linked_in/helpers/authorization.rb +69 -0
- data/lib/linked_in/helpers/request.rb +85 -0
- data/lib/linked_in/mash.rb +95 -0
- data/lib/linked_in/search.rb +71 -0
- data/lib/linked_in/version.rb +11 -0
- data/lib/linkedin.rb +35 -0
- data/linkedin-build.gemspec +28 -0
- data/spec/cases/api_spec.rb +308 -0
- data/spec/cases/linkedin_spec.rb +37 -0
- data/spec/cases/mash_spec.rb +113 -0
- data/spec/cases/oauth_spec.rb +178 -0
- data/spec/cases/search_spec.rb +234 -0
- data/spec/fixtures/cassette_library/LinkedIn_Api/Company_API.yml +81 -0
- data/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml +81 -0
- data/spec/fixtures/cassette_library/LinkedIn_Client/_authorize_from_request/should_return_a_valid_access_token.yml +37 -0
- data/spec/fixtures/cassette_library/LinkedIn_Client/_request_token/with_a_callback_url/should_return_a_valid_access_token.yml +37 -0
- data/spec/fixtures/cassette_library/LinkedIn_Client/_request_token/with_default_options/should_return_a_valid_request_token.yml +37 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_company_name_option/should_perform_a_search.yml +92 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_email_address/should_perform_a_people_search.yml +57 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_first_name_and_last_name_options/should_perform_a_search.yml +100 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_first_name_and_last_name_options_with_fields/should_perform_a_search.yml +114 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_keywords_string_parameter/should_perform_a_search.yml +52 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_multiple_email_address/should_perform_a_multi-email_search.yml +59 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_single_keywords_option/should_perform_a_search.yml +52 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_single_keywords_option_with_pagination/should_perform_a_search.yml +43 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search/email_search_returns_unauthorized/should_raise_an_unauthorized_error.yml +59 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_keywords_options_with_fields/should_perform_a_search.yml +43 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_keywords_string_parameter/should_perform_a_company_search.yml +80 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_single_keywords_option/should_perform_a_company_search.yml +80 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_single_keywords_option_with_facets_to_return/should_return_a_facet.yml +80 -0
- data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_single_keywords_option_with_pagination/should_perform_a_search.yml +74 -0
- data/spec/helper.rb +34 -0
- metadata +282 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
module LinkedIn
|
2
|
+
module Api
|
3
|
+
|
4
|
+
module QueryHelpers
|
5
|
+
private
|
6
|
+
|
7
|
+
def group_path(options)
|
8
|
+
path = "/groups"
|
9
|
+
if id = options.delete(:id)
|
10
|
+
path += "/#{id}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def simple_query(path, options={})
|
15
|
+
fields = options.delete(:fields) || LinkedIn.default_profile_fields
|
16
|
+
|
17
|
+
if options.delete(:public)
|
18
|
+
path +=":public"
|
19
|
+
elsif fields
|
20
|
+
path +=":(#{build_fields_params(fields)})"
|
21
|
+
end
|
22
|
+
|
23
|
+
headers = options.delete(:headers) || {}
|
24
|
+
params = to_query(options)
|
25
|
+
path += "#{path.include?("?") ? "&" : "?"}#{params}" if !params.empty?
|
26
|
+
|
27
|
+
Mash.from_json(get(path, headers))
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_fields_params(fields)
|
31
|
+
if fields.is_a?(Hash) && !fields.empty?
|
32
|
+
fields.map {|index,value| "#{index}:(#{build_fields_params(value)})" }.join(',')
|
33
|
+
elsif fields.respond_to?(:each)
|
34
|
+
fields.map {|field| build_fields_params(field) }.join(',')
|
35
|
+
else
|
36
|
+
fields.to_s.gsub("_", "-")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def person_path(options)
|
41
|
+
path = "/people"
|
42
|
+
if id = options.delete(:id)
|
43
|
+
path += "/id=#{id}"
|
44
|
+
elsif url = options.delete(:url)
|
45
|
+
path += "/url=#{CGI.escape(url)}"
|
46
|
+
elsif email = options.delete(:email)
|
47
|
+
path += "::(#{email})"
|
48
|
+
else
|
49
|
+
path += "/~"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def company_path(options)
|
54
|
+
path = "/companies"
|
55
|
+
|
56
|
+
if domain = options.delete(:domain)
|
57
|
+
path += "?email-domain=#{CGI.escape(domain)}"
|
58
|
+
elsif id = options.delete(:id)
|
59
|
+
path += "/#{id}"
|
60
|
+
elsif url = options.delete(:url)
|
61
|
+
path += "/url=#{CGI.escape(url)}"
|
62
|
+
elsif name = options.delete(:name)
|
63
|
+
path += "/universal-name=#{CGI.escape(name)}"
|
64
|
+
elsif is_admin = options.delete(:is_admin)
|
65
|
+
path += "?is-company-admin=#{CGI.escape(is_admin)}"
|
66
|
+
else
|
67
|
+
path += "/~"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def picture_urls_path(options)
|
72
|
+
path = person_path(options)
|
73
|
+
path += "/picture-urls"
|
74
|
+
end
|
75
|
+
|
76
|
+
def jobs_path(options)
|
77
|
+
path = "/jobs"
|
78
|
+
if id = options.delete(:id)
|
79
|
+
path += "/id=#{id}"
|
80
|
+
else
|
81
|
+
path += "/~"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module LinkedIn
|
2
|
+
module Api
|
3
|
+
|
4
|
+
# Share and Social Stream APIs
|
5
|
+
#
|
6
|
+
# @see https://developer.linkedin.com/docs/share-on-linkedin Share API
|
7
|
+
#
|
8
|
+
# The following API actions do not have corresponding methods in
|
9
|
+
# this module
|
10
|
+
#
|
11
|
+
# * GET Network Statistics
|
12
|
+
# * POST Post Network Update
|
13
|
+
#
|
14
|
+
# [(contribute here)](https://github.com/hexgnu/linkedin)
|
15
|
+
module ShareAndSocialStream
|
16
|
+
|
17
|
+
# Retrieve the authenticated users network updates
|
18
|
+
#
|
19
|
+
# Permissions: rw_nus
|
20
|
+
#
|
21
|
+
# @see http://developer.linkedin.com/documents/get-network-updates-and-statistics-api
|
22
|
+
# @see http://developer.linkedin.com/documents/network-update-types Network Update Types
|
23
|
+
#
|
24
|
+
# @macro person_path_options
|
25
|
+
# @option options [String] :scope
|
26
|
+
# @option options [String] :type
|
27
|
+
# @option options [String] :count
|
28
|
+
# @option options [String] :start
|
29
|
+
# @option options [String] :after
|
30
|
+
# @option options [String] :before
|
31
|
+
# @option options [String] :show-hidden-members
|
32
|
+
# @return [LinkedIn::Mash]
|
33
|
+
def network_updates(options={})
|
34
|
+
path = "#{person_path(options)}/network/updates"
|
35
|
+
simple_query(path, options)
|
36
|
+
end
|
37
|
+
|
38
|
+
# TODO refactor to use #network_updates
|
39
|
+
def shares(options={})
|
40
|
+
path = "#{person_path(options)}/network/updates"
|
41
|
+
simple_query(path, {:type => "SHAR", :scope => "self"}.merge(options))
|
42
|
+
end
|
43
|
+
|
44
|
+
def share(update_key, options={})
|
45
|
+
path = "#{person_path(options)}/network/updates/key=#{update_key}"
|
46
|
+
simple_query(path, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Retrieve all comments for a particular network update
|
50
|
+
#
|
51
|
+
# @note The first 5 comments are included in the response to #network_updates
|
52
|
+
#
|
53
|
+
# Permissions: rw_nus
|
54
|
+
#
|
55
|
+
# @see http://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates
|
56
|
+
#
|
57
|
+
# @param [String] update_key a update/update-key representing a
|
58
|
+
# particular network update
|
59
|
+
# @macro person_path_options
|
60
|
+
# @return [LinkedIn::Mash]
|
61
|
+
def share_comments(update_key, options={})
|
62
|
+
path = "#{person_path(options)}/network/updates/key=#{update_key}/update-comments"
|
63
|
+
simple_query(path, options)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Retrieve all likes for a particular network update
|
67
|
+
#
|
68
|
+
# @note Some likes are included in the response to #network_updates
|
69
|
+
#
|
70
|
+
# Permissions: rw_nus
|
71
|
+
#
|
72
|
+
# @see http://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates
|
73
|
+
#
|
74
|
+
# @param [String] update_key a update/update-key representing a
|
75
|
+
# particular network update
|
76
|
+
# @macro person_path_options
|
77
|
+
# @return [LinkedIn::Mash]
|
78
|
+
def share_likes(update_key, options={})
|
79
|
+
path = "#{person_path(options)}/network/updates/key=#{update_key}/likes"
|
80
|
+
simple_query(path, options)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Create a share for the authenticated user
|
84
|
+
#
|
85
|
+
# Permissions: rw_nus
|
86
|
+
#
|
87
|
+
# @see https://developer.linkedin.com/docs/share-on-linkedin Share API
|
88
|
+
#
|
89
|
+
# @macro share_input_fields
|
90
|
+
# @return [void]
|
91
|
+
def add_share(share)
|
92
|
+
path = "/people/~/shares"
|
93
|
+
defaults = {:visibility => {:code => "anyone"}}
|
94
|
+
post(path, MultiJson.dump(defaults.merge(share)), "Content-Type" => "application/json")
|
95
|
+
end
|
96
|
+
|
97
|
+
# Create a comment on an update from the authenticated user
|
98
|
+
#
|
99
|
+
# @see http://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates
|
100
|
+
#
|
101
|
+
# @param [String] update_key a update/update-key representing a
|
102
|
+
# particular network update
|
103
|
+
# @param [String] comment The text of the comment
|
104
|
+
# @return [void]
|
105
|
+
def update_comment(update_key, comment)
|
106
|
+
path = "/people/~/network/updates/key=#{update_key}/update-comments"
|
107
|
+
body = {'comment' => comment}
|
108
|
+
post(path, MultiJson.dump(body), "Content-Type" => "application/json")
|
109
|
+
end
|
110
|
+
|
111
|
+
# (Update) like an update as the authenticated user
|
112
|
+
#
|
113
|
+
# @see http://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates
|
114
|
+
#
|
115
|
+
# @param [String] update_key a update/update-key representing a
|
116
|
+
# particular network update
|
117
|
+
# @return [void]
|
118
|
+
def like_share(update_key)
|
119
|
+
path = "/people/~/network/updates/key=#{update_key}/is-liked"
|
120
|
+
put(path, 'true', "Content-Type" => "application/json")
|
121
|
+
end
|
122
|
+
|
123
|
+
# (Destroy) unlike an update the authenticated user previously
|
124
|
+
# liked
|
125
|
+
#
|
126
|
+
# @see http://developer.linkedin.com/documents/commenting-reading-comments-and-likes-network-updates
|
127
|
+
#
|
128
|
+
# @param [String] update_key a update/update-key representing a
|
129
|
+
# particular network update
|
130
|
+
# @return [void]
|
131
|
+
def unlike_share(update_key)
|
132
|
+
path = "/people/~/network/updates/key=#{update_key}/is-liked"
|
133
|
+
put(path, 'false', "Content-Type" => "application/json")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module LinkedIn
|
4
|
+
|
5
|
+
class Client
|
6
|
+
include Helpers::Request
|
7
|
+
include Helpers::Authorization
|
8
|
+
include Api::QueryHelpers
|
9
|
+
include Api::People
|
10
|
+
include Api::Groups
|
11
|
+
include Api::Companies
|
12
|
+
include Api::Jobs
|
13
|
+
include Api::ShareAndSocialStream
|
14
|
+
include Api::Communications
|
15
|
+
include Search
|
16
|
+
|
17
|
+
attr_reader :consumer_token, :consumer_secret, :consumer_options
|
18
|
+
|
19
|
+
def initialize(ctoken=LinkedIn.token, csecret=LinkedIn.secret, options={})
|
20
|
+
@consumer_token = ctoken
|
21
|
+
@consumer_secret = csecret
|
22
|
+
@consumer_options = options
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# def current_status
|
27
|
+
# path = "/people/~/current-status"
|
28
|
+
# Crack::XML.parse(get(path))['current_status']
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# def network_statuses(options={})
|
32
|
+
# options[:type] = 'STAT'
|
33
|
+
# network_updates(options)
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# def network_updates(options={})
|
37
|
+
# path = "/people/~/network"
|
38
|
+
# Network.from_xml(get(to_uri(path, options)))
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# # helpful in making authenticated calls and writing the
|
42
|
+
# # raw xml to a fixture file
|
43
|
+
# def write_fixture(path, filename)
|
44
|
+
# file = File.new("test/fixtures/#{filename}", "w")
|
45
|
+
# file.puts(access_token.get(path).body)
|
46
|
+
# file.close
|
47
|
+
# end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module LinkedIn
|
2
|
+
module Errors
|
3
|
+
class LinkedInError < StandardError
|
4
|
+
attr_reader :data
|
5
|
+
def initialize(data)
|
6
|
+
@data = data
|
7
|
+
super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Raised when a 401 response status code is received
|
12
|
+
class UnauthorizedError < LinkedInError; end
|
13
|
+
|
14
|
+
# Raised when a 400 response status code is received
|
15
|
+
class GeneralError < LinkedInError; end
|
16
|
+
|
17
|
+
# Raised when a 403 response status code is received
|
18
|
+
class AccessDeniedError < LinkedInError; end
|
19
|
+
|
20
|
+
# Raised when a 404 response status code is received
|
21
|
+
class NotFoundError < LinkedInError; end
|
22
|
+
|
23
|
+
# Raised when a 500 response status code is received
|
24
|
+
class InformLinkedInError < LinkedInError; end
|
25
|
+
|
26
|
+
# Raised when a 502 or 503 response status code is received
|
27
|
+
class UnavailableError < LinkedInError; end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module LinkedIn
|
2
|
+
module Helpers
|
3
|
+
|
4
|
+
module Authorization
|
5
|
+
|
6
|
+
DEFAULT_OAUTH_OPTIONS = {
|
7
|
+
#:request_token_path => "/uas/oauth/requestToken",
|
8
|
+
:access_token_path => "/oauth/v2/accessToken", #"/uas/oauth/accessToken",
|
9
|
+
:authorize_path => "/oauth/v2/authorize",
|
10
|
+
:api_host => "https://api.linkedin.com",
|
11
|
+
:auth_host => "https://www.linkedin.com"
|
12
|
+
}
|
13
|
+
|
14
|
+
def consumer
|
15
|
+
@consumer ||= ::OAuth2::Client.new(@consumer_token, @consumer_secret, parse_oauth_options)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Note: If using oauth with a web app, be sure to provide :oauth_callback.
|
19
|
+
# Options:
|
20
|
+
# :oauth_callback => String, url that LinkedIn should redirect to
|
21
|
+
def request_token(options={}, *arguments, &block)
|
22
|
+
@request_token ||= consumer.get_request_token(options, *arguments, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
# For web apps use params[:oauth_verifier], for desktop apps,
|
26
|
+
# use the verifier is the pin that LinkedIn gives users.
|
27
|
+
def authorize_from_request(request_token, request_secret, verifier_or_pin)
|
28
|
+
request_token = ::OAuth::RequestToken.new(consumer, request_token, request_secret)
|
29
|
+
access_token = request_token.get_access_token(:oauth_verifier => verifier_or_pin)
|
30
|
+
@auth_token, @auth_secret = access_token.token, access_token.secret
|
31
|
+
end
|
32
|
+
|
33
|
+
def access_token
|
34
|
+
@access_token ||= ::OAuth2::AccessToken.new(consumer, @auth_token, :expires_at => @expires_at)
|
35
|
+
end
|
36
|
+
|
37
|
+
def authorize_from_access(atoken, expires_at)
|
38
|
+
@auth_token, @expires_at = atoken, expires_at
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# since LinkedIn uses api.linkedin.com for request and access token exchanges,
|
44
|
+
# but www.linkedin.com for authorize/authenticate, we have to take care
|
45
|
+
# of the url creation ourselves.
|
46
|
+
def parse_oauth_options
|
47
|
+
{
|
48
|
+
#:request_token_url => full_oauth_url_for(:request_token, :api_host),
|
49
|
+
:access_token_url => full_oauth_url_for(:access_token, :api_host),
|
50
|
+
:authorize_url => full_oauth_url_for(:authorize, :auth_host),
|
51
|
+
:site => @consumer_options[:site] || @consumer_options[:api_host] || DEFAULT_OAUTH_OPTIONS[:api_host],
|
52
|
+
:proxy => @consumer_options.fetch(:proxy, nil)
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def full_oauth_url_for(url_type, host_type)
|
57
|
+
if @consumer_options["#{url_type}_url".to_sym]
|
58
|
+
@consumer_options["#{url_type}_url".to_sym]
|
59
|
+
else
|
60
|
+
host = @consumer_options[:site] || @consumer_options[host_type] || DEFAULT_OAUTH_OPTIONS[host_type]
|
61
|
+
path = @consumer_options[:"#{url_type}_path".to_sym] || DEFAULT_OAUTH_OPTIONS["#{url_type}_path".to_sym]
|
62
|
+
"#{host}#{path}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module LinkedIn
|
2
|
+
module Helpers
|
3
|
+
|
4
|
+
module Request
|
5
|
+
|
6
|
+
DEFAULT_HEADERS = {
|
7
|
+
'x-li-format' => 'json'
|
8
|
+
}
|
9
|
+
|
10
|
+
API_PATH = '/v1'
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def get(path, options={})
|
15
|
+
response = access_token.get("#{API_PATH}#{path}", {:headers => DEFAULT_HEADERS.merge(options)})
|
16
|
+
raise_errors(response)
|
17
|
+
response.body
|
18
|
+
end
|
19
|
+
|
20
|
+
def post(path, body='', options={})
|
21
|
+
response = access_token.post("#{API_PATH}#{path}", {:body => body, :headers => DEFAULT_HEADERS.merge(options)})
|
22
|
+
raise_errors(response)
|
23
|
+
response
|
24
|
+
end
|
25
|
+
|
26
|
+
def put(path, body, options={})
|
27
|
+
response = access_token.put("#{API_PATH}#{path}", {:body => body, :headers => DEFAULT_HEADERS.merge(options)})
|
28
|
+
raise_errors(response)
|
29
|
+
response
|
30
|
+
end
|
31
|
+
|
32
|
+
def delete(path, options={})
|
33
|
+
response = access_token.delete("#{API_PATH}#{path}", {:headers => DEFAULT_HEADERS.merge(options)})
|
34
|
+
raise_errors(response)
|
35
|
+
response
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def raise_errors(response)
|
41
|
+
# Even if the json answer contains the HTTP status code, LinkedIn also sets this code
|
42
|
+
# in the HTTP answer (thankfully).
|
43
|
+
case response.status.to_i
|
44
|
+
when 401
|
45
|
+
data = Mash.from_json(response.body)
|
46
|
+
raise LinkedIn::Errors::UnauthorizedError.new(data), "(#{data.status}): #{data.message}"
|
47
|
+
when 400
|
48
|
+
data = Mash.from_json(response.body)
|
49
|
+
raise LinkedIn::Errors::GeneralError.new(data), "(#{data.status}): #{data.message}"
|
50
|
+
when 403
|
51
|
+
data = Mash.from_json(response.body)
|
52
|
+
raise LinkedIn::Errors::AccessDeniedError.new(data), "(#{data.status}): #{data.message}"
|
53
|
+
when 404
|
54
|
+
raise LinkedIn::Errors::NotFoundError, "(#{response.status}): #{response.message}"
|
55
|
+
when 500
|
56
|
+
raise LinkedIn::Errors::InformLinkedInError, "LinkedIn had an internal error. Please let them know in the forum. (#{response.status}): #{response.message}"
|
57
|
+
when 502..503
|
58
|
+
raise LinkedIn::Errors::UnavailableError, "(#{response.status}): #{response.message}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# Stolen from Rack::Util.build_query
|
64
|
+
def to_query(params)
|
65
|
+
params.map { |k, v|
|
66
|
+
if v.class == Array
|
67
|
+
to_query(v.map { |x| [k, x] })
|
68
|
+
else
|
69
|
+
v.nil? ? escape(k) : "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
|
70
|
+
end
|
71
|
+
}.join("&")
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_uri(path, options)
|
75
|
+
uri = URI.parse(path)
|
76
|
+
|
77
|
+
if options && options != {}
|
78
|
+
uri.query = to_query(options)
|
79
|
+
end
|
80
|
+
uri.to_s
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|