linkedin-drspin 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/.autotest +14 -0
  2. data/.document +5 -0
  3. data/.gemtest +0 -0
  4. data/.gitignore +41 -0
  5. data/.rspec +1 -0
  6. data/.travis.yml +5 -0
  7. data/Gemfile +7 -0
  8. data/LICENSE +20 -0
  9. data/README.markdown +78 -0
  10. data/Rakefile +19 -0
  11. data/changelog.markdown +71 -0
  12. data/examples/authenticate.rb +21 -0
  13. data/examples/network.rb +12 -0
  14. data/examples/profile.rb +18 -0
  15. data/examples/sinatra.rb +77 -0
  16. data/examples/status.rb +6 -0
  17. data/lib/linked_in/api.rb +11 -0
  18. data/lib/linked_in/api/comment_methods.rb +33 -0
  19. data/lib/linked_in/api/company_search_methods.rb +65 -0
  20. data/lib/linked_in/api/group_methods.rb +18 -0
  21. data/lib/linked_in/api/people_search_methods.rb +112 -0
  22. data/lib/linked_in/api/post_methods.rb +33 -0
  23. data/lib/linked_in/api/query_methods.rb +81 -0
  24. data/lib/linked_in/api/update_methods.rb +55 -0
  25. data/lib/linked_in/client.rb +51 -0
  26. data/lib/linked_in/errors.rb +19 -0
  27. data/lib/linked_in/helpers.rb +6 -0
  28. data/lib/linked_in/helpers/authorization.rb +68 -0
  29. data/lib/linked_in/helpers/request.rb +80 -0
  30. data/lib/linked_in/mash.rb +68 -0
  31. data/lib/linked_in/search.rb +56 -0
  32. data/lib/linked_in/version.rb +11 -0
  33. data/lib/linkedin.rb +32 -0
  34. data/linkedin.gemspec +25 -0
  35. data/spec/cases/api_spec.rb +92 -0
  36. data/spec/cases/linkedin_spec.rb +37 -0
  37. data/spec/cases/mash_spec.rb +85 -0
  38. data/spec/cases/oauth_spec.rb +166 -0
  39. data/spec/cases/search_spec.rb +206 -0
  40. data/spec/fixtures/cassette_library/LinkedIn_Api/Company_API.yml +73 -0
  41. data/spec/fixtures/cassette_library/LinkedIn_Client/_authorize_from_request.yml +28 -0
  42. data/spec/fixtures/cassette_library/LinkedIn_Client/_request_token.yml +28 -0
  43. data/spec/fixtures/cassette_library/LinkedIn_Client/_request_token/with_a_callback_url.yml +28 -0
  44. data/spec/fixtures/cassette_library/LinkedIn_Client/_request_token/with_default_options.yml +28 -0
  45. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_company_name_option.yml +135 -0
  46. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_first_name_and_last_name_options.yml +122 -0
  47. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_first_name_and_last_name_options_with_fields.yml +72 -0
  48. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_keywords_string_parameter.yml +136 -0
  49. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_single_keywords_option.yml +136 -0
  50. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_single_keywords_option_with_pagination.yml +128 -0
  51. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_keywords_options_with_fields.yml +252 -0
  52. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_keywords_string_parameter.yml +73 -0
  53. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_single_keywords_option.yml +71 -0
  54. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_single_keywords_option_with_a_facet.yml +111 -0
  55. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_single_keywords_option_with_facets_to_return.yml +71 -0
  56. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_single_keywords_option_with_pagination.yml +66 -0
  57. data/spec/helper.rb +30 -0
  58. metadata +237 -0
