From bc786aba445d7e398af49452877586ea872c6b2b Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Thu, 30 Jan 2014 23:45:37 +0000 Subject: [PATCH 01/25] First stab at bringing config connection client --- lib/linked_in/client.rb | 24 --------- lib/linked_in/configuration.rb | 95 ++++++++++++++++++++++++++++++++++ lib/linked_in/connection.rb | 29 +++++++++++ 3 files changed, 124 insertions(+), 24 deletions(-) create mode 100644 lib/linked_in/configuration.rb create mode 100644 lib/linked_in/connection.rb diff --git a/lib/linked_in/client.rb b/lib/linked_in/client.rb index 645f196d..2e80b831 100644 --- a/lib/linked_in/client.rb +++ b/lib/linked_in/client.rb @@ -22,30 +22,6 @@ def initialize(ctoken=LinkedIn.token, csecret=LinkedIn.secret, options={}) @consumer_options = options end - # - # def current_status - # path = "/people/~/current-status" - # Crack::XML.parse(get(path))['current_status'] - # end - # - # def network_statuses(options={}) - # options[:type] = 'STAT' - # network_updates(options) - # end - # - # def network_updates(options={}) - # path = "/people/~/network" - # Network.from_xml(get(to_uri(path, options))) - # end - # - # # helpful in making authenticated calls and writing the - # # raw xml to a fixture file - # def write_fixture(path, filename) - # file = File.new("test/fixtures/#{filename}", "w") - # file.puts(access_token.get(path).body) - # file.close - # end - end end diff --git a/lib/linked_in/configuration.rb b/lib/linked_in/configuration.rb new file mode 100644 index 00000000..7f013d19 --- /dev/null +++ b/lib/linked_in/configuration.rb @@ -0,0 +1,95 @@ +require 'linked_in/version' + +module LinkedIn + # Defines constants and methods related to configuration + module Configuration + # An array of valid keys in the options hash when configuring a {LinkedIn::API} + VALID_OPTIONS_KEYS = [ + :adapter, + :consumer_key, + :consumer_secret, + :default_profile_fields, + :endpoint, + :format, + :gateway, + :oauth_token, + :oauth_token_secret, + :proxy, + :user_agent, + :faraday_options].freeze + + # The adapter that will be used to connect if none is set + DEFAULT_ADAPTER = :net_http + + # By default, don't set an application key + DEFAULT_CONSUMER_KEY = nil + + # By default, don't set an application secret + DEFAULT_CONSUMER_SECRET = nil + + # The endpoint that will be used to connect if none is set + # + DEFAULT_ENDPOINT = 'https://api.linkedin.com/v1'.freeze + + # The response format appended to the path and sent in the 'Accept' header if none is set + # + # @note JSON is preferred over XML because it is more concise and faster to parse. + DEFAULT_FORMAT = :json + + # By default, don't set a user oauth token + DEFAULT_OAUTH_TOKEN = nil + + # By default, don't set a user oauth secret + DEFAULT_OAUTH_TOKEN_SECRET = nil + + # By default, don't set any profile fields + DEFAULT_PROFILE_FIELDS = nil + + # By default, don't use a proxy server + DEFAULT_PROXY = nil + + # The value sent in the 'User-Agent' header if none is set + DEFAULT_USER_AGENT = "LinkedIn Ruby Gem #{LinkedIn::VERSION}".freeze + + DEFAULT_GATEWAY = nil + + DEFAULT_FARADAY_OPTIONS = {}.freeze + + # @private + attr_accessor *VALID_OPTIONS_KEYS + + # When this module is extended, set all configuration options to their default values + def self.extended(base) + base.reset + end + + # Convenience method to allow configuration options to be set in a block + def configure + yield self + end + + # Create a hash of options and their values + def options + options = {} + VALID_OPTIONS_KEYS.each{|k| options[k] = send(k)} + options + end + + # Reset all configuration options to defaults + def reset + self.adapter = DEFAULT_ADAPTER + self.consumer_key = DEFAULT_CONSUMER_KEY + self.consumer_secret = DEFAULT_CONSUMER_SECRET + self.default_profile_fields = DEFAULT_PROFILE_FIELDS + self.endpoint = DEFAULT_ENDPOINT + self.format = DEFAULT_FORMAT + self.oauth_token = DEFAULT_OAUTH_TOKEN + self.oauth_token_secret = DEFAULT_OAUTH_TOKEN_SECRET + self.proxy = DEFAULT_PROXY + self.user_agent = DEFAULT_USER_AGENT + self.gateway = DEFAULT_GATEWAY + self.faraday_options = DEFAULT_FARADAY_OPTIONS + self + end + end +end \ No newline at end of file diff --git a/lib/linked_in/connection.rb b/lib/linked_in/connection.rb new file mode 100644 index 00000000..9c39e04e --- /dev/null +++ b/lib/linked_in/connection.rb @@ -0,0 +1,29 @@ +require 'faraday' +require 'faraday_middleware' + +module LinkedIn + module Connection + private + def connection_options + { + :headers => { + 'Accept' => "application/#{format}", + 'User-Agent' => user_agent, + 'x-li-format' => 'json' + }, + :proxy => proxy, + :ssl => {:verity => false}, + :url => api_endpoint + } + end + + def connection + Faraday.new(connection_options) do |builder| + builder.use Faraday::Request::OAuth, authentication + builder.use Faraday::Request::UrlEncoded + builder.use Faraday::Response::ParseJson + builder.adapter(adapter) + end + end + end +end From 1adc6ef58e91ab35245b0d9b7e843aa23279f91e Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Thu, 30 Jan 2014 23:49:24 +0000 Subject: [PATCH 02/25] Verify not verity --- lib/linked_in/connection.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/linked_in/connection.rb b/lib/linked_in/connection.rb index 9c39e04e..44ae7a3c 100644 --- a/lib/linked_in/connection.rb +++ b/lib/linked_in/connection.rb @@ -5,16 +5,16 @@ module LinkedIn module Connection private def connection_options - { + faraday_options.merge({ :headers => { 'Accept' => "application/#{format}", 'User-Agent' => user_agent, 'x-li-format' => 'json' }, :proxy => proxy, - :ssl => {:verity => false}, + :ssl => {:verify => false}, :url => api_endpoint - } + }) end def connection From 2c6c0b400ada3d1c8744a233d174d17409bca101 Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Thu, 30 Jan 2014 23:57:31 +0000 Subject: [PATCH 03/25] Caching locally the connection variable --- lib/linked_in/connection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/linked_in/connection.rb b/lib/linked_in/connection.rb index 44ae7a3c..d4391c93 100644 --- a/lib/linked_in/connection.rb +++ b/lib/linked_in/connection.rb @@ -18,7 +18,7 @@ def connection_options end def connection - Faraday.new(connection_options) do |builder| + @connection ||= Faraday.new(connection_options) do |builder| builder.use Faraday::Request::OAuth, authentication builder.use Faraday::Request::UrlEncoded builder.use Faraday::Response::ParseJson From 7348501401795b9c20497a836ef07b8d41632e6d Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Thu, 30 Jan 2014 15:59:21 -0800 Subject: [PATCH 04/25] Move connection into client --- lib/linked_in/client.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/linked_in/client.rb b/lib/linked_in/client.rb index 2e80b831..b6288213 100644 --- a/lib/linked_in/client.rb +++ b/lib/linked_in/client.rb @@ -22,6 +22,28 @@ def initialize(ctoken=LinkedIn.token, csecret=LinkedIn.secret, options={}) @consumer_options = options end + def connection_options + faraday_options.merge({ + :headers => { + 'Accept' => "application/#{format}", + 'User-Agent' => user_agent, + 'x-li-format' => 'json' + }, + :proxy => proxy, + :ssl => {:verify => false}, + :url => api_endpoint + }) + end + + def connection + @connection ||= Faraday.new(connection_options) do |builder| + builder.use Faraday::Request::OAuth, authentication + builder.use Faraday::Request::UrlEncoded + builder.use Faraday::Response::ParseJson + builder.adapter(adapter) + end + end + end end From 8a1908d54265aa7422e10b5322f264be835fef2b Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Fri, 31 Jan 2014 00:28:08 +0000 Subject: [PATCH 05/25] WIP Faraday connection --- .rspec | 1 + lib/linked_in/client.rb | 30 ++++++++++++++++++++++++------ lib/linked_in/helpers/request.rb | 14 ++++---------- lib/linkedin.rb | 3 ++- linkedin.gemspec | 3 +++ 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/.rspec b/.rspec index 4e1e0d2f..ba44b749 100644 --- a/.rspec +++ b/.rspec @@ -1 +1,2 @@ --color +--fail-fast diff --git a/lib/linked_in/client.rb b/lib/linked_in/client.rb index b6288213..bd7ebdb8 100644 --- a/lib/linked_in/client.rb +++ b/lib/linked_in/client.rb @@ -1,4 +1,6 @@ require 'cgi' +require 'faraday' +require 'faraday_middleware' module LinkedIn @@ -21,26 +23,42 @@ def initialize(ctoken=LinkedIn.token, csecret=LinkedIn.secret, options={}) @consumer_secret = csecret @consumer_options = options end + private + + def authentication + { + :consumer_key => consumer_token, + :consumer_secret => consumer_secret, + :token => @auth_token, + :token_secret => @auth_secret + } + end + + def authenticated? + authentication.values.all? + end def connection_options - faraday_options.merge({ + LinkedIn.faraday_options.merge({ :headers => { - 'Accept' => "application/#{format}", - 'User-Agent' => user_agent, + 'Accept' => "application/#{LinkedIn.format}", + 'User-Agent' => LinkedIn.user_agent, 'x-li-format' => 'json' }, - :proxy => proxy, + :proxy => LinkedIn.proxy, :ssl => {:verify => false}, - :url => api_endpoint + :url => LinkedIn.endpoint }) end def connection + raise "Please authenticate first" unless authenticated? + @connection ||= Faraday.new(connection_options) do |builder| builder.use Faraday::Request::OAuth, authentication builder.use Faraday::Request::UrlEncoded builder.use Faraday::Response::ParseJson - builder.adapter(adapter) + builder.adapter(LinkedIn.adapter) end end diff --git a/lib/linked_in/helpers/request.rb b/lib/linked_in/helpers/request.rb index 94f66592..e604d633 100644 --- a/lib/linked_in/helpers/request.rb +++ b/lib/linked_in/helpers/request.rb @@ -3,34 +3,28 @@ module Helpers module Request - DEFAULT_HEADERS = { - 'x-li-format' => 'json' - } - - API_PATH = '/v1' - protected def get(path, options={}) - response = access_token.get("#{API_PATH}#{path}", DEFAULT_HEADERS.merge(options)) + response = connection.get(path, options) raise_errors(response) response.body end def post(path, body='', options={}) - response = access_token.post("#{API_PATH}#{path}", body, DEFAULT_HEADERS.merge(options)) + response = connection.post(path, body, options) raise_errors(response) response end def put(path, body, options={}) - response = access_token.put("#{API_PATH}#{path}", body, DEFAULT_HEADERS.merge(options)) + response = connection.put(path, body, options) raise_errors(response) response end def delete(path, options={}) - response = access_token.delete("#{API_PATH}#{path}", DEFAULT_HEADERS.merge(options)) + response = connection.delete(path, options) raise_errors(response) response end diff --git a/lib/linkedin.rb b/lib/linkedin.rb index 513f55ca..cea67420 100644 --- a/lib/linkedin.rb +++ b/lib/linkedin.rb @@ -1,7 +1,8 @@ require 'oauth' +require 'linked_in/configuration' module LinkedIn - + extend Configuration class << self attr_accessor :token, :secret, :default_profile_fields diff --git a/linkedin.gemspec b/linkedin.gemspec index ac2f6d4f..91b32784 100644 --- a/linkedin.gemspec +++ b/linkedin.gemspec @@ -5,6 +5,9 @@ Gem::Specification.new do |gem| gem.add_dependency 'hashie', '~> 3.0' gem.add_dependency 'multi_json', '~> 1.0' gem.add_dependency 'oauth', '~> 0.4' + gem.add_dependency 'faraday', '~> 0.8' + gem.add_dependency 'faraday_middleware' + gem.add_dependency 'simple_oauth' # gem.add_development_dependency 'json', '~> 1.6' gem.add_development_dependency 'rake', '~> 10' gem.add_development_dependency 'yard' From 195b64d1584dd7e74396182dec246fe31ea16b4a Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Fri, 31 Jan 2014 01:00:49 +0000 Subject: [PATCH 06/25] Proof of Concept done minus the weird fields issue --- lib/linked_in/api/communications.rb | 2 +- lib/linked_in/api/companies.rb | 6 ++--- lib/linked_in/api/groups.rb | 4 +-- lib/linked_in/api/jobs.rb | 2 +- lib/linked_in/api/query_helpers.rb | 10 ++++---- lib/linked_in/api/share_and_social_stream.rb | 8 +++--- lib/linked_in/helpers/request.rb | 8 +++--- lib/linked_in/mash.rb | 10 -------- lib/linked_in/search.rb | 9 +++---- spec/cases/api_spec.rb | 26 ++++++++++---------- spec/cases/mash_spec.rb | 10 -------- spec/cases/search_spec.rb | 10 ++++---- 12 files changed, 42 insertions(+), 63 deletions(-) diff --git a/lib/linked_in/api/communications.rb b/lib/linked_in/api/communications.rb index b6ac9983..6d805658 100644 --- a/lib/linked_in/api/communications.rb +++ b/lib/linked_in/api/communications.rb @@ -24,7 +24,7 @@ module Communications # message # @return [void] def send_message(subject, body, recipient_paths) - path = "/people/~/mailbox" + path = "people/~/mailbox" message = { 'subject' => subject, diff --git a/lib/linked_in/api/companies.rb b/lib/linked_in/api/companies.rb index 1110c100..d8f1a790 100644 --- a/lib/linked_in/api/companies.rb +++ b/lib/linked_in/api/companies.rb @@ -96,7 +96,7 @@ def company_updates_likes(update_key, options={}) # @macro share_input_fields # @return [void] def add_company_share(company_id, share) - path = "/companies/#{company_id}/shares" + path = "companies/#{company_id}/shares" defaults = {:visibility => {:code => "anyone"}} post(path, MultiJson.dump(defaults.merge(share)), "Content-Type" => "application/json") end @@ -108,7 +108,7 @@ def add_company_share(company_id, share) # @param [String] company_id Company ID # @return [void] def follow_company(company_id) - path = "/people/~/following/companies" + path = "people/~/following/companies" body = {:id => company_id } post(path, MultiJson.dump(body), "Content-Type" => "application/json") end @@ -120,7 +120,7 @@ def follow_company(company_id) # @param [String] company_id Company ID # @return [void] def unfollow_company(company_id) - path = "/people/~/following/companies/id=#{company_id}" + path = "people/~/following/companies/id=#{company_id}" delete(path) end end diff --git a/lib/linked_in/api/groups.rb b/lib/linked_in/api/groups.rb index 3483bd84..a21fd3f7 100644 --- a/lib/linked_in/api/groups.rb +++ b/lib/linked_in/api/groups.rb @@ -95,7 +95,7 @@ def post_group_discussion(group_id, discussion) # @macro share_input_fields # @return [void] def add_group_share(group_id, share) - path = "/groups/#{group_id}/posts" + path = "groups/#{group_id}/posts" post(path, MultiJson.dump(share), "Content-Type" => "application/json") end @@ -106,7 +106,7 @@ def add_group_share(group_id, share) # @param [String] group_id Group ID # @return [void] def join_group(group_id) - path = "/people/~/group-memberships/#{group_id}" + path = "people/~/group-memberships/#{group_id}" body = {'membership-state' => {'code' => 'member' }} put(path, MultiJson.dump(body), "Content-Type" => "application/json") end diff --git a/lib/linked_in/api/jobs.rb b/lib/linked_in/api/jobs.rb index 3689bc28..547b08e9 100644 --- a/lib/linked_in/api/jobs.rb +++ b/lib/linked_in/api/jobs.rb @@ -55,7 +55,7 @@ def job_suggestions(options = {}) # @param [String] job_id Job ID # @return [void] def add_job_bookmark(job_id) - path = "/people/~/job-bookmarks" + path = "people/~/job-bookmarks" body = {'job' => {'id' => job_id}} post(path, MultiJson.dump(body), "Content-Type" => "application/json") end diff --git a/lib/linked_in/api/query_helpers.rb b/lib/linked_in/api/query_helpers.rb index a1be84fe..b8dd88cc 100644 --- a/lib/linked_in/api/query_helpers.rb +++ b/lib/linked_in/api/query_helpers.rb @@ -5,7 +5,7 @@ module QueryHelpers private def group_path(options) - path = "/groups" + path = "groups" if id = options.delete(:id) path += "/#{id}" end @@ -24,7 +24,7 @@ def simple_query(path, options={}) params = to_query(options) path += "#{path.include?("?") ? "&" : "?"}#{params}" if !params.empty? - Mash.from_json(get(path, headers)) + Mash.new(get(path, headers)) end def build_fields_params(fields) @@ -38,7 +38,7 @@ def build_fields_params(fields) end def person_path(options) - path = "/people" + path = "people" if id = options.delete(:id) path += "/id=#{id}" elsif url = options.delete(:url) @@ -51,7 +51,7 @@ def person_path(options) end def company_path(options) - path = "/companies" + path = "companies" if domain = options.delete(:domain) path += "?email-domain=#{CGI.escape(domain)}" @@ -74,7 +74,7 @@ def picture_urls_path(options) end def jobs_path(options) - path = "/jobs" + path = "jobs" if id = options.delete(:id) path += "/id=#{id}" else diff --git a/lib/linked_in/api/share_and_social_stream.rb b/lib/linked_in/api/share_and_social_stream.rb index e9f2b4d9..8d7d44dd 100644 --- a/lib/linked_in/api/share_and_social_stream.rb +++ b/lib/linked_in/api/share_and_social_stream.rb @@ -85,7 +85,7 @@ def share_likes(update_key, options={}) # @macro share_input_fields # @return [void] def add_share(share) - path = "/people/~/shares" + path = "people/~/shares" defaults = {:visibility => {:code => "anyone"}} post(path, MultiJson.dump(defaults.merge(share)), "Content-Type" => "application/json") end @@ -99,7 +99,7 @@ def add_share(share) # @param [String] comment The text of the comment # @return [void] def update_comment(update_key, comment) - path = "/people/~/network/updates/key=#{update_key}/update-comments" + path = "people/~/network/updates/key=#{update_key}/update-comments" body = {'comment' => comment} post(path, MultiJson.dump(body), "Content-Type" => "application/json") end @@ -112,7 +112,7 @@ def update_comment(update_key, comment) # particular network update # @return [void] def like_share(update_key) - path = "/people/~/network/updates/key=#{update_key}/is-liked" + path = "people/~/network/updates/key=#{update_key}/is-liked" put(path, 'true', "Content-Type" => "application/json") end @@ -125,7 +125,7 @@ def like_share(update_key) # particular network update # @return [void] def unlike_share(update_key) - path = "/people/~/network/updates/key=#{update_key}/is-liked" + path = "people/~/network/updates/key=#{update_key}/is-liked" put(path, 'false', "Content-Type" => "application/json") end end diff --git a/lib/linked_in/helpers/request.rb b/lib/linked_in/helpers/request.rb index e604d633..e0a11da4 100644 --- a/lib/linked_in/helpers/request.rb +++ b/lib/linked_in/helpers/request.rb @@ -34,15 +34,15 @@ def delete(path, options={}) def raise_errors(response) # Even if the json answer contains the HTTP status code, LinkedIn also sets this code # in the HTTP answer (thankfully). - case response.code.to_i + case response.status.to_i when 401 - data = Mash.from_json(response.body) + data = Mash.new(response.body) raise LinkedIn::Errors::UnauthorizedError.new(data), "(#{data.status}): #{data.message}" when 400 - data = Mash.from_json(response.body) + data = Mash.new(response.body) raise LinkedIn::Errors::GeneralError.new(data), "(#{data.status}): #{data.message}" when 403 - data = Mash.from_json(response.body) + data = Mash.new(response.body) raise LinkedIn::Errors::AccessDeniedError.new(data), "(#{data.status}): #{data.message}" when 404 raise LinkedIn::Errors::NotFoundError, "(#{response.code}): #{response.message}" diff --git a/lib/linked_in/mash.rb b/lib/linked_in/mash.rb index b07e8ddd..9b987850 100644 --- a/lib/linked_in/mash.rb +++ b/lib/linked_in/mash.rb @@ -6,16 +6,6 @@ module LinkedIn # The generalized pseudo-object that is returned for all query # requests. class Mash < ::Hashie::Mash - - # Convert a json string to a Mash - # - # @param [String] json_string - # @return [LinkedIn::Mash] - def self.from_json(json_string) - result_hash = ::MultiJson.decode(json_string) - new(result_hash) - end - # Returns a Date if we have year, month and day, and no conflicting key # # @return [Date] diff --git a/lib/linked_in/search.rb b/lib/linked_in/search.rb index 2cf3f821..ce72e38b 100644 --- a/lib/linked_in/search.rb +++ b/lib/linked_in/search.rb @@ -18,7 +18,7 @@ module Search # @return [LinkedIn::Mash] def search(options={}, type='people') - path = "/#{type.to_s}-search" + path = "#{type.to_s}-search" if options.is_a?(Hash) fields = options.delete(:fields) @@ -27,10 +27,9 @@ def search(options={}, type='people') options = { :keywords => options } if options.is_a?(String) options = format_options_for_query(options) - - result_json = get(to_uri(path, options)) - - Mash.from_json(result_json) + puts options.inspect + puts path.inspect + Mash.new(get(path, options)) end private diff --git a/spec/cases/api_spec.rb b/spec/cases/api_spec.rb index d2a528ab..64758303 100644 --- a/spec/cases/api_spec.rb +++ b/spec/cases/api_spec.rb @@ -61,7 +61,7 @@ client.search(:first_name => "Javan").should be_an_instance_of(LinkedIn::Mash) end - it "should be able to search with an option and fetch specific fields" do + pending "should be able to search with an option and fetch specific fields" do stub_request(:get, "https://api.linkedin.com/v1/people-search:(num-results,total)?first-name=Javan").to_return( :body => "{}") client.search(:first_name => "Javan", :fields => ["num_results", "total"]).should be_an_instance_of(LinkedIn::Mash) @@ -71,14 +71,14 @@ stub_request(:post, "https://api.linkedin.com/v1/people/~/shares").to_return(:body => "", :status => 201) response = client.add_share(:comment => "Testing, 1, 2, 3") response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to share a new company status" do stub_request(:post, "https://api.linkedin.com/v1/companies/123456/shares").to_return(:body => "", :status => 201) response = client.add_company_share("123456", { :comment => "Testing, 1, 2, 3" }) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "returns the shares for a person" do @@ -92,7 +92,7 @@ :body => "", :status => 201) response = client.update_comment('SOMEKEY', "Testing, 1, 2, 3") response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to like a network update" do @@ -100,7 +100,7 @@ with(:body => "true").to_return(:body => "", :status => 201) response = client.like_share('SOMEKEY') response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to unlike a network update" do @@ -108,7 +108,7 @@ with(:body => "false").to_return(:body => "", :status => 201) response = client.unlike_share('SOMEKEY') response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to pass down the additional arguments to OAuth's get_request_token" do @@ -186,7 +186,7 @@ response = client.follow_company(1586) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to unfollow a company" do @@ -194,7 +194,7 @@ response = client.unfollow_company(1586) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end end @@ -220,7 +220,7 @@ stub_request(:post, "https://api.linkedin.com/v1/people/~/job-bookmarks").to_return(:body => "", :status => 201) response = client.add_job_bookmark(:id => 1452577) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end end @@ -247,7 +247,7 @@ response = client.join_group(123) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end it "should be able to list a group profile" do @@ -274,14 +274,14 @@ stub_request(:post, "https://api.linkedin.com/v1/groups/123/posts").with(:body => expected).to_return(:body => "", :status => 201) response = client.post_group_discussion(123, expected) response.body.should == nil - response.code.should == '201' + response.status.should == 201 end it "should be able to share a new group status" do stub_request(:post, "https://api.linkedin.com/v1/groups/1/posts").to_return(:body => "", :status => 201) response = client.add_group_share(1, :comment => "Testing, 1, 2, 3") response.body.should == nil - response.code.should == "201" + response.status.should == 201 end end @@ -290,7 +290,7 @@ stub_request(:post, "https://api.linkedin.com/v1/people/~/mailbox").to_return(:body => "", :status => 201) response = client.send_message("subject", "body", ["recip1", "recip2"]) response.body.should == nil - response.code.should == "201" + response.status.should == 201 end end diff --git a/spec/cases/mash_spec.rb b/spec/cases/mash_spec.rb index 08021e39..e2fcc904 100644 --- a/spec/cases/mash_spec.rb +++ b/spec/cases/mash_spec.rb @@ -2,16 +2,6 @@ describe LinkedIn::Mash do - describe ".from_json" do - it "should convert a json string to a Mash" do - json_string = "{\"name\":\"Josh Kalderimis\"}" - mash = LinkedIn::Mash.from_json(json_string) - - mash.should have_key('name') - mash.name.should == 'Josh Kalderimis' - end - end - describe "#convert_keys" do let(:mash) do LinkedIn::Mash.new({ diff --git a/spec/cases/search_spec.rb b/spec/cases/search_spec.rb index c3924c5c..6db9dee0 100644 --- a/spec/cases/search_spec.rb +++ b/spec/cases/search_spec.rb @@ -82,7 +82,7 @@ client.search({:keywords => 'apple', :fields => fields}, 'company') end - it "should perform a search" do + pending "should perform a search" do results.companies.all.first.name.should == 'Apple' results.companies.all.first.description.should == 'Apple designs Macs, the best personal computers in the world, along with OS X, iLife, iWork and professional software. Apple leads the digital music revolution with its iPods and iTunes online store. Apple has reinvented the mobile phone with its revolutionary iPhone and App Store, and is defining the future of mobile media and computing devices with iPad.' results.companies.all.first.id.should == 162479 @@ -156,7 +156,7 @@ client.profile(:email => 'email=yy@zz.com', :fields => fields) end - it "should perform a people search" do + pending "should perform a people search" do results._total.should == 1 output = results["values"] output.each do |record| @@ -173,7 +173,7 @@ client.profile(:email => 'email=yy@zz.com,email=xx@yy.com', :fields => fields) end - it "should perform a multi-email search" do + pending "should perform a multi-email search" do results._total.should == 2 output = results["values"] output.count.should == 2 @@ -182,7 +182,7 @@ describe "email search returns unauthorized", vcr: vcr_options do - it "should raise an unauthorized error" do + pending "should raise an unauthorized error" do fields = ['id'] expect {client.profile(:email => 'email=aa@bb.com', :fields => fields)}.to raise_error(LinkedIn::Errors::UnauthorizedError) end @@ -195,7 +195,7 @@ client.search(:first_name => 'Charles', :last_name => 'Garcia', :fields => fields) end - it "should perform a search" do + pending "should perform a search" do first_person = results.people.all.first results.people.all.size.should == 10 first_person.first_name.should == 'Charles' From 45c22b05a8612491e9d0eaf87c9c053f397e6eac Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Mon, 3 Feb 2014 10:25:17 -0800 Subject: [PATCH 07/25] Take out puts --- lib/linked_in/search.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/linked_in/search.rb b/lib/linked_in/search.rb index ce72e38b..76e7f4de 100644 --- a/lib/linked_in/search.rb +++ b/lib/linked_in/search.rb @@ -27,8 +27,6 @@ def search(options={}, type='people') options = { :keywords => options } if options.is_a?(String) options = format_options_for_query(options) - puts options.inspect - puts path.inspect Mash.new(get(path, options)) end From 3202628b42adb346000f4484a2131b1ac91b6695 Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Mon, 3 Feb 2014 11:02:12 -0800 Subject: [PATCH 08/25] All things passing --- lib/linked_in/configuration.rb | 2 +- lib/linked_in/helpers/request.rb | 9 ++++----- spec/cases/api_spec.rb | 2 +- spec/cases/search_spec.rb | 12 ++++++------ 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/linked_in/configuration.rb b/lib/linked_in/configuration.rb index 7f013d19..93564223 100644 --- a/lib/linked_in/configuration.rb +++ b/lib/linked_in/configuration.rb @@ -29,7 +29,7 @@ module Configuration # The endpoint that will be used to connect if none is set # - DEFAULT_ENDPOINT = 'https://api.linkedin.com/v1'.freeze + DEFAULT_ENDPOINT = 'https://api.linkedin.com/'.freeze # The response format appended to the path and sent in the 'Accept' header if none is set # diff --git a/lib/linked_in/helpers/request.rb b/lib/linked_in/helpers/request.rb index e0a11da4..37a2e1b6 100644 --- a/lib/linked_in/helpers/request.rb +++ b/lib/linked_in/helpers/request.rb @@ -6,25 +6,25 @@ module Request protected def get(path, options={}) - response = connection.get(path, options) + response = connection.get('v1/' + path, options) raise_errors(response) response.body end def post(path, body='', options={}) - response = connection.post(path, body, options) + response = connection.post('v1/' + path, body, options) raise_errors(response) response end def put(path, body, options={}) - response = connection.put(path, body, options) + response = connection.put('v1/' + path, body, options) raise_errors(response) response end def delete(path, options={}) - response = connection.delete(path, options) + response = connection.delete('v1/' + path, options) raise_errors(response) response end @@ -53,7 +53,6 @@ def raise_errors(response) end end - # Stolen from Rack::Util.build_query def to_query(params) params.map { |k, v| diff --git a/spec/cases/api_spec.rb b/spec/cases/api_spec.rb index 64758303..b7cf169d 100644 --- a/spec/cases/api_spec.rb +++ b/spec/cases/api_spec.rb @@ -61,7 +61,7 @@ client.search(:first_name => "Javan").should be_an_instance_of(LinkedIn::Mash) end - pending "should be able to search with an option and fetch specific fields" do + it "should be able to search with an option and fetch specific fields" do stub_request(:get, "https://api.linkedin.com/v1/people-search:(num-results,total)?first-name=Javan").to_return( :body => "{}") client.search(:first_name => "Javan", :fields => ["num_results", "total"]).should be_an_instance_of(LinkedIn::Mash) diff --git a/spec/cases/search_spec.rb b/spec/cases/search_spec.rb index 6db9dee0..01ace293 100644 --- a/spec/cases/search_spec.rb +++ b/spec/cases/search_spec.rb @@ -82,7 +82,7 @@ client.search({:keywords => 'apple', :fields => fields}, 'company') end - pending "should perform a search" do + it "should perform a search" do results.companies.all.first.name.should == 'Apple' results.companies.all.first.description.should == 'Apple designs Macs, the best personal computers in the world, along with OS X, iLife, iWork and professional software. Apple leads the digital music revolution with its iPods and iTunes online store. Apple has reinvented the mobile phone with its revolutionary iPhone and App Store, and is defining the future of mobile media and computing devices with iPad.' results.companies.all.first.id.should == 162479 @@ -156,7 +156,7 @@ client.profile(:email => 'email=yy@zz.com', :fields => fields) end - pending "should perform a people search" do + it "should perform a people search" do results._total.should == 1 output = results["values"] output.each do |record| @@ -167,13 +167,13 @@ end describe "by multiple email address", vcr: vcr_options do - + let(:results) do fields = ['id'] client.profile(:email => 'email=yy@zz.com,email=xx@yy.com', :fields => fields) end - pending "should perform a multi-email search" do + it "should perform a multi-email search" do results._total.should == 2 output = results["values"] output.count.should == 2 @@ -182,7 +182,7 @@ describe "email search returns unauthorized", vcr: vcr_options do - pending "should raise an unauthorized error" do + it "should raise an unauthorized error" do fields = ['id'] expect {client.profile(:email => 'email=aa@bb.com', :fields => fields)}.to raise_error(LinkedIn::Errors::UnauthorizedError) end @@ -195,7 +195,7 @@ client.search(:first_name => 'Charles', :last_name => 'Garcia', :fields => fields) end - pending "should perform a search" do + it "should perform a search" do first_person = results.people.all.first results.people.all.size.should == 10 first_person.first_name.should == 'Charles' From ef014d3558f6d06e633fae2d13a4bd0e803e69fb Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Mon, 3 Feb 2014 11:14:28 -0800 Subject: [PATCH 09/25] Finishing up and giving the ability to add new middleware --- lib/linked_in/configuration.rb | 11 ++++++++++- lib/linked_in/connection.rb | 9 ++++++--- spec/helper.rb | 1 + 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/linked_in/configuration.rb b/lib/linked_in/configuration.rb index 93564223..0e8577fc 100644 --- a/lib/linked_in/configuration.rb +++ b/lib/linked_in/configuration.rb @@ -1,4 +1,6 @@ require 'linked_in/version' +require 'faraday' +require 'faraday_middleware' module LinkedIn # Defines constants and methods related to configuration @@ -16,7 +18,8 @@ module Configuration :oauth_token_secret, :proxy, :user_agent, - :faraday_options].freeze + :faraday_options, + :middleware].freeze # The adapter that will be used to connect if none is set DEFAULT_ADAPTER = :net_http @@ -55,6 +58,11 @@ module Configuration DEFAULT_FARADAY_OPTIONS = {}.freeze + DEFAULT_MIDDLEWARE = [ + ::Faraday::Request::UrlEncoded, + ::Faraday::Response::ParseJson + ] + # @private attr_accessor *VALID_OPTIONS_KEYS @@ -89,6 +97,7 @@ def reset self.user_agent = DEFAULT_USER_AGENT self.gateway = DEFAULT_GATEWAY self.faraday_options = DEFAULT_FARADAY_OPTIONS + self.middleware = DEFAULT_MIDDLEWARE self end end diff --git a/lib/linked_in/connection.rb b/lib/linked_in/connection.rb index d4391c93..62bc734e 100644 --- a/lib/linked_in/connection.rb +++ b/lib/linked_in/connection.rb @@ -19,9 +19,12 @@ def connection_options def connection @connection ||= Faraday.new(connection_options) do |builder| - builder.use Faraday::Request::OAuth, authentication - builder.use Faraday::Request::UrlEncoded - builder.use Faraday::Response::ParseJson + Faraday::Request::OAuth, authentication + + middleware.each do |middle| + builder.use middle + end + builder.adapter(adapter) end end diff --git a/spec/helper.rb b/spec/helper.rb index b0765d65..b1dd8650 100644 --- a/spec/helper.rb +++ b/spec/helper.rb @@ -1,5 +1,6 @@ $:.unshift File.expand_path('..', __FILE__) $:.unshift File.expand_path('../../lib', __FILE__) + if ENV['COVERAGE'] == 't' require 'simplecov' SimpleCov.start From 40f78239658c2b989232d4317afec68466ac63bc Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Mon, 3 Feb 2014 11:18:37 -0800 Subject: [PATCH 10/25] Take out to_query and to_uri helpers --- lib/linked_in/api/query_helpers.rb | 6 +++--- lib/linked_in/helpers/request.rb | 24 ++---------------------- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/lib/linked_in/api/query_helpers.rb b/lib/linked_in/api/query_helpers.rb index b8dd88cc..44b6d091 100644 --- a/lib/linked_in/api/query_helpers.rb +++ b/lib/linked_in/api/query_helpers.rb @@ -21,10 +21,10 @@ def simple_query(path, options={}) end headers = options.delete(:headers) || {} - params = to_query(options) - path += "#{path.include?("?") ? "&" : "?"}#{params}" if !params.empty? + # params = to_query(options) + # path += "#{path.include?("?") ? "&" : "?"}#{params}" if !params.empty? - Mash.new(get(path, headers)) + Mash.new(get(path, options, headers)) end def build_fields_params(fields) diff --git a/lib/linked_in/helpers/request.rb b/lib/linked_in/helpers/request.rb index 37a2e1b6..a7d92e3b 100644 --- a/lib/linked_in/helpers/request.rb +++ b/lib/linked_in/helpers/request.rb @@ -5,8 +5,8 @@ module Request protected - def get(path, options={}) - response = connection.get('v1/' + path, options) + def get(path, query_params, headers = {}) + response = connection.get('v1/' + path, query_params, headers) raise_errors(response) response.body end @@ -52,26 +52,6 @@ def raise_errors(response) raise LinkedIn::Errors::UnavailableError, "(#{response.code}): #{response.message}" end end - - # Stolen from Rack::Util.build_query - def to_query(params) - params.map { |k, v| - if v.class == Array - to_query(v.map { |x| [k, x] }) - else - v.nil? ? escape(k) : "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" - end - }.join("&") - end - - def to_uri(path, options) - uri = URI.parse(path) - - if options && options != {} - uri.query = to_query(options) - end - uri.to_s - end end end From 80222d1d8984a2dfe1c56ef4ea5c2a9c60d2fc33 Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Mon, 3 Feb 2014 11:44:19 -0800 Subject: [PATCH 11/25] Refactor error reporting --- lib/linked_in/client.rb | 5 +- lib/linked_in/configuration.rb | 4 +- lib/linked_in/connection.rb | 32 ----------- lib/linked_in/helpers/request.rb | 67 ++++++---------------- lib/linked_in/middleware/error_reporter.rb | 23 ++++++++ lib/linkedin.rb | 2 +- spec/cases/error_reporter_spec.rb | 42 ++++++++++++++ 7 files changed, 91 insertions(+), 84 deletions(-) delete mode 100644 lib/linked_in/connection.rb create mode 100644 lib/linked_in/middleware/error_reporter.rb create mode 100644 spec/cases/error_reporter_spec.rb diff --git a/lib/linked_in/client.rb b/lib/linked_in/client.rb index bd7ebdb8..8e7328e2 100644 --- a/lib/linked_in/client.rb +++ b/lib/linked_in/client.rb @@ -56,8 +56,9 @@ def connection @connection ||= Faraday.new(connection_options) do |builder| builder.use Faraday::Request::OAuth, authentication - builder.use Faraday::Request::UrlEncoded - builder.use Faraday::Response::ParseJson + LinkedIn.middleware.each do |middle| + builder.use middle + end builder.adapter(LinkedIn.adapter) end end diff --git a/lib/linked_in/configuration.rb b/lib/linked_in/configuration.rb index 0e8577fc..599c73b6 100644 --- a/lib/linked_in/configuration.rb +++ b/lib/linked_in/configuration.rb @@ -1,6 +1,7 @@ require 'linked_in/version' require 'faraday' require 'faraday_middleware' +require 'linked_in/middleware/error_reporter' module LinkedIn # Defines constants and methods related to configuration @@ -60,7 +61,8 @@ module Configuration DEFAULT_MIDDLEWARE = [ ::Faraday::Request::UrlEncoded, - ::Faraday::Response::ParseJson + ::Faraday::Response::ParseJson, + ::LinkedIn::ErrorReporter ] # @private diff --git a/lib/linked_in/connection.rb b/lib/linked_in/connection.rb deleted file mode 100644 index 62bc734e..00000000 --- a/lib/linked_in/connection.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'faraday' -require 'faraday_middleware' - -module LinkedIn - module Connection - private - def connection_options - faraday_options.merge({ - :headers => { - 'Accept' => "application/#{format}", - 'User-Agent' => user_agent, - 'x-li-format' => 'json' - }, - :proxy => proxy, - :ssl => {:verify => false}, - :url => api_endpoint - }) - end - - def connection - @connection ||= Faraday.new(connection_options) do |builder| - Faraday::Request::OAuth, authentication - - middleware.each do |middle| - builder.use middle - end - - builder.adapter(adapter) - end - end - end -end diff --git a/lib/linked_in/helpers/request.rb b/lib/linked_in/helpers/request.rb index a7d92e3b..14711c2d 100644 --- a/lib/linked_in/helpers/request.rb +++ b/lib/linked_in/helpers/request.rb @@ -5,54 +5,25 @@ module Request protected - def get(path, query_params, headers = {}) - response = connection.get('v1/' + path, query_params, headers) - raise_errors(response) - response.body - end - - def post(path, body='', options={}) - response = connection.post('v1/' + path, body, options) - raise_errors(response) - response - end - - def put(path, body, options={}) - response = connection.put('v1/' + path, body, options) - raise_errors(response) - response - end - - def delete(path, options={}) - response = connection.delete('v1/' + path, options) - raise_errors(response) - response - end - - private - - def raise_errors(response) - # Even if the json answer contains the HTTP status code, LinkedIn also sets this code - # in the HTTP answer (thankfully). - case response.status.to_i - when 401 - data = Mash.new(response.body) - raise LinkedIn::Errors::UnauthorizedError.new(data), "(#{data.status}): #{data.message}" - when 400 - data = Mash.new(response.body) - raise LinkedIn::Errors::GeneralError.new(data), "(#{data.status}): #{data.message}" - when 403 - data = Mash.new(response.body) - raise LinkedIn::Errors::AccessDeniedError.new(data), "(#{data.status}): #{data.message}" - when 404 - raise LinkedIn::Errors::NotFoundError, "(#{response.code}): #{response.message}" - when 500 - raise LinkedIn::Errors::InformLinkedInError, "LinkedIn had an internal error. Please let them know in the forum. (#{response.code}): #{response.message}" - when 502..503 - raise LinkedIn::Errors::UnavailableError, "(#{response.code}): #{response.message}" - end - end + def get(path, query_params, headers = {}) + response = connection.get('v1/' + path, query_params, headers) + response.body + end + + def post(path, body='', options={}) + response = connection.post('v1/' + path, body, options) + response + end + + def put(path, body, options={}) + response = connection.put('v1/' + path, body, options) + response + end + + def delete(path, options={}) + response = connection.delete('v1/' + path, options) + response + end end - end end diff --git a/lib/linked_in/middleware/error_reporter.rb b/lib/linked_in/middleware/error_reporter.rb new file mode 100644 index 00000000..5c5a1106 --- /dev/null +++ b/lib/linked_in/middleware/error_reporter.rb @@ -0,0 +1,23 @@ +module LinkedIn + class ErrorReporter < Faraday::Middleware + def call(env) + @app.call(env).on_complete do + response = env[:response] + case response.status + when 401 + raise LinkedIn::Errors::UnauthorizedError.new(response), "(#{response.status}): #{response.body}" + when 400 + raise LinkedIn::Errors::GeneralError.new(response), "(#{response.status}): #{response.body}" + when 403 + raise LinkedIn::Errors::AccessDeniedError.new(response), "(#{response.status}): #{response.body}" + when 404 + raise LinkedIn::Errors::NotFoundError, "(#{response.status}): #{response.body}" + when 500 + raise LinkedIn::Errors::InformLinkedInError, "LinkedIn had an internal error. Please let them know in the forum. (#{response.status}): #{response.body}" + when 502..503 + raise LinkedIn::Errors::UnavailableError, "(#{response.status}): #{response.body}" + end + end + end + end +end \ No newline at end of file diff --git a/lib/linkedin.rb b/lib/linkedin.rb index cea67420..ef4e5554 100644 --- a/lib/linkedin.rb +++ b/lib/linkedin.rb @@ -33,4 +33,4 @@ def configure autoload :Helpers, "linked_in/helpers" autoload :Search, "linked_in/search" autoload :Version, "linked_in/version" -end +end \ No newline at end of file diff --git a/spec/cases/error_reporter_spec.rb b/spec/cases/error_reporter_spec.rb new file mode 100644 index 00000000..6cebfe98 --- /dev/null +++ b/spec/cases/error_reporter_spec.rb @@ -0,0 +1,42 @@ +require 'helper' + +describe LinkedIn::Client do + before do + LinkedIn.default_profile_fields = nil + client.stub(:consumer).and_return(consumer) + client.authorize_from_access('atoken', 'asecret') + end + + let(:client){LinkedIn::Client.new('token', 'secret')} + let(:consumer){OAuth::Consumer.new('token', 'secret', {:site => 'https://api.linkedin.com'})} + + it 'raises an unauthorized error when 401' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 401) + ->{ client.profile }.should raise_error(LinkedIn::Errors::UnauthorizedError) + end + + it 'raises a general error when 400' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 400) + ->{ client.profile }.should raise_error(LinkedIn::Errors::GeneralError) + end + + it 'raises a access denied error when 403' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 403) + ->{ client.profile }.should raise_error(LinkedIn::Errors::AccessDeniedError) + end + + it 'raises a notfounderror when 404' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 404) + ->{ client.profile }.should raise_error(LinkedIn::Errors::NotFoundError) + end + + it 'raises a informlinkedinerror if 500' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 500) + ->{ client.profile }.should raise_error(LinkedIn::Errors::InformLinkedInError) + end + + it 'raises an unavailable error if either 502 or 503' do + stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 502) + ->{ client.profile }.should raise_error(LinkedIn::Errors::UnavailableError) + end +end \ No newline at end of file From 74483091703fda8bd802e860193256abc9b52db0 Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Mon, 3 Feb 2014 11:56:33 -0800 Subject: [PATCH 12/25] Use mashify instead of Mash.new --- lib/linked_in/api/query_helpers.rb | 2 +- lib/linked_in/client.rb | 8 +++++++- lib/linked_in/configuration.rb | 2 -- lib/linked_in/errors.rb | 8 +------- lib/linked_in/search.rb | 2 +- 5 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/linked_in/api/query_helpers.rb b/lib/linked_in/api/query_helpers.rb index 44b6d091..30adcdd1 100644 --- a/lib/linked_in/api/query_helpers.rb +++ b/lib/linked_in/api/query_helpers.rb @@ -24,7 +24,7 @@ def simple_query(path, options={}) # params = to_query(options) # path += "#{path.include?("?") ? "&" : "?"}#{params}" if !params.empty? - Mash.new(get(path, options, headers)) + get(path, options, headers) end def build_fields_params(fields) diff --git a/lib/linked_in/client.rb b/lib/linked_in/client.rb index 8e7328e2..44b639fd 100644 --- a/lib/linked_in/client.rb +++ b/lib/linked_in/client.rb @@ -55,10 +55,16 @@ def connection raise "Please authenticate first" unless authenticated? @connection ||= Faraday.new(connection_options) do |builder| - builder.use Faraday::Request::OAuth, authentication + builder.use ::Faraday::Request::OAuth, authentication + builder.use ::Faraday::Request::UrlEncoded + + builder.use ::FaradayMiddleware::Mashify, :mash_class => LinkedIn::Mash + builder.use ::Faraday::Response::ParseJson + LinkedIn.middleware.each do |middle| builder.use middle end + builder.adapter(LinkedIn.adapter) end end diff --git a/lib/linked_in/configuration.rb b/lib/linked_in/configuration.rb index 599c73b6..e1efbe22 100644 --- a/lib/linked_in/configuration.rb +++ b/lib/linked_in/configuration.rb @@ -60,8 +60,6 @@ module Configuration DEFAULT_FARADAY_OPTIONS = {}.freeze DEFAULT_MIDDLEWARE = [ - ::Faraday::Request::UrlEncoded, - ::Faraday::Response::ParseJson, ::LinkedIn::ErrorReporter ] diff --git a/lib/linked_in/errors.rb b/lib/linked_in/errors.rb index bded0658..59c422aa 100644 --- a/lib/linked_in/errors.rb +++ b/lib/linked_in/errors.rb @@ -1,12 +1,6 @@ module LinkedIn module Errors - class LinkedInError < StandardError - attr_reader :data - def initialize(data) - @data = data - super - end - end + class LinkedInError < StandardError; end # Raised when a 401 response status code is received class UnauthorizedError < LinkedInError; end diff --git a/lib/linked_in/search.rb b/lib/linked_in/search.rb index 76e7f4de..9a2d5561 100644 --- a/lib/linked_in/search.rb +++ b/lib/linked_in/search.rb @@ -27,7 +27,7 @@ def search(options={}, type='people') options = { :keywords => options } if options.is_a?(String) options = format_options_for_query(options) - Mash.new(get(path, options)) + get(path, options) end private From 10437695d5fc6381902c5102b3c9bb630d26418f Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Thu, 20 Feb 2014 17:45:53 -0800 Subject: [PATCH 13/25] Take out whitespace --- lib/linked_in/client.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/linked_in/client.rb b/lib/linked_in/client.rb index 44b639fd..fcdb4bba 100644 --- a/lib/linked_in/client.rb +++ b/lib/linked_in/client.rb @@ -57,7 +57,6 @@ def connection @connection ||= Faraday.new(connection_options) do |builder| builder.use ::Faraday::Request::OAuth, authentication builder.use ::Faraday::Request::UrlEncoded - builder.use ::FaradayMiddleware::Mashify, :mash_class => LinkedIn::Mash builder.use ::Faraday::Response::ParseJson From 0064f3a3207194dbd0ce7d8e40f6a3f5962920ce Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Thu, 20 Feb 2014 17:46:36 -0800 Subject: [PATCH 14/25] Cleanup brackets on spec --- spec/cases/error_reporter_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/cases/error_reporter_spec.rb b/spec/cases/error_reporter_spec.rb index 6cebfe98..fb008429 100644 --- a/spec/cases/error_reporter_spec.rb +++ b/spec/cases/error_reporter_spec.rb @@ -7,8 +7,8 @@ client.authorize_from_access('atoken', 'asecret') end - let(:client){LinkedIn::Client.new('token', 'secret')} - let(:consumer){OAuth::Consumer.new('token', 'secret', {:site => 'https://api.linkedin.com'})} + let(:client) { LinkedIn::Client.new('token', 'secret') } + let(:consumer) { OAuth::Consumer.new('token', 'secret', :site => 'https://api.linkedin.com') } it 'raises an unauthorized error when 401' do stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 401) @@ -39,4 +39,4 @@ stub_request(:get, "https://api.linkedin.com/v1/people/~").to_return(:body => "{}", :status => 502) ->{ client.profile }.should raise_error(LinkedIn::Errors::UnavailableError) end -end \ No newline at end of file +end From 065e0a3430dec79ed06d9046de751007105b23a3 Mon Sep 17 00:00:00 2001 From: Jason Nochlin Date: Mon, 3 Feb 2014 19:43:01 -0500 Subject: [PATCH 15/25] Remove failfast option --- .rspec | 1 - 1 file changed, 1 deletion(-) diff --git a/.rspec b/.rspec index ba44b749..4e1e0d2f 100644 --- a/.rspec +++ b/.rspec @@ -1,2 +1 @@ --color ---fail-fast From 44362bf6ce7512fc649b77be5b9c2d0bcc6f04bf Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Thu, 20 Feb 2014 18:02:05 -0800 Subject: [PATCH 16/25] Raise multi_json to ~>1.8 --- linkedin.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linkedin.gemspec b/linkedin.gemspec index 91b32784..6662ed85 100644 --- a/linkedin.gemspec +++ b/linkedin.gemspec @@ -3,7 +3,7 @@ require File.expand_path('../lib/linked_in/version', __FILE__) Gem::Specification.new do |gem| gem.add_dependency 'hashie', '~> 3.0' - gem.add_dependency 'multi_json', '~> 1.0' + gem.add_dependency 'multi_json', '~> 1.8' gem.add_dependency 'oauth', '~> 0.4' gem.add_dependency 'faraday', '~> 0.8' gem.add_dependency 'faraday_middleware' From 4c0a2394fe45417421ee2f0931f8c6a95116745f Mon Sep 17 00:00:00 2001 From: Jason Nochlin Date: Tue, 11 Nov 2014 19:01:40 -0500 Subject: [PATCH 17/25] Fix SimpleOAuth header generation --- lib/linked_in/client.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/linked_in/client.rb b/lib/linked_in/client.rb index fcdb4bba..4021eab1 100644 --- a/lib/linked_in/client.rb +++ b/lib/linked_in/client.rb @@ -30,7 +30,7 @@ def authentication :consumer_key => consumer_token, :consumer_secret => consumer_secret, :token => @auth_token, - :token_secret => @auth_secret + :token_secret => @auth_secret, } end @@ -55,7 +55,7 @@ def connection raise "Please authenticate first" unless authenticated? @connection ||= Faraday.new(connection_options) do |builder| - builder.use ::Faraday::Request::OAuth, authentication + builder.use ::Faraday::Request::OAuth, authentication.merge(:ignore_extra_keys => true) builder.use ::Faraday::Request::UrlEncoded builder.use ::FaradayMiddleware::Mashify, :mash_class => LinkedIn::Mash builder.use ::Faraday::Response::ParseJson From 301f1bb11f67ed7b4f761db098898ae63ad5b2b0 Mon Sep 17 00:00:00 2001 From: Jason Nochlin Date: Tue, 11 Nov 2014 21:18:16 -0500 Subject: [PATCH 18/25] Match class/file naming convention --- lib/linked_in.rb | 36 ++++++++++++++++++++++++++++++++++++ lib/linkedin.rb | 37 +------------------------------------ 2 files changed, 37 insertions(+), 36 deletions(-) create mode 100644 lib/linked_in.rb diff --git a/lib/linked_in.rb b/lib/linked_in.rb new file mode 100644 index 00000000..cea67420 --- /dev/null +++ b/lib/linked_in.rb @@ -0,0 +1,36 @@ +require 'oauth' +require 'linked_in/configuration' + +module LinkedIn + extend Configuration + class << self + attr_accessor :token, :secret, :default_profile_fields + + # config/initializers/linkedin.rb (for instance) + # + # ```ruby + # LinkedIn.configure do |config| + # config.token = 'consumer_token' + # config.secret = 'consumer_secret' + # config.default_profile_fields = ['educations', 'positions'] + # end + # ``` + # elsewhere + # + # ```ruby + # client = LinkedIn::Client.new + # ``` + def configure + yield self + true + end + end + + autoload :Api, "linked_in/api" + autoload :Client, "linked_in/client" + autoload :Mash, "linked_in/mash" + autoload :Errors, "linked_in/errors" + autoload :Helpers, "linked_in/helpers" + autoload :Search, "linked_in/search" + autoload :Version, "linked_in/version" +end diff --git a/lib/linkedin.rb b/lib/linkedin.rb index ef4e5554..7416b677 100644 --- a/lib/linkedin.rb +++ b/lib/linkedin.rb @@ -1,36 +1 @@ -require 'oauth' -require 'linked_in/configuration' - -module LinkedIn - extend Configuration - class << self - attr_accessor :token, :secret, :default_profile_fields - - # config/initializers/linkedin.rb (for instance) - # - # ```ruby - # LinkedIn.configure do |config| - # config.token = 'consumer_token' - # config.secret = 'consumer_secret' - # config.default_profile_fields = ['educations', 'positions'] - # end - # ``` - # elsewhere - # - # ```ruby - # client = LinkedIn::Client.new - # ``` - def configure - yield self - true - end - end - - autoload :Api, "linked_in/api" - autoload :Client, "linked_in/client" - autoload :Mash, "linked_in/mash" - autoload :Errors, "linked_in/errors" - autoload :Helpers, "linked_in/helpers" - autoload :Search, "linked_in/search" - autoload :Version, "linked_in/version" -end \ No newline at end of file +require 'linked_in' From 95b113110926d6298455480541fc728bd7c38392 Mon Sep 17 00:00:00 2001 From: Jason Nochlin Date: Wed, 12 Nov 2014 06:05:35 -0500 Subject: [PATCH 19/25] Update http stubs for #224 --- spec/cases/api_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/cases/api_spec.rb b/spec/cases/api_spec.rb index b7cf169d..ee57cdd1 100644 --- a/spec/cases/api_spec.rb +++ b/spec/cases/api_spec.rb @@ -125,7 +125,7 @@ context "Company API", :vcr do it "should be able to view a company profile" do - stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586").to_return(:body => "{}") + stub_request(:get, "https://api.linkedin.com/v1/companies/1586").to_return(:body => "{}") client.company(:id => 1586).should be_an_instance_of(LinkedIn::Mash) end @@ -162,22 +162,22 @@ end it "should be able to view company_updates" do - stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/updates").to_return(:body => "{}") + stub_request(:get, "https://api.linkedin.com/v1/companies/1586/updates").to_return(:body => "{}") client.company_updates(:id => 1586).should be_an_instance_of(LinkedIn::Mash) end it "should be able to view company_statistic" do - stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/company-statistics").to_return(:body => "{}") + stub_request(:get, "https://api.linkedin.com/v1/companies/1586/company-statistics").to_return(:body => "{}") client.company_statistics(:id => 1586).should be_an_instance_of(LinkedIn::Mash) end it "should be able to view company updates comments" do - stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/updates/key=company_update_key/update-comments").to_return(:body => "{}") + stub_request(:get, "https://api.linkedin.com/v1/companies/1586/updates/key=company_update_key/update-comments").to_return(:body => "{}") client.company_updates_comments("company_update_key", :id => 1586).should be_an_instance_of(LinkedIn::Mash) end it "should be able to view company updates likes" do - stub_request(:get, "https://api.linkedin.com/v1/companies/id=1586/updates/key=company_update_key/likes").to_return(:body => "{}") + stub_request(:get, "https://api.linkedin.com/v1/companies/1586/updates/key=company_update_key/likes").to_return(:body => "{}") client.company_updates_likes("company_update_key", :id => 1586).should be_an_instance_of(LinkedIn::Mash) end @@ -190,7 +190,7 @@ end it "should be able to unfollow a company" do - stub_request(:delete, "https://api.linkedin.com/v1/people/~/following/companies/id=1586").to_return(:body => "", :status => 201) + stub_request(:delete, "https://api.linkedin.com/v1/people/~/following/companies/1586").to_return(:body => "", :status => 201) response = client.unfollow_company(1586) response.body.should == nil From 7294454c0698b5d23672d41cfceb8d794ebddaff Mon Sep 17 00:00:00 2001 From: Jason Nochlin Date: Wed, 12 Nov 2014 06:15:54 -0500 Subject: [PATCH 20/25] More updates to http stubs and fix Company API cassette --- spec/cases/api_spec.rb | 2 +- .../Company_API/should_load_correct_company_data.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/cases/api_spec.rb b/spec/cases/api_spec.rb index ee57cdd1..8e993b63 100644 --- a/spec/cases/api_spec.rb +++ b/spec/cases/api_spec.rb @@ -190,7 +190,7 @@ end it "should be able to unfollow a company" do - stub_request(:delete, "https://api.linkedin.com/v1/people/~/following/companies/1586").to_return(:body => "", :status => 201) + stub_request(:delete, "https://api.linkedin.com/v1/people/~/following/companies/id=1586").to_return(:body => "", :status => 201) response = client.unfollow_company(1586) response.body.should == nil diff --git a/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml b/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml index 5e231240..3f20a7ea 100644 --- a/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml +++ b/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml @@ -2,7 +2,7 @@ http_interactions: - request: method: get - uri: https://api.linkedin.com/v1/companies/id=1586 + uri: https://api.linkedin.com/v1/companies/1586 body: encoding: US-ASCII string: '' @@ -39,7 +39,7 @@ http_interactions: recorded_at: Wed, 10 Apr 2013 22:06:51 GMT - request: method: get - uri: https://api.linkedin.com/v1/companies/id=1586:(id,name,industry,locations:(address:(city,state,country-code),is-headquarters),employee-count-range) + uri: https://api.linkedin.com/v1/companies/1586:(id,name,industry,locations:(address:(city,state,country-code),is-headquarters),employee-count-range) body: encoding: US-ASCII string: '' From 60ab3597c142497d0f54df5d3b7e2b90aa2a58c2 Mon Sep 17 00:00:00 2001 From: Jason Nochlin Date: Wed, 12 Nov 2014 06:41:08 -0500 Subject: [PATCH 21/25] Build against rbx-2 to match Addressable gem --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3677baad..2b44e021 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,4 @@ rvm: - 2.1.0 - 1.9.3 - jruby-19mode - - rbx + - rbx-2 From 1db6a0ed55100fd7776b0d5dacc57717395af2c5 Mon Sep 17 00:00:00 2001 From: Jason Nochlin Date: Wed, 12 Nov 2014 06:44:35 -0500 Subject: [PATCH 22/25] Revert "Build against rbx-2 to match Addressable gem" - didn't fix build This reverts commit 60ab3597c142497d0f54df5d3b7e2b90aa2a58c2. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2b44e021..3677baad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,4 @@ rvm: - 2.1.0 - 1.9.3 - jruby-19mode - - rbx-2 + - rbx From 617ad8d1a0b584c168209063d3787afe793dfcb2 Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Fri, 14 Nov 2014 16:22:20 -0800 Subject: [PATCH 23/25] Let's try and use a specific version of rbx --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3677baad..0d2de855 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,4 @@ rvm: - 2.1.0 - 1.9.3 - jruby-19mode - - rbx + - rbx-2.2.7 From d839efaa1fc6d7dfcfec269cba1ba7f24a9ebdac Mon Sep 17 00:00:00 2001 From: Matt Kirk Date: Fri, 14 Nov 2014 16:30:12 -0800 Subject: [PATCH 24/25] Bump again --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0d2de855..6b34d85b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,4 @@ rvm: - 2.1.0 - 1.9.3 - jruby-19mode - - rbx-2.2.7 + - rbx-2.2.9 From e669cc687ea2ddbe613e855ed5c0598449560a3c Mon Sep 17 00:00:00 2001 From: Jason Nochlin Date: Sat, 22 Nov 2014 14:06:21 -0500 Subject: [PATCH 25/25] Drop rbx --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6b34d85b..7ee50eb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,3 @@ rvm: - 2.1.0 - 1.9.3 - jruby-19mode - - rbx-2.2.9