linkedin 0.4.6 → 0.4.7

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -1
  3. data/.yardopts +7 -0
  4. data/{changelog.markdown → CHANGELOG.md} +5 -1
  5. data/EXAMPLES.md +199 -0
  6. data/Gemfile +4 -0
  7. data/README.md +43 -0
  8. data/Rakefile +2 -7
  9. data/lib/linked_in/api.rb +34 -2
  10. data/lib/linked_in/api/communications.rb +44 -0
  11. data/lib/linked_in/api/companies.rb +128 -0
  12. data/lib/linked_in/api/groups.rb +115 -0
  13. data/lib/linked_in/api/jobs.rb +64 -0
  14. data/lib/linked_in/api/people.rb +72 -0
  15. data/lib/linked_in/api/query_helpers.rb +86 -0
  16. data/lib/linked_in/api/share_and_social_stream.rb +133 -0
  17. data/lib/linked_in/client.rb +7 -2
  18. data/lib/linked_in/errors.rb +12 -2
  19. data/lib/linked_in/mash.rb +31 -4
  20. data/lib/linked_in/search.rb +16 -1
  21. data/lib/linked_in/version.rb +1 -1
  22. data/lib/linkedin.rb +4 -1
  23. data/linkedin.gemspec +5 -3
  24. data/spec/cases/api_spec.rb +15 -5
  25. data/spec/cases/mash_spec.rb +30 -2
  26. data/spec/cases/oauth_spec.rb +5 -6
  27. data/spec/cases/search_spec.rb +53 -23
  28. data/spec/fixtures/cassette_library/LinkedIn_Api/Company_API.yml +3 -3
  29. data/spec/fixtures/cassette_library/LinkedIn_Api/Company_API/should_load_correct_company_data.yml +81 -0
  30. data/spec/fixtures/cassette_library/LinkedIn_Client/{_authorize_from_request.yml → _authorize_from_request/should_return_a_valid_access_token.yml} +0 -0
  31. data/spec/fixtures/cassette_library/LinkedIn_Client/_request_token/{with_a_callback_url.yml → with_a_callback_url/should_return_a_valid_access_token.yml} +0 -0
  32. data/spec/fixtures/cassette_library/LinkedIn_Client/_request_token/{with_default_options.yml → with_default_options/should_return_a_valid_request_token.yml} +0 -0
  33. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/{by_company_name_option.yml → by_company_name_option/should_perform_a_search.yml} +8 -9
  34. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_email_address/should_perform_a_people_search.yml +57 -0
  35. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/{by_first_name_and_last_name_options.yml → by_first_name_and_last_name_options/should_perform_a_search.yml} +15 -15
  36. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_first_name_and_last_name_options_with_fields/should_perform_a_search.yml +114 -0
  37. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/{by_keywords_string_parameter.yml → by_keywords_string_parameter/should_perform_a_search.yml} +8 -9
  38. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_multiple_email_address/should_perform_a_multi-email_search.yml +59 -0
  39. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/{by_single_keywords_option.yml → by_single_keywords_option/should_perform_a_search.yml} +8 -9
  40. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/{by_single_keywords_option_with_pagination.yml → by_single_keywords_option_with_pagination/should_perform_a_search.yml} +1 -3
  41. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/email_search_returns_unauthorized/should_raise_an_unauthorized_error.yml +59 -0
  42. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_keywords_options_with_fields/should_perform_a_search.yml +43 -0
  43. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/{by_keywords_string_parameter.yml → by_keywords_string_parameter/should_perform_a_company_search.yml} +19 -19
  44. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/{by_single_keywords_option.yml → by_single_keywords_option/should_perform_a_company_search.yml} +19 -19
  45. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/{by_single_keywords_option_with_facets_to_return.yml → by_single_keywords_option_with_facets_to_return/should_return_a_facet.yml} +14 -14
  46. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/{by_single_keywords_option_with_pagination.yml → by_single_keywords_option_with_pagination/should_perform_a_search.yml} +15 -15
  47. data/spec/helper.rb +9 -5
  48. metadata +76 -61
  49. data/.document +0 -5
  50. data/README.markdown +0 -84
  51. data/examples/authenticate.rb +0 -26
  52. data/examples/communication.rb +0 -7
  53. data/examples/network.rb +0 -12
  54. data/examples/profile.rb +0 -18
  55. data/examples/sinatra.rb +0 -77
  56. data/examples/status.rb +0 -6
  57. data/lib/linked_in/api/query_methods.rb +0 -176
  58. data/lib/linked_in/api/update_methods.rb +0 -85
  59. data/spec/fixtures/cassette_library/LinkedIn_Client/_request_token.yml +0 -37
  60. data/spec/fixtures/cassette_library/LinkedIn_Search/_search/by_first_name_and_last_name_options_with_fields.yml +0 -112
  61. data/spec/fixtures/cassette_library/LinkedIn_Search/_search_company/by_keywords_options_with_fields.yml +0 -232
