linkedin 0.4.6 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
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