@@ -0,0 +1,65 @@
1
+ module LinkedIn
2
+ module Api
3
+ module CompanySearchMethods
4
+
5
+ # Public: Search the LinkedIn service for companies
6
+ #
7
+ # options - The Hash options used to refine the selection:
8
+ # :sort - Controls the search result order.
9
+ # :start - The people record to start the return from.
10
+ # Used for page wrapping when the total number
11
+ # of records matching the search exceeds count
12
+ # (default: 0).
13
+ # :count - The number of companiy records to return
14
+ # (default: 25).
15
+ # :companies - The company fields to be returned
16
+ # (default: id,name,website-url)
17
+ # :keywords - The keywords to search for (optional).
18
+ #
19
+ # Examples
20
+ #
21
+ # > y linkedin.company_search(:keywords => "social,local",
22
+ # :count => 2)
23
+ # ---
24
+ # companies:
25
+ # _count: 2
26
+ # _start: 0
27
+ # total: 8620
28
+ # all:
29
+ # - id: 1355
30
+ # name: DHL
31
+ # website_url: http://www.dhl.com
32
+ # - id: 15656
33
+ # name: AECOM
34
+ # website_url: www.aecom.com
35
+ # => nil
36
+ #
37
+ # Returns a Hashie::Mash of the matched companies.
38
+ def company_search(options={})
39
+ options.reverse_merge!({
40
+ :sort => 'relevance',
41
+ :start => 0,
42
+ :count => 25,
43
+ :companies => 'id,name,website-url'
44
+ })
45
+
46
+ path = "/company-search:(companies:(#{options[:companies]}))" +
47
+ "?sort=#{options[:sort]}" +
48
+ "&start=#{options[:start]}" +
49
+ "&count=#{options[:count]}"
50
+
51
+ path += "&keywords=#{CGI.escape(options[:keywords])}" if
52
+ options[:keywords]
53
+
54
+ Mash.from_json(get(path))
55
+ end
56
+
57
+
58
+ def location(options={})
59
+ path = "/people-search:(facets:(code,buckets:(code,name)))?company-name=microsoft&facets=location"
60
+ simple_query(path)
61
+ end
62
+
63
+ end # CompanySearchMethods
64
+ end # Api
65
+ end # LinkedIn
@@ -0,0 +1,18 @@
1
+ module LinkedIn
2
+ module Api
3
+ module GroupMethods
4
+
5
+ def groups(options={})
6
+ path = "#{person_path(options)}/group-memberships?membership-state=member"
7
+ group_mash = simple_query(path, options)
8
+ group_mash.all
9
+ end
10
+
11
+ def suggested_groups(options={})
12
+ path = "#{person_path(options)}/suggestions/groups"
13
+ simple_query(path, options)
14
+ end
15
+
16
+ end # GroupMethods
17
+ end # Api
18
+ end # LinkedIn
@@ -0,0 +1,112 @@
1
+ module LinkedIn
2
+ module Api
3
+ module PeopleSearchMethods
4
+
5
+ # Public: Search the LinkedIn service for people
6
+ #
7
+ # options - The Hash options used to refine the selection:
8
+ # :people - The people fields to be returned
9
+ # (default: public-profile-url,id,first-name,
10
+ # last-name,headline,location).
11
+ # :count - The number of people records to return
12
+ # (default: 25).
13
+ # :start - The people record to start the return from.
14
+ # Used for page wrapping when the total number
15
+ # of records matching the search exceeds count
16
+ # (default: 0).
17
+ # :companies - A comma separated list of company codes to
18
+ # to match against the current-company field
19
+ # of people (optional).
20
+ # :locations - A comma separated list of location codes to
21
+ # match agains the location field of people
22
+ # (optional).
23
+ # :get_all - Boolean variable telling us to get all of
24
+ # the people that match our search. LinkedIn
25
+ # will only return the first 25 by default
26
+ # (optional).
27
+ #
28
+ # Examples
29
+ #
30
+ # > y client.people_search(:locations => 'us:91',
31
+ # :company => 1035,
32
+ # :count => 1)
33
+ # ---
34
+ # people:
35
+ # _count: 1
36
+ # _start: 0
37
+ # total: 110
38
+ # all:
39
+ # - first_name: Ben
40
+ # headline: Designer at SkB Architects
41
+ # id: EHp0p-X67f
42
+ # last_name: Humphrey
43
+ # location:
44
+ # country:
45
+ # code: us
46
+ # name: Greater Seattle Area
47
+ # public_profile_url: http://www.linkedin.com/in/benhumphrey
48
+ # => nil
49
+ #
50
+ # Returns a Hashie::Mash of the matched people.
51
+ def people_search(options={})
52
+
53
+ # revere merge defaults into options has so that we don't
54
+ # overwrite what the user has given us.
55
+ options.reverse_merge!({
56
+ :people => "public-profile-url,id,first-name,last-name" +
57
+ ",headline,location",
58
+ :count => 25,
59
+ :start => 0
60
+ })
61
+
62
+ # initialize path string for a people-search
63
+ path = "/people-search:(people:(#{options[:people]}))" +
64
+ "?count=#{options[:count]}" +
65
+ "&start=#{options[:start]}"
66
+
67
+ # add a facet so that we find everyone in the given companys
68
+ # if the :company option is defined.
69
+ path += "&facet=current-company,#{options[:companies]}" if
70
+ options[:companies]
71
+
72
+ # add a facet so that we find everyone in the given locations
73
+ # if the :location option is defined.
74
+ path += "&facet=location,#{CGI.escape(options[:locations])}" if
75
+ options[:locations]
76
+
77
+ # hit the linkedin service with the search. we store the payload
78
+ # as an array so that we can manipulate it below.
79
+ payload = MultiJson.decode(get(path))
80
+ Rails.logger.debug path
81
+
82
+ # if the :get_all option is set, we check to make sure that
83
+ # the count of items returned from the linkedin service is
84
+ # not less than the total number of items that match our
85
+ # search in the linkedin service.
86
+ while ((payload['people']['_start'] +
87
+ payload['people']['_count']) <
88
+ payload['people']['_total'])
89
+
90
+ # update the path string so that we start from where we
91
+ # left off from the last search.
92
+ path.sub!(/start=\d+/,
93
+ "start=#{payload['people']['_start'] +
94
+ payload['people']['_count']}")
95
+ Rails.logger.debug path
96
+
97
+ # update the count in our payload
98
+ payload['people']['_count'] += options[:count]
99
+
100
+ # hit the linkedin service again and merge teh new
101
+ # results into our payload.
102
+ payload['people']['values'] +=
103
+ MultiJson.decode(get(path))['people']['values']
104
+
105
+ end if options[:get_all]
106
+
107
+ Mash.from_json(MultiJson.encode(payload))
108
+
109
+ end # people_search()
110
+ end # PeopleSearchMethods
111
+ end # Api
112
+ end # LinkedIn
@@ -0,0 +1,33 @@
1
+ module LinkedIn
2
+ module Api
3
+ module PostMethods
4
+ #
5
+ # group_posts(options={})
6
+ #
7
+ # inputs:
8
+ # REQUIRED
9
+ # :group_id - the numeric id of the group to pull posts from.
10
+ # OPTIONAL
11
+ # :count - number of posts to retun (max 50)
12
+ # :start - post number to start pulling from
13
+ #
14
+ # outputs:
15
+ # Mash of json results from LinkedIn service
16
+ #
17
+ # description: Retreive posts from a given group and filter
18
+ # based on optional inputs.
19
+ #
20
+ def group_posts(options={})
21
+ options.reverse_merge!({:order => "recency"})
22
+ if options[:group_id]
23
+ group_id = options.delete(:group_id)
24
+ else
25
+ raise ":group_id option required for group_posts method"
26
+ end
27
+ path = "/groups/#{group_id}/posts:(title,summary,creator,id)"
28
+ simple_query(path, options)
29
+ end
30
+
31
+ end # PostMethods
32
+ end # Api
33
+ end # LinkedIn
@@ -0,0 +1,81 @@
1
+ module LinkedIn
2
+ module Api
3
+
4
+ module QueryMethods
5
+
6
+ def profile(options={})
7
+ path = person_path(options)
8
+ simple_query(path, options)
9
+ end
10
+
11
+ def connections(options={})
12
+ path = "#{person_path(options)}/connections"
13
+ simple_query(path, options)
14
+ end
15
+
16
+ def network_updates(options={})
17
+ path = "#{person_path(options)}/network/updates"
18
+ simple_query(path, options)
19
+ end
20
+
21
+ def company(options = {})
22
+ path = company_path(options)
23
+ simple_query(path, options)
24
+ end
25
+
26
+
27
+ private
28
+
29
+ def simple_query(path, options={})
30
+ fields = options.delete(:fields) || LinkedIn.default_profile_fields
31
+
32
+ if options.delete(:public)
33
+ path +=":public"
34
+ elsif fields
35
+ path +=":(#{fields.map{ |f| f.to_s.gsub("_","-") }.join(',')})"
36
+ end
37
+
38
+ headers = options.delete(:headers) || {}
39
+ params = options.map { |k,v| "#{k}=#{v}" }.join("&")
40
+ path += "?#{params}" if not params.empty?
41
+
42
+ Mash.from_json(get(path, headers))
43
+ end
44
+
45
+ def person_path(options)
46
+ path = "/people/"
47
+ if id = options.delete(:id)
48
+ path += "id=#{id}"
49
+ elsif url = options.delete(:url)
50
+ path += "url=#{CGI.escape(url)}"
51
+ else
52
+ path += "~"
53
+ end
54
+ end
55
+
56
+ def company_path(options)
57
+ # We leave out the trailing slash because it is used by keys but not
58
+ # by filters
59
+ path = "/companies"
60
+
61
+ # Add a trailing slash for keys (i.e. input values that return one
62
+ # company)
63
+ if id = options.delete(:id)
64
+ path += "/id=#{id}"
65
+ elsif url = options.delete(:url)
66
+ path += "/url=#{CGI.escape(url)}"
67
+ elsif name = options.delete(:name)
68
+ path += "/universal-name=#{CGI.escape(name)}"
69
+ # Add a question mark for filters (i.e. input values that return
70
+ # an array of companies.
71
+ elsif domain = options.delete(:domain)
72
+ path += "?email-domain=#{CGI.escape(domain)}"
73
+ else
74
+ path += "~"
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,55 @@
1
+ module LinkedIn
2
+ module Api
3
+
4
+ module UpdateMethods
5
+
6
+ def add_share(share)
7
+ path = "/people/~/shares"
8
+ defaults = {:visibility => {:code => "anyone"}}
9
+ post(path, defaults.merge(share).to_json, "Content-Type" => "application/json")
10
+ end
11
+
12
+ # def share(options={})
13
+ # path = "/people/~/shares"
14
+ # defaults = { :visability => 'anyone' }
15
+ # post(path, share_to_xml(defaults.merge(options)))
16
+ # end
17
+ #
18
+ # def update_comment(network_key, comment)
19
+ # path = "/people/~/network/updates/key=#{network_key}/update-comments"
20
+ # post(path, comment_to_xml(comment))
21
+ # end
22
+ #
23
+ # def update_network(message)
24
+ # path = "/people/~/person-activities"
25
+ # post(path, network_update_to_xml(message))
26
+ # end
27
+ #
28
+ # def send_message(subject, body, recipient_paths)
29
+ # path = "/people/~/mailbox"
30
+ #
31
+ # message = LinkedIn::Message.new
32
+ # message.subject = subject
33
+ # message.body = body
34
+ # recipients = LinkedIn::Recipients.new
35
+ #
36
+ # recipients.recipients = recipient_paths.map do |profile_path|
37
+ # recipient = LinkedIn::Recipient.new
38
+ # recipient.person = LinkedIn::Person.new
39
+ # recipient.person.path = "/people/#{profile_path}"
40
+ # recipient
41
+ # end
42
+ # message.recipients = recipients
43
+ # post(path, message_to_xml(message)).code
44
+ # end
45
+ #
46
+ # def clear_status
47
+ # path = "/people/~/current-status"
48
+ # delete(path).code
49
+ # end
50
+ #
51
+
52
+ end
53
+
54
+ end
55
+ 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::QueryMethods
9
+ include Api::UpdateMethods
10
+ include Api::GroupMethods
11
+ include Api::PostMethods
12
+ include Api::CompanySearchMethods
13
+ include Api::PeopleSearchMethods
14
+ include Api::CommentMethods
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,19 @@
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
+ class UnauthorizedError < LinkedInError; end
12
+ class GeneralError < LinkedInError; end
13
+ class AccessDeniedError < LinkedInError; end
14
+
15
+ class UnavailableError < StandardError; end
16
+ class InformLinkedInError < StandardError; end
17
+ class NotFoundError < StandardError; end
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ module LinkedIn
2
+ module Helpers
3
+ autoload :Authorization, "linked_in/helpers/authorization"
4
+ autoload :Request, "linked_in/helpers/request"
5
+ end
6
+ end