data/.document DELETED
@@ -1,5 +0,0 @@
1
- README.rdoc
2
- lib/**/*.rb
3
- bin/*
4
- features/**/*.feature
5
- LICENSE
@@ -1,84 +0,0 @@
1
- # LinkedIn
2
-
3
- Ruby wrapper for the [LinkedIn API](http://developer.linkedin.com). The LinkedIn gem provides an easy-to-use wrapper for LinkedIn's Oauth/XML APIs.
4
-
5
- Travis CI : [![Build Status](https://secure.travis-ci.org/hexgnu/linkedin.png)](http://travis-ci.org/hexgnu/linkedin)
6
-
7
- ## Installation
8
-
9
- gem install linkedin
10
-
11
- ## Usage
12
-
13
- ### Authenticate
14
-
15
- LinkedIn's API uses Oauth for authentication. Luckily, the LinkedIn gem hides most of the gory details from you.
16
-
17
- ```ruby
18
- require 'linkedin'
19
-
20
- # get your api keys at https://www.linkedin.com/secure/developer
21
- client = LinkedIn::Client.new('your_consumer_key', 'your_consumer_secret')
22
-
23
- # If you want to use one of the scopes from linkedin you have to pass it in at this point
24
- # You can learn more about it here: http://developer.linkedin.com/documents/authentication
25
- request_token = client.request_token({}, :scope => "r_basicprofile+r_emailaddress")
26
-
27
- rtoken = request_token.token
28
- rsecret = request_token.secret
29
-
30
- # to test from your desktop, open the following url in your browser
31
- # and record the pin it gives you
32
- request_token.authorize_url
33
- => "https://api.linkedin.com/uas/oauth/authorize?oauth_token=<generated_token>"
34
-
35
- # then fetch your access keys
36
- client.authorize_from_request(rtoken, rsecret, pin)
37
- => ["OU812", "8675309"] # <= save these for future requests
38
-
39
- # or authorize from previously fetched access keys
40
- c.authorize_from_access("OU812", "8675309")
41
-
42
- # you're now free to move about the cabin, call any API method
43
- ```
44
-
45
- ### Profile examples
46
- ```ruby
47
- # get the profile for the authenticated user
48
- client.profile
49
-
50
- # get a profile for someone found in network via ID
51
- client.profile(:id => 'gNma67_AdI')
52
-
53
- # get a profile for someone via their public profile url
54
- client.profile(:url => 'http://www.linkedin.com/in/netherland')
55
- ```
56
-
57
- More examples in the [examples folder](http://github.com/pengwynn/linkedin/blob/master/examples).
58
-
59
- For a nice example on using this in a [Rails App](http://pivotallabs.com/users/will/blog/articles/1096-linkedin-gem-for-a-web-app).
60
-
61
- If you want to play with the LinkedIn api without using the gem, have a look at the [apigee LinkedIn console](http://app.apigee.com/console/linkedin).
62
-
63
- ## TODO
64
-
65
- * Change to json api
66
- * Update and correct test suite
67
- * Change to Faraday for authentication
68
- * Implement Messaging APIs
69
-
70
- ## Note on Patches/Pull Requests
71
-
72
- * Fork the project.
73
- * Make your feature addition or bug fix.
74
- * Add tests for it. This is important so I don't break it in a
75
- future version unintentionally.
76
- * Make sure your test doesn't just check of instance of LinkedIn::Mash :smile:.
77
- * Commit, do not mess with rakefile, version, or history.
78
- (if you want to have your own version, that is fine but
79
- bump version in a commit by itself I can ignore when I pull)
80
- * Send me a pull request. Bonus points for topic branches.
81
-
82
- ## Copyright
83
-
84
- Copyright (c) 2013-Present [Matt Kirk](http://matthewkirk.com) 2009-11 [Wynn Netherland](http://wynnnetherland.com). See LICENSE for details.
@@ -1,26 +0,0 @@
1
- require 'rubygems'
2
- require 'linkedin'
3
-
4
- # get your api keys at https://www.linkedin.com/secure/developer
5
- client = LinkedIn::Client.new('your_consumer_key', 'your_consumer_secret')
6
-
7
- # If you want to use one of the scopes from linkedin you have to pass it in at this point
8
- # You can learn more about it here: http://developer.linkedin.com/documents/authentication
9
- request_token = client.request_token({}, :scope => "r_basicprofile+r_emailaddress")
10
-
11
- rtoken = request_token.token
12
- rsecret = request_token.secret
13
-
14
- # to test from your desktop, open the following url in your browser
15
- # and record the pin it gives you
16
- request_token.authorize_url
17
- => "https://api.linkedin.com/uas/oauth/authorize?oauth_token=<generated_token>"
18
-
19
- # then fetch your access keys
20
- client.authorize_from_request(rtoken, rsecret, pin)
21
- => ["OU812", "8675309"] # <= save these for future requests
22
-
23
- # or authorize from previously fetched access keys
24
- c.authorize_from_access("OU812", "8675309")
25
-
26
- # you're now free to move about the cabin, call any API method
@@ -1,7 +0,0 @@
1
- # AUTHENTICATE FIRST found in examples/authenticate.rb
2
-
3
- # client is a LinkedIn::Client
4
-
5
- # send a message to a person in your network. you will need to authenticate the
6
- # user and ask for the "w_messages" permission.
7
- response = client.send_message("subject", "body", ["person_1_id", "person_2_id"])
@@ -1,12 +0,0 @@
1
- # AUTHENTICATE FIRST found in examples/authenticate.rb
2
-
3
- # client is a LinkedIn::Client
4
-
5
- # get network updates for the authenticated user
6
- client.network_updates
7
-
8
- # get profile picture changes
9
- client.network_updates(:type => 'PICT')
10
-
11
- # view connections for the currently authenticated user
12
- client.connections
@@ -1,18 +0,0 @@
1
- # AUTHENTICATE FIRST found in examples/authenticate.rb
2
-
3
- # client is a LinkedIn::Client
4
-
5
- # get the profile for the authenticated user
6
- client.profile
7
-
8
- # get a profile for someone found in network via ID
9
- client.profile(:id => 'gNma67_AdI')
10
-
11
- # get a profile for someone via their public profile url
12
- client.profile(:url => 'http://www.linkedin.com/in/netherland')
13
-
14
- # provides the ability to access authenticated user's company field in the profile
15
- user = client.profile(:fields => %w(positions))
16
- companies = user.positions.all.map{|t| t.company}
17
- # Example: most recent company can be accessed via companies[0]
18
-
@@ -1,77 +0,0 @@
1
- require "rubygems"
2
- require "haml"
3
- require "sinatra"
4
- require "linkedin"
5
-
6
- enable :sessions
7
-
8
- helpers do
9
- def login?
10
- !session[:atoken].nil?
11
- end
12
-
13
- def profile
14
- linkedin_client.profile unless session[:atoken].nil?
15
- end
16
-
17
- def connections
18
- linkedin_client.connections unless session[:atoken].nil?
19
- end
20
-
21
- private
22
- def linkedin_client
23
- client = LinkedIn::Client.new(settings.api, settings.secret)
24
- client.authorize_from_access(session[:atoken], session[:asecret])
25
- client
26
- end
27
-
28
- end
29
-
30
- configure do
31
- # get your api keys at https://www.linkedin.com/secure/developer
32
- set :api, "your_api_key"
33
- set :secret, "your_secret"
34
- end
35
-
36
- get "/" do
37
- haml :index
38
- end
39
-
40
- get "/auth" do
41
- client = LinkedIn::Client.new(settings.api, settings.secret)
42
- request_token = client.request_token(:oauth_callback => "http://#{request.host}:#{request.port}/auth/callback")
43
- session[:rtoken] = request_token.token
44
- session[:rsecret] = request_token.secret
45
-
46
- redirect client.request_token.authorize_url
47
- end
48
-
49
- get "/auth/logout" do
50
- session[:atoken] = nil
51
- redirect "/"
52
- end
53
-
54
- get "/auth/callback" do
55
- client = LinkedIn::Client.new(settings.api, settings.secret)
56
- if session[:atoken].nil?
57
- pin = params[:oauth_verifier]
58
- atoken, asecret = client.authorize_from_request(session[:rtoken], session[:rsecret], pin)
59
- session[:atoken] = atoken
60
- session[:asecret] = asecret
61
- end
62
- redirect "/"
63
- end
64
-
65
-
66
- __END__
67
- @@index
68
- -if login?
69
- %p Welcome #{profile.first_name}!
70
- %a{:href => "/auth/logout"} Logout
71
- %p= profile.headline
72
- %br
73
- %div= "You have #{connections.total} connections!"
74
- -connections.all.each do |c|
75
- %div= "#{c.first_name} #{c.last_name} - #{c.headline}"
76
- -else
77
- %a{:href => "/auth"} Login using LinkedIn
@@ -1,6 +0,0 @@
1
- # AUTHENTICATE FIRST found in examples/authenticate.rb
2
-
3
- # client is a LinkedIn::Client
4
-
5
- # update status for the authenticated user
6
- client.add_share(:comment => 'is playing with the LinkedIn Ruby gem')
@@ -1,176 +0,0 @@
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
- def company_updates(options={})
27
- path = "#{company_path(options)}/updates"
28
- simple_query(path, options)
29
- end
30
-
31
- def company_statistics(options={})
32
- path = "#{company_path(options)}/company-statistics"
33
- simple_query(path, options)
34
- end
35
-
36
- def company_updates_comments(update_key, options={})
37
- path = "#{company_path(options)}/updates/key=#{update_key}/update-comments"
38
- simple_query(path, options)
39
- end
40
-
41
- def company_updates_likes(update_key, options={})
42
- path = "#{company_path(options)}/updates/key=#{update_key}/likes"
43
- simple_query(path, options)
44
- end
45
-
46
- def job(options = {})
47
- path = jobs_path(options)
48
- simple_query(path, options)
49
- end
50
-
51
- def job_bookmarks(options = {})
52
- path = "#{person_path(options)}/job-bookmarks"
53
- simple_query(path, options)
54
- end
55
-
56
- def job_suggestions(options = {})
57
- path = "#{person_path(options)}/suggestions/job-suggestions"
58
- simple_query(path, options)
59
- end
60
-
61
- def group_memberships(options = {})
62
- path = "#{person_path(options)}/group-memberships"
63
- simple_query(path, options)
64
- end
65
-
66
- def group_profile(options)
67
- path = group_path(options)
68
- simple_query(path, options)
69
- end
70
-
71
- def group_posts(options)
72
- path = "#{group_path(options)}/posts"
73
- simple_query(path, options)
74
- end
75
-
76
- def shares(options={})
77
- path = "#{person_path(options)}/network/updates"
78
- simple_query(path, {:type => "SHAR", :scope => "self"}.merge(options))
79
- end
80
-
81
- def share_comments(update_key, options={})
82
- path = "#{person_path(options)}/network/updates/key=#{update_key}/update-comments"
83
- simple_query(path, options)
84
- end
85
-
86
- def share_likes(update_key, options={})
87
- path = "#{person_path(options)}/network/updates/key=#{update_key}/likes"
88
- simple_query(path, options)
89
- end
90
-
91
- def picture_urls(options={})
92
- picture_size = options.delete(:picture_size) || 'original'
93
- path = "#{picture_urls_path(options)}::(#{picture_size})"
94
- simple_query(path, options)
95
- end
96
-
97
- private
98
-
99
- def group_path(options)
100
- path = "/groups"
101
- if id = options.delete(:id)
102
- path += "/#{id}"
103
- end
104
- end
105
-
106
- def simple_query(path, options={})
107
- fields = options.delete(:fields) || LinkedIn.default_profile_fields
108
-
109
- if options.delete(:public)
110
- path +=":public"
111
- elsif fields
112
- path +=":(#{build_fields_params(fields)})"
113
- end
114
-
115
- headers = options.delete(:headers) || {}
116
- params = to_query(options)
117
- path += "#{path.include?("?") ? "&" : "?"}#{params}" if !params.empty?
118
-
119
- Mash.from_json(get(path, headers))
120
- end
121
-
122
- def build_fields_params(fields)
123
- if fields.is_a?(Hash) && !fields.empty?
124
- fields.map {|index,value| "#{index}:(#{build_fields_params(value)})" }.join(',')
125
- elsif fields.respond_to?(:each)
126
- fields.map {|field| build_fields_params(field) }.join(',')
127
- else
128
- fields.to_s.gsub("_", "-")
129
- end
130
- end
131
-
132
- def person_path(options)
133
- path = "/people/"
134
- if id = options.delete(:id)
135
- path += "id=#{id}"
136
- elsif url = options.delete(:url)
137
- path += "url=#{CGI.escape(url)}"
138
- else
139
- path += "~"
140
- end
141
- end
142
-
143
- def company_path(options)
144
- path = "/companies"
145
-
146
- if domain = options.delete(:domain)
147
- path += "?email-domain=#{CGI.escape(domain)}"
148
- elsif id = options.delete(:id)
149
- path += "/id=#{id}"
150
- elsif url = options.delete(:url)
151
- path += "/url=#{CGI.escape(url)}"
152
- elsif name = options.delete(:name)
153
- path += "/universal-name=#{CGI.escape(name)}"
154
- elsif is_admin = options.delete(:is_admin)
155
- path += "?is-company-admin=#{CGI.escape(is_admin)}"
156
- else
157
- path += "/~"
158
- end
159
- end
160
-
161
- def picture_urls_path(options)
162
- path = person_path(options)
163
- path += "/picture-urls"
164
- end
165
-
166
- def jobs_path(options)
167
- path = "/jobs"
168
- if id = options.delete(:id)
169
- path += "/id=#{id}"
170
- else
171
- path += "/~"
172
- end
173
- end
174
- end
175
- end
176
- end
@@ -1,85 +0,0 @@
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 add_company_share(company_id, share)
13
- path = "/companies/#{company_id}/shares"
14
- defaults = {:visibility => {:code => "anyone"}}
15
- post(path, defaults.merge(share).to_json, "Content-Type" => "application/json")
16
- end
17
-
18
- def post_group_discussion(group_id, discussion)
19
- warn 'Use add_group_share over post_group_discussion. This will be taken out in future versions'
20
- add_group_share(group_id, discussion)
21
- end
22
-
23
- def add_group_share(group_id, share)
24
- path = "/groups/#{group_id}/posts"
25
- post(path, share.to_json, "Content-Type" => "application/json")
26
- end
27
-
28
- def follow_company(company_id)
29
- path = "/people/~/following/companies"
30
- body = {:id => company_id }
31
- post(path, body.to_json, "Content-Type" => "application/json")
32
- end
33
-
34
- def unfollow_company(company_id)
35
- path = "/people/~/following/companies/id=#{company_id}"
36
- delete(path)
37
- end
38
-
39
- def join_group(group_id)
40
- path = "/people/~/group-memberships/#{group_id}"
41
- body = {'membership-state' => {'code' => 'member' }}
42
- put(path, body.to_json, "Content-Type" => "application/json")
43
- end
44
-
45
- def add_job_bookmark(bookmark)
46
- path = "/people/~/job-bookmarks"
47
- body = {'job' => {'id' => bookmark}}
48
- post(path, body.to_json, "Content-Type" => "application/json")
49
- end
50
-
51
- def update_comment(network_key, comment)
52
- path = "/people/~/network/updates/key=#{network_key}/update-comments"
53
- body = {'comment' => comment}
54
- post(path, body.to_json, "Content-Type" => "application/json")
55
- end
56
-
57
- def like_share(network_key)
58
- path = "/people/~/network/updates/key=#{network_key}/is-liked"
59
- put(path, 'true', "Content-Type" => "application/json")
60
- end
61
-
62
- def unlike_share(network_key)
63
- path = "/people/~/network/updates/key=#{network_key}/is-liked"
64
- put(path, 'false', "Content-Type" => "application/json")
65
- end
66
-
67
- def send_message(subject, body, recipient_paths)
68
- path = "/people/~/mailbox"
69
-
70
- message = {
71
- 'subject' => subject,
72
- 'body' => body,
73
- 'recipients' => {
74
- 'values' => recipient_paths.map do |profile_path|
75
- { 'person' => { '_path' => "/people/#{profile_path}" } }
76
- end
77
- }
78
- }
79
- post(path, message.to_json, "Content-Type" => "application/json")
80
- end
81
-
82
- end
83
-
84
- end
85
- end