linkedin2 0.0.16 → 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +2 -0
  4. data/.rspec +2 -2
  5. data/.travis.yml +1 -1
  6. data/README.md +3 -3
  7. data/Rakefile +1 -1
  8. data/lib/linkedin/api.rb +16 -0
  9. data/lib/linkedin/api/authentication.rb +5 -7
  10. data/lib/linkedin/api/companies.rb +16 -10
  11. data/lib/linkedin/api/invitation.rb +39 -0
  12. data/lib/linkedin/api/messaging.rb +24 -0
  13. data/lib/linkedin/api/network_updates.rb +5 -9
  14. data/lib/linkedin/api/people.rb +18 -0
  15. data/lib/linkedin/client.rb +34 -72
  16. data/lib/linkedin/configuration.rb +26 -11
  17. data/lib/linkedin/credentials.rb +27 -0
  18. data/lib/linkedin/errors.rb +45 -0
  19. data/lib/linkedin/faraday_middleware.rb +6 -4
  20. data/lib/linkedin/faraday_middleware/credentials_request.rb +31 -0
  21. data/lib/linkedin/faraday_middleware/{linkedin_error_response.rb → error_response.rb} +2 -10
  22. data/lib/linkedin/faraday_middleware/format_request.rb +17 -0
  23. data/lib/linkedin/faraday_middleware/user_agent_request.rb +10 -0
  24. data/lib/linkedin/fields.rb +58 -0
  25. data/lib/linkedin/industries.rb +199 -0
  26. data/lib/linkedin/response.rb +19 -0
  27. data/lib/linkedin/version.rb +1 -1
  28. data/lib/linkedin2.rb +11 -19
  29. data/linkedin.gemspec +16 -7
  30. data/spec/api/companies_spec.rb +8 -9
  31. data/spec/api/groups_spec.rb +3 -4
  32. data/spec/api/jobs_spec.rb +2 -3
  33. data/spec/api/network_updates_spec.rb +9 -15
  34. data/spec/api/{profiles_spec.rb → people_spec.rb} +11 -13
  35. data/spec/faraday_middleware/{linkedin_error_response_spec.rb → error_response_spec.rb} +8 -21
  36. data/spec/fixtures/requests/companies.yml +25 -15
  37. data/spec/fixtures/requests/invalid.yml +7 -7
  38. data/spec/fixtures/requests/network_updates.yml +12 -12
  39. data/spec/fixtures/requests/people.yml +380 -0
  40. data/spec/spec_helper.rb +18 -19
  41. data/spec/support/coverage.rb +14 -0
  42. data/spec/support/vcr.rb +9 -0
  43. data/spec/test_app.yml +3 -2
  44. metadata +119 -38
  45. data/lib/linkedin/api/industries.rb +0 -171
  46. data/lib/linkedin/api/permissions.rb +0 -42
  47. data/lib/linkedin/api/profiles.rb +0 -71
  48. data/lib/linkedin/error.rb +0 -29
  49. data/lib/linkedin/faraday_middleware/linkedin_format_request.rb +0 -26
  50. data/lib/linkedin/industry.rb +0 -33
  51. data/spec/fixtures/requests/profiles.yml +0 -201
@@ -1,42 +0,0 @@
1
- module LinkedIn
2
- module API
3
- module Permissions
4
- COMPANY = { 'company' => [ 'id', 'name', 'type', 'size', 'industry', 'ticker' ] }
5
- LOCATION = { 'location' => ['name', { 'country' => 'code' } ] }
6
- POSITIONS = { 'positions' => [ 'id', 'title', 'summary', 'start-date', 'end-date', 'is-current', COMPANY ] }
7
- PROFILE_REQ = { 'api-standard-profile-request' => ['url', 'headers'] }
8
-
9
- PROFILE_BASE = [ 'id', 'first-name', 'last-name','maiden-name', 'formatted-name', 'phonetic-first-name',
10
- 'phonetic-last-name', 'formatted-phonetic-name', 'headline', 'industry', 'distance',
11
- 'current-share', 'num-connections', 'num-connections-capped', 'summary', 'specialties',
12
- 'picture-url', 'site-standard-profile-request', 'public-profile-url',
13
- LOCATION, POSITIONS, PROFILE_REQ ]
14
-
15
- RELATION = { 'relation-to-viewer' => [ 'num-related-connections', 'related-connections' => PROFILE_BASE ] }
16
-
17
- MEMBER_RESOURCES = { 'member-url-resources' => [ 'url', 'name' ] }
18
- FULL_BASE = [ 'last-modified-timestamp', 'proposal-comments', 'associations', 'interests', 'publications',
19
- 'patents', 'languages', 'skills', 'certifications', 'educations', 'courses', 'volunteer',
20
- 'three-current-positions', 'three-past-positions', 'num-recommenders', 'recommendations-received',
21
- 'mfeed-rss-url', 'following', 'job-bookmarks', 'suggestions', 'date-of-birth',
22
- 'related-profile-views', 'honors-awards' ]
23
-
24
- R_BASICPROFILE = PROFILE_BASE + [ RELATION ]
25
- R_EMAILADDRESS = [ 'email-address' ]
26
- R_FULLPROFILE = R_BASICPROFILE + FULL_BASE + [ MEMBER_RESOURCES ]
27
- R_CONTACTINFO = [ 'phone-numbers', 'bound-account-types', 'im-accounts', 'main-address', 'twitter-accounts', 'primary-twitter-account']
28
- R_NETWORK = [ 'connections' ]
29
- RW_GROUPS = [ 'group-memberships' ]
30
- RW_NUS = [ 'network' ]
31
- W_MESSAGES = []
32
-
33
- def self.render_permissions (*fields)
34
- fields = fields.first if fields.size == 1
35
-
36
- return render_permissions(fields.map { |key, value| "#{key}:(#{render_permissions value})" }) if fields.respond_to? :keys
37
- return fields.map { |value| render_permissions value }.join ',' if fields.respond_to? :each
38
- fields.to_s
39
- end
40
- end
41
- end
42
- end
@@ -1,71 +0,0 @@
1
- module LinkedIn
2
- module API
3
- module Profiles
4
- def profile_api(selector)
5
- profile selector, Permissions::PROFILE_REQ
6
- end
7
-
8
- def profile(selector = '~', fields = nil, token = nil)
9
- fields ||= profile_fields
10
- query = "#{selector.to_param}:(#{Permissions.render_permissions fields})"
11
- get "v1/people/#{query}" do |req|
12
- req.headers.merge! 'x-li-auth-token' => token unless token.blank?
13
- end
14
- end
15
-
16
- def connections(selector = '~', fields = nil)
17
- profile [selector, 'connections'].join('/'), fields
18
- end
19
-
20
- def shared_connections(selector, fields = Permissions::RELATION, offset = 0, limit = 10, token = nil)
21
- query = "#{selector.to_param}:(#{Permissions.render_permissions fields})"
22
- get "v1/people/#{query}" do |req|
23
- req.params.merge! start: offset, count: limit
24
- req.headers.merge! 'x-li-auth-token' => token unless token.blank?
25
- end
26
- end
27
-
28
- def search(options = {}, token = nil)
29
- get "v1/people-search?#{options.to_param}" do |req|
30
- req.headers.merge! 'x-li-auth-token' => token unless token.blank?
31
- end
32
- end
33
-
34
- def connect_with(selector, subject, message, type = :friend, auth_name = nil, auth_value = nil)
35
- if auth_name.blank? || auth_value.blank?
36
- profile = profile_api selector
37
- token = profile.apiStandardProfileRequest_.headers_.values_.first.value
38
- auth_name, auth_value = *token.split(':')
39
- end
40
-
41
- connection_request = { recipients: { values: [ { person: { _path: "/people/#{selector.to_param}" } } ] },
42
- subject: subject,
43
- body: message,
44
- 'item-content' => {
45
- 'invitation-request' => {
46
- 'connect-type' => type,
47
- authorization: { name: auth_name, value: auth_value } } } }
48
-
49
- post 'v1/people/~/mailbox' do |req|
50
- req.headers['Content-Type'] = 'application/json'
51
- req.headers['x-li-format'] = 'json'
52
- req.body = connection_request.to_json
53
- end
54
- end
55
-
56
- def message(subject, message, recipients)
57
- recipients = [recipients].flatten
58
-
59
- recipients = recipients.map { |recipient| { person: { _path: "/people/#{recipient.to_param}" } } }
60
-
61
- message = { recipients: { values: recipients }, subject: subject, body: message }
62
-
63
- post 'v1/people/~/mailbox' do |req|
64
- req.headers['Content-Type'] = 'application/json'
65
- req.headers['x-li-format'] = 'json'
66
- req.body = message.to_json
67
- end
68
- end
69
- end
70
- end
71
- end
@@ -1,29 +0,0 @@
1
- module LinkedIn
2
- class Error < StandardError
3
- extend Forwardable
4
-
5
- attr_accessor :request, :response
6
- delegate [:status, :body] => :response
7
-
8
- def initialize(error_data={})
9
- if hash = Hash.try_convert(error_data)
10
- self.request, self.response = hash[:request], hash[:response]
11
- end
12
-
13
- super (self.response && self.response.body['message']) || error_data
14
- end
15
- end
16
-
17
- class BadRequest < Error; end
18
- class Unauthorized < Error; end
19
- class Forbidden < Error; end
20
- class NotFound < Error; end
21
- class InternalServerError < Error; end
22
-
23
- class CSRF < Error
24
- def initialize(expected=nil, received=nil)
25
- additional = "Excepted '#{expected}' but received '#{received}'" if expected
26
- super "Response state did not match sent state. #{additional}"
27
- end
28
- end
29
- end
@@ -1,26 +0,0 @@
1
- module LinkedIn
2
- module FaradayMiddleware
3
- class LinkedinFormatRequest < Faraday::Middleware
4
- def initialize(app = nil, format = :json)
5
- super app
6
-
7
- @format = format
8
- end
9
-
10
- def call(env)
11
- set_request_format! env[:url] unless has_format?(env[:url])
12
-
13
- @app.call env
14
- end
15
-
16
- def has_format?(url)
17
- !(url.query =~ /(^|&)format=/).nil?
18
- end
19
-
20
- def set_request_format!(url)
21
- ar = URI.decode_www_form(url.query || '') << ['format', @format]
22
- url.query = URI.encode_www_form(ar)
23
- end
24
- end
25
- end
26
- end
@@ -1,33 +0,0 @@
1
- module LinkedIn
2
- module Industry
3
- def self.all
4
- LinkedIn::API::Industries::INDUSTRIES
5
- end
6
-
7
- def self.[](code)
8
- find_by_code(code)
9
- end
10
-
11
- def self.find_by_code(code)
12
- all.detect { |indust| indust[:code] == code }
13
- end
14
-
15
- def self.find_by_group(*groups)
16
- all.reject { |indust| (groups & indust[:group]) != groups }
17
- end
18
-
19
- def self.find_by_description(description)
20
- all.detect { |indust| normalize_description(indust[:description]) == normalize_description(description) }
21
- end
22
-
23
- def self.find_group_names(*groups)
24
- Array[groups].flatten.map { |group| LinkedIn::API::Industries::GROUPS[group.to_sym] }
25
- end
26
-
27
- private
28
-
29
- def self.normalize_description(description)
30
- description.to_s.downcase.strip.gsub(' ','_').gsub(/[^\w]/, '').to_sym
31
- end
32
- end
33
- end
@@ -1,201 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: get
5
- uri: https://api.linkedin.com/v1/people/~?oauth2_access_token=AQUJwEF40pJUbVxsW_mujQ3QCiXvlTnMFk55SlfVPYRcAPdsn1oE1Hm8Ldlc61o57k96i04ufG81KFdPJIOSJswXsGyZ0tk9IMZea8sfNXMGMnZgikQJUQPkmRVYVw9BP1qH9tp7hJF32DQtzkBB_NE8xPASPVgXVWbbntChGyYqqDvF1p8&format=json
6
- body:
7
- encoding: US-ASCII
8
- string: ''
9
- headers:
10
- User-Agent:
11
- - Faraday v0.8.8
12
- response:
13
- status:
14
- code: 200
15
- message:
16
- headers:
17
- server:
18
- - Apache-Coyote/1.1
19
- x-li-request-id:
20
- - 03M2HIZ5ZZ
21
- vary:
22
- - '*'
23
- x-li-format:
24
- - json
25
- content-type:
26
- - application/json;charset=UTF-8
27
- date:
28
- - Sun, 13 Oct 2013 22:48:35 GMT
29
- x-li-fabric:
30
- - PROD-ELA4
31
- access-control-allow-origin:
32
- - https://www.linkedin.com
33
- age:
34
- - '0'
35
- transfer-encoding:
36
- - chunked
37
- connection:
38
- - keep-alive
39
- x-li-pop:
40
- - PROD-ELA4
41
- x-li-uuid:
42
- - mBWfxe/MLBPwzEjFASsAAA==
43
- body:
44
- encoding: UTF-8
45
- string: |-
46
- {
47
- "firstName": "Josh",
48
- "headline": "Test Engineer at LinkedIn2 Gem",
49
- "lastName": "Testjordan",
50
- "siteStandardProfileRequest": {"url": "http://www.linkedin.com/profile/view?id=292221312&authType=name&authToken=lTbb&trk=api*a3296321*s3370311*"}
51
- }
52
- http_version:
53
- recorded_at: Sun, 13 Oct 2013 22:48:40 GMT
54
- - request:
55
- method: get
56
- uri: https://api.linkedin.com/v1/people/id=Fy5e5a4mqr?oauth2_access_token=AQUJwEF40pJUbVxsW_mujQ3QCiXvlTnMFk55SlfVPYRcAPdsn1oE1Hm8Ldlc61o57k96i04ufG81KFdPJIOSJswXsGyZ0tk9IMZea8sfNXMGMnZgikQJUQPkmRVYVw9BP1qH9tp7hJF32DQtzkBB_NE8xPASPVgXVWbbntChGyYqqDvF1p8&format=json
57
- body:
58
- encoding: US-ASCII
59
- string: ''
60
- headers:
61
- User-Agent:
62
- - Faraday v0.8.8
63
- response:
64
- status:
65
- code: 200
66
- message:
67
- headers:
68
- server:
69
- - Apache-Coyote/1.1
70
- x-li-request-id:
71
- - K70EU26VBI
72
- vary:
73
- - '*'
74
- x-li-format:
75
- - json
76
- content-type:
77
- - application/json;charset=UTF-8
78
- date:
79
- - Sun, 13 Oct 2013 22:48:36 GMT
80
- x-li-fabric:
81
- - PROD-ELA4
82
- access-control-allow-origin:
83
- - https://www.linkedin.com
84
- age:
85
- - '0'
86
- transfer-encoding:
87
- - chunked
88
- connection:
89
- - keep-alive
90
- x-li-pop:
91
- - PROD-ELA4
92
- x-li-uuid:
93
- - sLbq6O/MLBMQaCG8uSoAAA==
94
- body:
95
- encoding: UTF-8
96
- string: |-
97
- {
98
- "firstName": "Sir Richard",
99
- "headline": "Chairman,Virgin Group.",
100
- "lastName": "B.",
101
- "siteStandardProfileRequest": {"url": "http://www.linkedin.com/profile/view?id=293623781&authType=name&authToken=Y22Y&trk=api*a3296321*s3370311*"}
102
- }
103
- http_version:
104
- recorded_at: Sun, 13 Oct 2013 22:48:41 GMT
105
- - request:
106
- method: get
107
- uri: https://api.linkedin.com/v1/people/~/connections?oauth2_access_token=AQUJwEF40pJUbVxsW_mujQ3QCiXvlTnMFk55SlfVPYRcAPdsn1oE1Hm8Ldlc61o57k96i04ufG81KFdPJIOSJswXsGyZ0tk9IMZea8sfNXMGMnZgikQJUQPkmRVYVw9BP1qH9tp7hJF32DQtzkBB_NE8xPASPVgXVWbbntChGyYqqDvF1p8&format=json
108
- body:
109
- encoding: US-ASCII
110
- string: ''
111
- headers:
112
- User-Agent:
113
- - Faraday v0.8.8
114
- response:
115
- status:
116
- code: 200
117
- message:
118
- headers:
119
- server:
120
- - Apache-Coyote/1.1
121
- x-li-request-id:
122
- - DKYIS1K51I
123
- vary:
124
- - '*'
125
- x-li-format:
126
- - json
127
- content-type:
128
- - application/json;charset=UTF-8
129
- date:
130
- - Sun, 13 Oct 2013 22:50:18 GMT
131
- x-li-fabric:
132
- - PROD-ELA4
133
- access-control-allow-origin:
134
- - https://www.linkedin.com
135
- age:
136
- - '2'
137
- transfer-encoding:
138
- - chunked
139
- connection:
140
- - keep-alive
141
- x-li-pop:
142
- - PROD-ELA4
143
- x-li-uuid:
144
- - yIk8xgfNLBMQblmOAisAAA==
145
- body:
146
- encoding: UTF-8
147
- string: |-
148
- {
149
- "_total": 2,
150
- "values": [
151
- {
152
- "apiStandardProfileRequest": {
153
- "headers": {
154
- "_total": 1,
155
- "values": [{
156
- "name": "x-li-auth-token",
157
- "value": "name:24s3"
158
- }]
159
- },
160
- "url": "http://api.linkedin.com/v1/people/4eTIydMs1T"
161
- },
162
- "firstName": "Bob",
163
- "headline": "Guy at EverTrue",
164
- "id": "4eTIydMs1T",
165
- "industry": "Leisure, Travel & Tourism",
166
- "lastName": "Breznak",
167
- "location": {
168
- "country": {"code": "us"},
169
- "name": "Greater Boston Area"
170
- },
171
- "pictureUrl": "http://m.c.lnkd.licdn.com/mpr/mprx/0_zR-8K5tqrNEyhBCYz0APKFGVrqDrGlCYcx60KFPQftJhjzvOMjGuObFeOJSfTn_tq4rYx8SQ5fvK",
172
- "siteStandardProfileRequest": {"url": "http://www.linkedin.com/profile/view?id=28903483&authType=name&authToken=24s3&trk=api*a3296321*s3370311*"}
173
- },
174
- {
175
- "apiStandardProfileRequest": {
176
- "headers": {
177
- "_total": 1,
178
- "values": [{
179
- "name": "x-li-auth-token",
180
- "value": "name:Dack"
181
- }]
182
- },
183
- "url": "http://api.linkedin.com/v1/people/mbAZ4HR8RV"
184
- },
185
- "firstName": "Josh",
186
- "headline": "No-bullshit Software Engineer",
187
- "id": "mbAZ4HR8RV",
188
- "industry": "Computer Software",
189
- "lastName": "Jordan",
190
- "location": {
191
- "country": {"code": "us"},
192
- "name": "Greater Boston Area"
193
- },
194
- "pictureUrl": "http://m.c.lnkd.licdn.com/mpr/mprx/0_tK6jMqPfpQ370lofKczaMnrmy_kxjqUfrB-CMBig_LK7GKu7On9AccBPtmX8Y1siPPXinrgl7GAr",
195
- "siteStandardProfileRequest": {"url": "http://www.linkedin.com/profile/view?id=18939563&authType=name&authToken=Dack&trk=api*a3296321*s3370311*"}
196
- }
197
- ]
198
- }
199
- http_version:
200
- recorded_at: Sun, 13 Oct 2013 22:50:23 GMT
201
- recorded_with: VCR 2.5.0